summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--payloads/libpayload/drivers/usb/ehci.c3
-rw-r--r--payloads/libpayload/drivers/usb/ohci.c3
-rw-r--r--payloads/libpayload/drivers/usb/uhci.c3
-rw-r--r--payloads/libpayload/drivers/usb/usb.c36
-rw-r--r--payloads/libpayload/include/usb/usb.h19
5 files changed, 57 insertions, 7 deletions
diff --git a/payloads/libpayload/drivers/usb/ehci.c b/payloads/libpayload/drivers/usb/ehci.c
index 5af99e0f53..f5c14d5031 100644
--- a/payloads/libpayload/drivers/usb/ehci.c
+++ b/payloads/libpayload/drivers/usb/ehci.c
@@ -754,6 +754,9 @@ ehci_init (pcidev_t addr)
controller->shutdown = ehci_shutdown;
controller->bulk = ehci_bulk;
controller->control = ehci_control;
+ controller->set_address = generic_set_address;
+ controller->finish_device_config = NULL;
+ controller->destroy_device = NULL;
controller->create_intr_queue = ehci_create_intr_queue;
controller->destroy_intr_queue = ehci_destroy_intr_queue;
controller->poll_intr_queue = ehci_poll_intr_queue;
diff --git a/payloads/libpayload/drivers/usb/ohci.c b/payloads/libpayload/drivers/usb/ohci.c
index 44eba310c3..95db5f4af8 100644
--- a/payloads/libpayload/drivers/usb/ohci.c
+++ b/payloads/libpayload/drivers/usb/ohci.c
@@ -189,6 +189,9 @@ ohci_init (pcidev_t addr)
controller->shutdown = ohci_shutdown;
controller->bulk = ohci_bulk;
controller->control = ohci_control;
+ controller->set_address = generic_set_address;
+ controller->finish_device_config = NULL;
+ controller->destroy_device = NULL;
controller->create_intr_queue = ohci_create_intr_queue;
controller->destroy_intr_queue = ohci_destroy_intr_queue;
controller->poll_intr_queue = ohci_poll_intr_queue;
diff --git a/payloads/libpayload/drivers/usb/uhci.c b/payloads/libpayload/drivers/usb/uhci.c
index bfa1b57d43..f9c361de22 100644
--- a/payloads/libpayload/drivers/usb/uhci.c
+++ b/payloads/libpayload/drivers/usb/uhci.c
@@ -170,6 +170,9 @@ uhci_init (pcidev_t addr)
controller->shutdown = uhci_shutdown;
controller->bulk = uhci_bulk;
controller->control = uhci_control;
+ controller->set_address = generic_set_address;
+ controller->finish_device_config = NULL;
+ controller->destroy_device = NULL;
controller->create_intr_queue = uhci_create_intr_queue;
controller->destroy_intr_queue = uhci_destroy_intr_queue;
controller->poll_intr_queue = uhci_poll_intr_queue;
diff --git a/payloads/libpayload/drivers/usb/usb.c b/payloads/libpayload/drivers/usb/usb.c
index 6dafd076c4..54a5935c1a 100644
--- a/payloads/libpayload/drivers/usb/usb.c
+++ b/payloads/libpayload/drivers/usb/usb.c
@@ -242,13 +242,11 @@ get_free_address (hci_t *controller)
return -1; // no free address
}
-static int
-set_address (hci_t *controller, int speed, int hubport, int hubaddr)
+int
+generic_set_address (hci_t *controller, int speed, int hubport, int hubaddr)
{
int adr = get_free_address (controller); // address to set
dev_req_t dr;
- configuration_descriptor_t *cd;
- device_descriptor_t *dd;
memset (&dr, 0, sizeof (dr));
dr.data_dir = host_to_device;
@@ -273,11 +271,29 @@ set_address (hci_t *controller, int speed, int hubport, int hubaddr)
dev->endpoints[0].direction = SETUP;
mdelay (50);
if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
- usb_debug ("set_address failed\n");
return -1;
}
mdelay (50);
+
+ return adr;
+}
+
+static int
+set_address (hci_t *controller, int speed, int hubport, int hubaddr)
+{
+ int adr = controller->set_address(controller, speed, hubport, hubaddr);
+ if (adr < 0 || !controller->devices[adr]) {
+ usb_debug ("set_address failed\n");
+ return -1;
+ }
+ configuration_descriptor_t *cd;
+ device_descriptor_t *dd;
+
+ usbdev_t *dev = controller->devices[adr];
dev->address = adr;
+ dev->hub = hubaddr;
+ dev->port = hubport;
+ dev->speed = speed;
dev->descriptor = get_descriptor (dev, gen_bmRequestType
(device_to_host, standard_type, dev_recp), 1, 0, 0);
dd = (device_descriptor_t *) dev->descriptor;
@@ -298,7 +314,6 @@ set_address (hci_t *controller, int speed, int hubport, int hubaddr)
dev->configuration = get_descriptor (dev, gen_bmRequestType
(device_to_host, standard_type, dev_recp), 2, 0, 0);
cd = (configuration_descriptor_t *) dev->configuration;
- set_configuration (dev);
interface_descriptor_t *interface =
(interface_descriptor_t *) (((char *) cd) + cd->bLength);
{
@@ -366,6 +381,13 @@ set_address (hci_t *controller, int speed, int hubport, int hubaddr)
}
}
+ if (controller->finish_device_config &&
+ controller->finish_device_config(dev))
+ return adr; /* Device isn't configured correctly,
+ only control transfers may work. */
+
+ set_configuration(dev);
+
int class = dd->bDeviceClass;
if (class == 0)
class = interface->bInterfaceClass;
@@ -475,6 +497,8 @@ usb_detach_device(hci_t *controller, int devno)
controller->devices[devno]->destroy (controller->devices[devno]);
free(controller->devices[devno]);
controller->devices[devno] = NULL;
+ if (controller->destroy_device)
+ controller->destroy_device(controller, devno);
}
}
diff --git a/payloads/libpayload/include/usb/usb.h b/payloads/libpayload/include/usb/usb.h
index fc3ce5a50f..3aac2aee6c 100644
--- a/payloads/libpayload/include/usb/usb.h
+++ b/payloads/libpayload/include/usb/usb.h
@@ -115,7 +115,7 @@ struct usbdev {
typedef enum { OHCI = 0, UHCI = 1, EHCI = 2, XHCI = 3} hc_type;
struct usbdev_hc {
- struct usbdev_hc *next;
+ hci_t *next;
pcidev_t bus_address;
u32 reg_base;
hc_type type;
@@ -143,6 +143,20 @@ struct usbdev_hc {
void (*destroy_intr_queue) (endpoint_t *ep, void *queue);
u8* (*poll_intr_queue) (void *queue);
void *instance;
+
+ /* set_address(): Tell the usb device its address and
+ return it. xHCI controllers want to
+ do this by themself. Also, the usbdev
+ structure has to be allocated and
+ initialized. */
+ int (*set_address) (hci_t *controller, int speed, int hubport, int hubaddr);
+ /* finish_device_config(): Another hook for xHCI,
+ returns 0 on success. */
+ int (*finish_device_config) (usbdev_t *dev);
+ /* destroy_device(): Finally, destroy all structures that
+ were allocated during set_address()
+ and finish_device_config(). */
+ void (*destroy_device) (hci_t *controller, int devaddr);
};
typedef struct {
@@ -250,6 +264,9 @@ gen_bmRequestType (dev_req_dir dir, dev_req_type type, dev_req_recp recp)
return (dir << 7) | (type << 5) | recp;
}
+/* default "set address" handler */
+int generic_set_address (hci_t *controller, int speed, int hubport, int hubaddr);
+
void usb_detach_device(hci_t *controller, int devno);
int usb_attach_device(hci_t *controller, int hubaddress, int port, int speed);