usb_poll ( bus );
/* Refill endpoint */
- usb_refill ( &usbep->ep );
+ if ( usbep->ep.open )
+ usb_refill ( &usbep->ep );
}
/**
return -ENOENT;
}
+/**
+ * Check if endpoint is open
+ *
+ * @v usbintf EFI USB interface
+ * @v endpoint Endpoint address
+ * @ret is_open Endpoint is open
+ */
+static int efi_usb_is_open ( struct efi_usb_interface *usbintf,
+ unsigned int endpoint ) {
+ unsigned int index = USB_ENDPOINT_IDX ( endpoint );
+ struct efi_usb_endpoint *usbep = usbintf->endpoint[index];
+
+ return ( usbep && usbep->ep.open );
+}
+
/**
* Open endpoint
*
EFI_STATUS efirc;
int rc;
+ /* Allocate structure, if needed. Once allocated, we leave
+ * the endpoint structure in place until the device is
+ * removed, to work around external UEFI code that closes the
+ * endpoint at illegal times.
+ */
+ usbep = usbintf->endpoint[index];
+ if ( ! usbep ) {
+ usbep = zalloc ( sizeof ( *usbep ) );
+ if ( ! usbep ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ usbep->usbintf = usbintf;
+ usbintf->endpoint[index] = usbep;
+ }
+
/* Get endpoint MTU */
mtu = efi_usb_mtu ( usbintf, endpoint );
if ( mtu < 0 ) {
}
/* Allocate and initialise structure */
- usbep = zalloc ( sizeof ( *usbep ) );
- if ( ! usbep ) {
- rc = -ENOMEM;
- goto err_alloc;
- }
- usbep->usbintf = usbintf;
usb_endpoint_init ( &usbep->ep, usbdev->usb, driver );
usb_endpoint_describe ( &usbep->ep, endpoint, attributes, mtu, 0,
( interval << 3 /* microframes */ ) );
strerror ( rc ) );
goto err_open;
}
-
- /* Record opened endpoint */
- usbintf->endpoint[index] = usbep;
DBGC ( usbdev, "USBDEV %s %s opened\n",
usbintf->name, usb_endpoint_name ( &usbep->ep ) );
bs->CloseEvent ( usbep->event );
err_event:
- usbintf->endpoint[index] = usbep;
usb_endpoint_close ( &usbep->ep );
err_open:
- free ( usbep );
- err_alloc:
err_mtu:
+ err_alloc:
return rc;
}
usb_endpoint_close ( &usbep->ep );
DBGC ( usbdev, "USBDEV %s %s closed\n",
usbintf->name, usb_endpoint_name ( &usbep->ep ) );
-
- /* Free endpoint */
- free ( usbep );
-
- /* Record closed endpoint */
- usbintf->endpoint[index] = NULL;
}
/**
for ( i = 0 ; i < ( sizeof ( usbintf->endpoint ) /
sizeof ( usbintf->endpoint[0] ) ) ; i++ ) {
usbep = usbintf->endpoint[i];
- if ( usbep )
+ if ( usbep && usbep->ep.open )
efi_usb_close ( usbep );
}
}
+/**
+ * Free all endpoints
+ *
+ * @v usbintf EFI USB interface
+ */
+static void efi_usb_free_all ( struct efi_usb_interface *usbintf ) {
+ struct efi_usb_endpoint *usbep;
+ unsigned int i;
+
+ for ( i = 0 ; i < ( sizeof ( usbintf->endpoint ) /
+ sizeof ( usbintf->endpoint[0] ) ) ; i++ ) {
+ usbep = usbintf->endpoint[i];
+ if ( usbep ) {
+ assert ( ! usbep->ep.open );
+ free ( usbep );
+ usbintf->endpoint[i] = NULL;
+ }
+ }
+}
+
/**
* Complete synchronous transfer
*
int rc;
/* Open endpoint, if applicable */
- if ( ( ! usbintf->endpoint[index] ) &&
+ if ( ( ! efi_usb_is_open ( usbintf, endpoint ) ) &&
( ( rc = efi_usb_open ( usbintf, endpoint, attributes, 0,
&efi_usb_sync_driver ) ) != 0 ) ) {
goto err_open;
status );
drop:
- /* Recycle I/O buffer */
- usb_recycle ( &usbep->ep, iobuf );
+ /* Recycle or free I/O buffer */
+ if ( usbep->ep.open ) {
+ usb_recycle ( &usbep->ep, iobuf );
+ } else {
+ free_iob ( iobuf );
+ }
}
/** Asynchronous endpoint operations */
EFI_STATUS efirc;
int rc;
+ /* Fail if endpoint is already open */
+ if ( efi_usb_is_open ( usbintf, endpoint ) ) {
+ rc = -EINVAL;
+ goto err_already_open;
+ }
+
/* Open endpoint */
if ( ( rc = efi_usb_open ( usbintf, endpoint,
USB_ENDPOINT_ATTR_INTERRUPT, interval,
err_prefill:
efi_usb_close ( usbep );
err_open:
+ err_already_open:
return rc;
}
unsigned int index = USB_ENDPOINT_IDX ( endpoint );
/* Do nothing if endpoint is already closed */
- usbep = usbintf->endpoint[index];
- if ( ! usbep )
+ if ( ! efi_usb_is_open ( usbintf, endpoint ) )
return;
+ usbep = usbintf->endpoint[index];
/* Stop timer */
bs->SetTimer ( usbep->event, TimerCancel, 0 );
usbintf->name, efi_handle_name ( usbintf->handle ) );
return 0;
- efi_usb_close_all ( usbintf );
bs->UninstallMultipleProtocolInterfaces (
usbintf->handle,
&efi_usb_io_protocol_guid, &usbintf->usbio,
&efi_device_path_protocol_guid, usbintf->path,
NULL );
err_install_protocol:
+ efi_usb_close_all ( usbintf );
+ efi_usb_free_all ( usbintf );
list_del ( &usbintf->list );
free ( usbintf );
err_alloc:
*/
static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_usb_device *usbdev = usbintf->usbdev;
- /* Close all endpoints */
- efi_usb_close_all ( usbintf );
+ DBGC ( usbdev, "USBDEV %s uninstalling %s\n",
+ usbintf->name, efi_handle_name ( usbintf->handle ) );
/* Uninstall protocols */
bs->UninstallMultipleProtocolInterfaces (
&efi_device_path_protocol_guid, usbintf->path,
NULL );
+ /* Close and free all endpoints */
+ efi_usb_close_all ( usbintf );
+ efi_usb_free_all ( usbintf );
+
/* Remove from list of interfaces */
list_del ( &usbintf->list );