Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/usb-ehci.c | 19 ++++++++++++++----- src/usb-ehci.h | 5 ++++- src/usb-ohci.c | 17 +++++++++++++---- src/usb-ohci.h | 5 ++++- src/usb-uhci.c | 21 +++++++++++++++------ src/usb-uhci.h | 5 ++++- src/usb.c | 41 +++++++++++++++++++---------------------- src/usb.h | 3 +++ 8 files changed, 76 insertions(+), 40 deletions(-)
diff --git a/src/usb-ehci.c b/src/usb-ehci.c index 6115610..9721568 100644 --- a/src/usb-ehci.c +++ b/src/usb-ehci.c @@ -422,17 +422,26 @@ ehci_wait_td(struct ehci_pipe *pipe, struct ehci_qtd *td, int timeout) }
struct usb_pipe * -ehci_alloc_async_pipe(struct usb_pipe *dummy) +ehci_alloc_async_pipe(struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc) { if (! CONFIG_USB_EHCI) return NULL; struct usb_ehci_s *cntl = container_of( - dummy->cntl, struct usb_ehci_s, usb); - dprintf(7, "ehci_alloc_async_pipe %p %d\n", &cntl->usb, dummy->eptype); + usbdev->hub->cntl, struct usb_ehci_s, usb); + u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + dprintf(7, "ehci_alloc_async_pipe %p %d\n", &cntl->usb, eptype); + + struct usb_pipe *usbpipe = usb_getFreePipe(&cntl->usb, eptype); + if (usbpipe) { + // Use previously allocated pipe. + usb_desc2pipe(usbpipe, usbdev, epdesc); + return usbpipe; + }
// Allocate a new queue head. struct ehci_pipe *pipe; - if (dummy->eptype == USB_ENDPOINT_XFER_CONTROL) + if (eptype == USB_ENDPOINT_XFER_CONTROL) pipe = memalign_tmphigh(EHCI_QH_ALIGN, sizeof(*pipe)); else pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe)); @@ -441,7 +450,7 @@ ehci_alloc_async_pipe(struct usb_pipe *dummy) return NULL; } memset(pipe, 0, sizeof(*pipe)); - memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); + usb_desc2pipe(&pipe->pipe, usbdev, epdesc); pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
// Add queue head to controller list. diff --git a/src/usb-ehci.h b/src/usb-ehci.h index a4fbb77..ed2c3f7 100644 --- a/src/usb-ehci.h +++ b/src/usb-ehci.h @@ -3,8 +3,11 @@
// usb-ehci.c int ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci); +struct usbdevice_s; +struct usb_endpoint_descriptor; +struct usb_pipe *ehci_alloc_async_pipe(struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc); struct usb_pipe; -struct usb_pipe *ehci_alloc_async_pipe(struct usb_pipe *dummy); int ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize , void *data, int datasize); int ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); diff --git a/src/usb-ohci.c b/src/usb-ohci.c index 9522309..8703b26 100644 --- a/src/usb-ohci.c +++ b/src/usb-ohci.c @@ -319,18 +319,27 @@ wait_ed(struct ohci_ed *ed) }
struct usb_pipe * -ohci_alloc_async_pipe(struct usb_pipe *dummy) +ohci_alloc_async_pipe(struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc) { if (! CONFIG_USB_OHCI) return NULL; - if (dummy->eptype != USB_ENDPOINT_XFER_CONTROL) { + u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (eptype != USB_ENDPOINT_XFER_CONTROL) { dprintf(1, "OHCI Bulk transfers not supported.\n"); return NULL; } struct usb_ohci_s *cntl = container_of( - dummy->cntl, struct usb_ohci_s, usb); + usbdev->hub->cntl, struct usb_ohci_s, usb); dprintf(7, "ohci_alloc_async_pipe %p\n", &cntl->usb);
+ struct usb_pipe *usbpipe = usb_getFreePipe(&cntl->usb, eptype); + if (usbpipe) { + // Use previously allocated pipe. + usb_desc2pipe(usbpipe, usbdev, epdesc); + return usbpipe; + } + // Allocate a new queue head. struct ohci_pipe *pipe = malloc_tmphigh(sizeof(*pipe)); if (!pipe) { @@ -338,7 +347,7 @@ ohci_alloc_async_pipe(struct usb_pipe *dummy) return NULL; } memset(pipe, 0, sizeof(*pipe)); - memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); + usb_desc2pipe(&pipe->pipe, usbdev, epdesc); pipe->ed.hwINFO = ED_SKIP;
// Add queue head to controller list. diff --git a/src/usb-ohci.h b/src/usb-ohci.h index 6085355..bc6eb7b 100644 --- a/src/usb-ohci.h +++ b/src/usb-ohci.h @@ -3,8 +3,11 @@
// usb-ohci.c void ohci_init(struct pci_device *pci, int busid); +struct usbdevice_s; +struct usb_endpoint_descriptor; +struct usb_pipe *ohci_alloc_async_pipe(struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc); struct usb_pipe; -struct usb_pipe *ohci_alloc_async_pipe(struct usb_pipe *dummy); int ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize , void *data, int datasize); int ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); diff --git a/src/usb-uhci.c b/src/usb-uhci.c index 1c911c6..0da4eff 100644 --- a/src/usb-uhci.c +++ b/src/usb-uhci.c @@ -293,17 +293,26 @@ wait_pipe(struct uhci_pipe *pipe, int timeout) }
struct usb_pipe * -uhci_alloc_async_pipe(struct usb_pipe *dummy) +uhci_alloc_async_pipe(struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc) { if (! CONFIG_USB_UHCI) return NULL; struct usb_uhci_s *cntl = container_of( - dummy->cntl, struct usb_uhci_s, usb); - dprintf(7, "uhci_alloc_async_pipe %p %d\n", &cntl->usb, dummy->eptype); + usbdev->hub->cntl, struct usb_uhci_s, usb); + u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + dprintf(7, "uhci_alloc_async_pipe %p %d\n", &cntl->usb, eptype); + + struct usb_pipe *usbpipe = usb_getFreePipe(&cntl->usb, eptype); + if (usbpipe) { + // Use previously allocated pipe. + usb_desc2pipe(usbpipe, usbdev, epdesc); + return usbpipe; + }
// Allocate a new queue head. struct uhci_pipe *pipe; - if (dummy->eptype == USB_ENDPOINT_XFER_CONTROL) + if (eptype == USB_ENDPOINT_XFER_CONTROL) pipe = malloc_tmphigh(sizeof(*pipe)); else pipe = malloc_low(sizeof(*pipe)); @@ -312,7 +321,7 @@ uhci_alloc_async_pipe(struct usb_pipe *dummy) return NULL; } memset(pipe, 0, sizeof(*pipe)); - memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); + usb_desc2pipe(&pipe->pipe, usbdev, epdesc); pipe->qh.element = UHCI_PTR_TERM; pipe->iobase = cntl->iobase;
@@ -321,7 +330,7 @@ uhci_alloc_async_pipe(struct usb_pipe *dummy) pipe->qh.link = control_qh->link; barrier(); control_qh->link = (u32)&pipe->qh | UHCI_PTR_QH; - if (dummy->eptype == USB_ENDPOINT_XFER_CONTROL) + if (eptype == USB_ENDPOINT_XFER_CONTROL) cntl->control_qh = &pipe->qh; return &pipe->pipe; } diff --git a/src/usb-uhci.h b/src/usb-uhci.h index 0706e8f..035a565 100644 --- a/src/usb-uhci.h +++ b/src/usb-uhci.h @@ -3,8 +3,11 @@
// usb-uhci.c void uhci_init(struct pci_device *pci, int busid); +struct usbdevice_s; +struct usb_endpoint_descriptor; +struct usb_pipe *uhci_alloc_async_pipe(struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc); struct usb_pipe; -struct usb_pipe *uhci_alloc_async_pipe(struct usb_pipe *dummy); int uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize , void *data, int datasize); int uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize); diff --git a/src/usb.c b/src/usb.c index 50f8b50..b61fbc1 100644 --- a/src/usb.c +++ b/src/usb.c @@ -37,11 +37,10 @@ free_pipe(struct usb_pipe *pipe) }
// Fill "pipe" endpoint info from an endpoint descriptor. -static void -desc2pipe(struct usb_pipe *pipe, struct usbdevice_s *usbdev - , struct usb_endpoint_descriptor *epdesc) +void +usb_desc2pipe(struct usb_pipe *pipe, struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc) { - memset(pipe, 0, sizeof(*pipe)); pipe->cntl = usbdev->hub->cntl; pipe->type = usbdev->hub->cntl->type; pipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; @@ -64,38 +63,36 @@ desc2pipe(struct usb_pipe *pipe, struct usbdevice_s *usbdev } }
-// Allocate an async pipe (control or bulk). +// Check for an available pipe on the freelist. struct usb_pipe * -alloc_async_pipe(struct usbdevice_s *usbdev - , struct usb_endpoint_descriptor *epdesc) +usb_getFreePipe(struct usb_s *cntl, u8 eptype) { - struct usb_pipe dummy; - desc2pipe(&dummy, usbdev, epdesc); - - // Check for an available pipe on the freelist. - struct usb_pipe **pfree = &dummy.cntl->freelist; + struct usb_pipe **pfree = &cntl->freelist; for (;;) { struct usb_pipe *pipe = *pfree; if (!pipe) - break; - if (pipe->eptype == dummy.eptype) { - // Use previously allocated pipe. + return NULL; + if (pipe->eptype == eptype) { *pfree = pipe->freenext; - memcpy(pipe, &dummy, sizeof(*pipe)); return pipe; } pfree = &pipe->freenext; } +}
- // Allocate a new pipe. - switch (dummy.type) { +// Allocate an async pipe (control or bulk). +struct usb_pipe * +alloc_async_pipe(struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc) +{ + switch (usbdev->hub->cntl->type) { default: case USB_TYPE_UHCI: - return uhci_alloc_async_pipe(&dummy); + return uhci_alloc_async_pipe(usbdev, epdesc); case USB_TYPE_OHCI: - return ohci_alloc_async_pipe(&dummy); + return ohci_alloc_async_pipe(usbdev, epdesc); case USB_TYPE_EHCI: - return ehci_alloc_async_pipe(&dummy); + return ehci_alloc_async_pipe(usbdev, epdesc); } }
@@ -135,7 +132,7 @@ alloc_intr_pipe(struct usbdevice_s *usbdev , struct usb_endpoint_descriptor *epdesc) { struct usb_pipe dummy; - desc2pipe(&dummy, usbdev, epdesc); + usb_desc2pipe(&dummy, usbdev, epdesc); // Find the exponential period of the requested time. int period = epdesc->bInterval; int frameexp; diff --git a/src/usb.h b/src/usb.h index fff54e5..c792376 100644 --- a/src/usb.h +++ b/src/usb.h @@ -218,6 +218,9 @@ int send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *re , void *data); int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize); void free_pipe(struct usb_pipe *pipe); +void usb_desc2pipe(struct usb_pipe *pipe, struct usbdevice_s *usbdev + , struct usb_endpoint_descriptor *epdesc); +struct usb_pipe *usb_getFreePipe(struct usb_s *cntl, u8 eptype); struct usb_pipe *alloc_async_pipe(struct usbdevice_s *usbdev , struct usb_endpoint_descriptor *epdesc); struct usb_pipe *alloc_intr_pipe(struct usbdevice_s *usbdev