diff --git a/payloads/libpayload/drivers/usb/ehci.c b/payloads/libpayload/drivers/usb/ehci.c index 6e9f03aff0..35292e5706 100644 --- a/payloads/libpayload/drivers/usb/ehci.c +++ b/payloads/libpayload/drivers/usb/ehci.c @@ -270,6 +270,7 @@ static void free_qh_and_tds(ehci_qh_t *qh, qtd_t *cur) static int wait_for_tds(qtd_t *head) { + /* returns the amount of bytes *not* transmitted, or -1 for error */ int result = 0; qtd_t *cur = head; while (1) { @@ -291,16 +292,18 @@ static int wait_for_tds(qtd_t *head) if (timeout < 0) { usb_debug("Error: ehci: queue transfer " "processing timed out.\n"); - return 1; + return -1; } if (cur->token & QTD_HALTED) { usb_debug("ERROR with packet\n"); dump_td(virt_to_phys(cur)); usb_debug("-----------------\n"); - return 1; + return -1; } + result += (cur->token & QTD_TOTAL_LEN_MASK) + >> QTD_TOTAL_LEN_SHIFT; if (cur->next_qtd & 1) { - return 0; + break; } if (0) dump_td(virt_to_phys(cur)); /* helps debugging the TD chain */ @@ -338,13 +341,13 @@ static int ehci_process_async_schedule( int result; /* make sure async schedule is disabled */ - if (ehci_set_async_schedule(ehcic, 0)) return 1; + if (ehci_set_async_schedule(ehcic, 0)) return -1; /* hook up QH */ ehcic->operation->asynclistaddr = virt_to_phys(qhead); /* start async schedule */ - if (ehci_set_async_schedule(ehcic, 1)) return 1; + if (ehci_set_async_schedule(ehcic, 1)) return -1; /* wait for result */ result = wait_for_tds(head); @@ -358,6 +361,7 @@ static int ehci_process_async_schedule( static int ehci_bulk (endpoint_t *ep, int size, u8 *data, int finalize) { int result = 0; + int remaining = size; int endp = ep->endpoint & 0xf; int pid = (ep->direction==IN)?EHCI_IN:EHCI_OUT; @@ -365,7 +369,7 @@ static int ehci_bulk (endpoint_t *ep, int size, u8 *data, int finalize) if (ep->dev->speed < 2) { /* we need a split transaction */ if (closest_usb2_hub(ep->dev, &hubaddr, &hubport)) - return 1; + return -1; } qtd_t *head = memalign(64, sizeof(qtd_t)); @@ -375,12 +379,12 @@ static int ehci_bulk (endpoint_t *ep, int size, u8 *data, int finalize) cur->token = QTD_ACTIVE | (pid << QTD_PID_SHIFT) | (0 << QTD_CERR_SHIFT); - u32 chunk = fill_td(cur, data, size); - size -= chunk; + u32 chunk = fill_td(cur, data, remaining); + remaining -= chunk; data += chunk; cur->alt_next_qtd = QTD_TERMINATE; - if (size == 0) { + if (remaining == 0) { cur->next_qtd = virt_to_phys(0) | QTD_TERMINATE; break; } else { @@ -411,10 +415,13 @@ static int ehci_bulk (endpoint_t *ep, int size, u8 *data, int finalize) result = ehci_process_async_schedule( EHCI_INST(ep->dev->controller), qh, head); + if (result >= 0) + result = size - result; ep->toggle = (cur->token & QTD_TOGGLE_MASK) >> QTD_TOGGLE_SHIFT; free_qh_and_tds(qh, head); + return result; } @@ -432,7 +439,7 @@ static int ehci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq if (dev->speed < 2) { /* we need a split transaction */ if (closest_usb2_hub(dev, &hubaddr, &hubport)) - return 1; + return -1; non_hs_ctrl_ep = 1; } @@ -499,6 +506,8 @@ static int ehci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq result = ehci_process_async_schedule( EHCI_INST(dev->controller), qh, head); + if (result >= 0) + result = dalen - result; free_qh_and_tds(qh, head); return result; diff --git a/payloads/libpayload/drivers/usb/ohci.c b/payloads/libpayload/drivers/usb/ohci.c index 51ea8fb433..8a09a953f4 100644 --- a/payloads/libpayload/drivers/usb/ohci.c +++ b/payloads/libpayload/drivers/usb/ohci.c @@ -44,7 +44,7 @@ static int ohci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq static void* ohci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming); static void ohci_destroy_intr_queue (endpoint_t *ep, void *queue); static u8* ohci_poll_intr_queue (void *queue); -static void ohci_process_done_queue(ohci_t *ohci, int spew_debug); +static int ohci_process_done_queue(ohci_t *ohci, int spew_debug); #ifdef USB_DEBUG static void @@ -319,13 +319,13 @@ wait_for_ed(usbdev_t *dev, ed_t *head, int pages) usb_debug("Error: ohci: endpoint " "descriptor processing timed out.\n"); /* Clear the done queue. */ - ohci_process_done_queue(OHCI_INST(dev->controller), 1); + int result = ohci_process_done_queue(OHCI_INST(dev->controller), 1); if (head->head_pointer & 1) { usb_debug("HALTED!\n"); - return 1; + return -1; } - return 0; + return result; } static void @@ -353,6 +353,7 @@ static int ohci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen, unsigned char *data) { + int remaining = dalen; td_t *cur; // pages are specified as 4K in OHCI, so don't use getpagesize() @@ -390,21 +391,21 @@ ohci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen cur->current_buffer_pointer = virt_to_phys(data); pages--; int consumed = (4096 - ((unsigned long)data % 4096)); - if (consumed >= dalen) { + if (consumed >= remaining) { // end of data is within same page - cur->buffer_end = virt_to_phys(data + dalen - 1); - dalen = 0; + cur->buffer_end = virt_to_phys(data + remaining - 1); + remaining = 0; /* assert(pages == 0); */ } else { - dalen -= consumed; + remaining -= consumed; data += consumed; pages--; - int second_page_size = dalen; - if (dalen > 4096) { + int second_page_size = remaining; + if (remaining > 4096) { second_page_size = 4096; } cur->buffer_end = virt_to_phys(data + second_page_size - 1); - dalen -= second_page_size; + remaining -= second_page_size; data += second_page_size; } } @@ -452,7 +453,7 @@ ohci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen OHCI_INST(dev->controller)->opreg->HcControl |= ControlListEnable; OHCI_INST(dev->controller)->opreg->HcCommandStatus = ControlListFilled; - int failure = wait_for_ed(dev, head, + int result = wait_for_ed(dev, head, (dalen==0)?0:(last_page - first_page + 1)); /* Wait some frames before and one after disabling list access. */ mdelay(4); @@ -462,7 +463,10 @@ ohci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen /* free memory */ ohci_free_ed(head); - return failure; + if (result >= 0) + result = dalen - result; + + return result; } /* finalize == 1: if data is of packet aligned size, add a zero length packet */ @@ -470,6 +474,7 @@ static int ohci_bulk (endpoint_t *ep, int dalen, u8 *data, int finalize) { int i; + int remaining = dalen; usb_debug("bulk: %x bytes from %x, finalize: %x, maxpacketsize: %x\n", dalen, data, finalize, ep->maxpacketsize); td_t *cur, *next; @@ -499,28 +504,28 @@ ohci_bulk (endpoint_t *ep, int dalen, u8 *data, int finalize) TD_CC_NOACCESS; cur->current_buffer_pointer = virt_to_phys(data); pages--; - if (dalen == 0) { + if (remaining == 0) { /* magic TD for empty packet transfer */ cur->current_buffer_pointer = 0; cur->buffer_end = 0; /* assert((pages == 0) && finalize); */ } int consumed = (4096 - ((unsigned long)data % 4096)); - if (consumed >= dalen) { + if (consumed >= remaining) { // end of data is within same page - cur->buffer_end = virt_to_phys(data + dalen - 1); - dalen = 0; + cur->buffer_end = virt_to_phys(data + remaining - 1); + remaining = 0; /* assert(pages == finalize); */ } else { - dalen -= consumed; + remaining -= consumed; data += consumed; pages--; - int second_page_size = dalen; - if (dalen > 4096) { + int second_page_size = remaining; + if (remaining > 4096) { second_page_size = 4096; } cur->buffer_end = virt_to_phys(data + second_page_size - 1); - dalen -= second_page_size; + remaining -= second_page_size; data += second_page_size; } /* One more TD. */ @@ -556,7 +561,7 @@ ohci_bulk (endpoint_t *ep, int dalen, u8 *data, int finalize) OHCI_INST(ep->dev->controller)->opreg->HcControl |= BulkListEnable; OHCI_INST(ep->dev->controller)->opreg->HcCommandStatus = BulkListFilled; - int failure = wait_for_ed(ep->dev, head, + int result = wait_for_ed(ep->dev, head, (dalen==0)?0:(last_page - first_page + 1)); /* Wait some frames before and one after disabling list access. */ mdelay(4); @@ -568,12 +573,12 @@ ohci_bulk (endpoint_t *ep, int dalen, u8 *data, int finalize) /* free memory */ ohci_free_ed(head); - if (failure) { - /* try cleanup */ + if (result >= 0) + result = dalen - result; + else clear_stall(ep); - } - return failure; + return result; } @@ -778,9 +783,11 @@ ohci_poll_intr_queue(void *const q_) return data; } -static void +static int ohci_process_done_queue(ohci_t *const ohci, const int spew_debug) { + /* returns the amount of bytes *not* transmitted for short packets */ + int result = 0; int i, j; /* Temporary queue of interrupt queue TDs (to reverse order). */ @@ -788,7 +795,7 @@ ohci_process_done_queue(ohci_t *const ohci, const int spew_debug) /* Check if done head has been written. */ if (!(ohci->opreg->HcInterruptStatus & WritebackDoneHead)) - return; + return 0; /* Fetch current done head. Lsb is only interesting for hw interrupts. */ u32 phys_done_queue = ohci->hcca->HccaDoneHead & ~1; @@ -805,7 +812,11 @@ ohci_process_done_queue(ohci_t *const ohci, const int spew_debug) switch (done_td->config & TD_QUEUETYPE_MASK) { case TD_QUEUETYPE_ASYNC: - /* Free processed async TDs. */ + /* Free processed async TDs and count short transfer. */ + if (done_td->current_buffer_pointer) + result += (done_td->buffer_end & 0xfff) - + (done_td->current_buffer_pointer + & 0xfff) + 1; free((void *)done_td); break; case TD_QUEUETYPE_INTR: { @@ -862,5 +873,7 @@ ohci_process_done_queue(ohci_t *const ohci, const int spew_debug) } if (spew_debug) usb_debug("processed %d done tds, %d intr tds thereof.\n", i, j); + + return result; } diff --git a/payloads/libpayload/drivers/usb/uhci.c b/payloads/libpayload/drivers/usb/uhci.c index df9bdca03c..94d855205b 100644 --- a/payloads/libpayload/drivers/usb/uhci.c +++ b/payloads/libpayload/drivers/usb/uhci.c @@ -383,7 +383,7 @@ uhci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen } else { usb_debug ("control packet, req %x\n", req); td_dump (td); - result = 1; + result = -1; } free (tds); return result; @@ -465,7 +465,7 @@ uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize) usb_debug("Stalled. Trying to clean up.\n"); clear_stall (ep); free (tds); - return 1; + return -1; } ep->toggle = toggle; free (tds); diff --git a/payloads/libpayload/drivers/usb/usb.c b/payloads/libpayload/drivers/usb/usb.c index 23561c40aa..83d03735a8 100644 --- a/payloads/libpayload/drivers/usb/usb.c +++ b/payloads/libpayload/drivers/usb/usb.c @@ -157,7 +157,7 @@ get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType, dr.wValue = (descType << 8) | descIdx; dr.wIndex = langID; dr.wLength = 8; - if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) { + if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf) < 0) { usb_debug ("getting descriptor size (type %x) failed\n", descType); } @@ -181,7 +181,7 @@ get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType, memset (result, 0, size); dr.wLength = size; if (dev->controller-> - control (dev, IN, sizeof (dr), &dr, size, result)) { + control (dev, IN, sizeof (dr), &dr, size, result) < 0) { usb_debug ("getting descriptor (type %x, size %x) failed\n", descType, size); } @@ -213,7 +213,7 @@ clear_feature (usbdev_t *dev, int endp, int feature, int rtype) dr.wValue = feature; dr.wIndex = endp; dr.wLength = 0; - return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0); + return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0; } int @@ -272,7 +272,7 @@ set_address (hci_t *controller, int speed, int hubport, int hubaddr) dev->endpoints[0].toggle = 0; dev->endpoints[0].direction = SETUP; mdelay (50); - if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) { + if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0) { usb_debug ("set_address failed\n"); return -1; } diff --git a/payloads/libpayload/drivers/usb/usbmsc.c b/payloads/libpayload/drivers/usb/usbmsc.c index f1de483170..2d28fbd12f 100644 --- a/payloads/libpayload/drivers/usb/usbmsc.c +++ b/payloads/libpayload/drivers/usb/usbmsc.c @@ -184,7 +184,7 @@ reset_transport (usbdev_t *dev) dr.wLength = 0; /* if any of these fails, detach device, as we are lost */ - if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) || + if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0 || clear_stall (MSC_INST (dev)->bulk_in) || clear_stall (MSC_INST (dev)->bulk_out)) { usb_debug ("Detaching unresponsive device.\n"); @@ -211,9 +211,8 @@ get_max_luns (usbdev_t *dev) dr.wValue = 0; dr.wIndex = 0; dr.wLength = 1; - if (dev->controller->control (dev, IN, sizeof (dr), &dr, 1, &luns)) { + if (dev->controller->control (dev, IN, sizeof (dr), &dr, 1, &luns) < 0) luns = 0; // assume only 1 lun if req fails - } return luns; } @@ -239,10 +238,10 @@ wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd, static int get_csw (endpoint_t *ep, csw_t *csw) { - if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1)) { + if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1) < 0) { clear_stall (ep); if (ep->dev->controller->bulk - (ep, sizeof (csw_t), (u8 *) csw, 1)) { + (ep, sizeof (csw_t), (u8 *) csw, 1) < 0) { return reset_transport (ep->dev); } } @@ -265,17 +264,17 @@ execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen, } wrap_cbw (&cbw, buflen, dir, cb, cblen); if (dev->controller-> - bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0)) { + bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0) < 0) { return reset_transport (dev); } if (buflen > 0) { if (dir == cbw_direction_data_in) { if (dev->controller-> - bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) + bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0) < 0) clear_stall (MSC_INST (dev)->bulk_in); } else { if (dev->controller-> - bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) + bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0) < 0) clear_stall (MSC_INST (dev)->bulk_out); } } diff --git a/payloads/libpayload/drivers/usb/xhci.c b/payloads/libpayload/drivers/usb/xhci.c index 341b5969c2..512cf5d106 100644 --- a/payloads/libpayload/drivers/usb/xhci.c +++ b/payloads/libpayload/drivers/usb/xhci.c @@ -242,7 +242,7 @@ static int xhci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen, unsigned char *data) { - return 1; + return -1; } /* finalize == 1: if data is of packet aligned size, add a zero length packet */ @@ -252,7 +252,7 @@ xhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize) int maxpsize = ep->maxpacketsize; if (maxpsize == 0) fatal("MaxPacketSize == 0!!!"); - return 1; + return -1; } /* create and hook-up an intr queue into device schedule */