From f2443d10ff3d4b0e3c3eb68ce43d7f26468a1b00 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 20 Sep 2010 03:57:25 +0200 Subject: [PATCH 1/5] USB: Make non-bulk delay longer in OHCI This fixes TIMEOUT with my Kingston 32GB USB3.0 flashdrive, which I experienced on my PXA270 (USB 1.1) Vpac270 board. Signed-off-by: Marek Vasut --- drivers/usb/host/ohci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 3f76c4e9f..d24697896 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1529,7 +1529,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, if (usb_pipebulk(pipe)) timeout = BULK_TO; else - timeout = 100; + timeout = 1000; /* wait for it to complete */ for (;;) { From ac5d32d15c3f950d983740aed5403f570ac15c62 Mon Sep 17 00:00:00 2001 From: Vitaly Kuzmichev Date: Wed, 22 Sep 2010 13:13:55 +0400 Subject: [PATCH 2/5] USB-CDC: Fix tx/rx_req memory leaks Remove and fix needless and destructive operations with tx/rx_req. 1) 'req' in rx_complete is always not NULL and always equals to rx_req 2) Free allocated tx_req if rx_req allocation has failed 3) Do not zero out tx/rx_req in usb_eth_init, leave this for eth_reset_config which will be called at the next use of usb0 4) Additional check in usb_eth_recv is not required Signed-off-by: Vitaly Kuzmichev --- drivers/usb/gadget/ether.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index bc6480c78..8f5eec1b4 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1276,9 +1276,6 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) debug("%s: status %d\n", __func__, req->status); packet_received = 1; - - if (req) - dev->rx_req = req; } static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags) @@ -1287,16 +1284,18 @@ static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags) dev->tx_req = usb_ep_alloc_request(dev->in_ep, 0); if (!dev->tx_req) - goto fail; + goto fail1; dev->rx_req = usb_ep_alloc_request(dev->out_ep, 0); if (!dev->rx_req) - goto fail; + goto fail2; return 0; -fail: +fail2: + usb_ep_free_request(dev->in_ep, dev->tx_req); +fail1: error("can't alloc requests"); return -1; } @@ -1791,8 +1790,6 @@ static int usb_eth_init(struct eth_device *netdev, bd_t *bd) } dev->network_started = 0; - dev->tx_req = NULL; - dev->rx_req = NULL; packet_received = 0; packet_sent = 0; @@ -1823,15 +1820,13 @@ static int usb_eth_send(struct eth_device *netdev, volatile void *packet, int length) { int retval; - struct usb_request *req = NULL; struct eth_dev *dev = &l_ethdev; + struct usb_request *req = dev->tx_req; unsigned long ts; unsigned long timeout = USB_CONNECT_TIMEOUT; debug("%s:...\n", __func__); - req = dev->tx_req; - req->buf = (void *)packet; req->context = NULL; req->complete = tx_complete; @@ -1883,8 +1878,7 @@ static int usb_eth_recv(struct eth_device *netdev) NetReceive(NetRxPackets[0], dev->rx_req->length); packet_received = 0; - if (dev->rx_req) - rx_submit(dev, dev->rx_req, 0); + rx_submit(dev, dev->rx_req, 0); } else error("dev->rx_req invalid"); } From 98fae9707fd83a61ec29d9c42c15267a735f9b71 Mon Sep 17 00:00:00 2001 From: Vitaly Kuzmichev Date: Wed, 22 Sep 2010 13:13:56 +0400 Subject: [PATCH 3/5] USB-CDC: Prevent rx_req being enqueued twice After gadget reinitializaton (after tftp has been done once) packet_received may become equal to 1 due to nuking OUT_EP while disabling it in eth_reset_config. rx_submit called from usb_eth_init queues rx_req first time. But the first call of usb_eth_recv from NetLoop queues rx_req again due to packet_received = 1. The following flow shows the path of functions calls when this happens: net/net.c:NetLoop | +-net/eth.c:eth_init | ether.c:usb_eth_init | | | +-udc_driver:usb_gadget_handle_interrupts | | udc_driver:... | | ether.c:eth_setup | | ether.c:eth_set_config | | ether.c:eth_reset_config | | udc_driver:usb_ep_disable | | udc_driver:nuke | | ether.c:rx_complete | | ether.c: packet_received = 1; | | | +-ether.c:rx_submit | udc_driver:usb_ep_queue --- The first time when rx_req is queued | +-net/eth.c:eth_rx ether.c:usb_eth_recv | +-udc_driver:usb_gadget_handle_interrupts | udc_driver:... --- no interrupts, returning +-ether.c: if (packet_received) { ... ether.c:rx_submit udc_driver:usb_ep_queue --- The second time! Signed-off-by: Vitaly Kuzmichev --- drivers/usb/gadget/ether.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 8f5eec1b4..b22ca90fc 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1810,6 +1810,7 @@ static int usb_eth_init(struct eth_device *netdev, bd_t *bd) usb_gadget_handle_interrupts(); } + packet_received = 0; rx_submit(dev, dev->rx_req, 0); return 0; fail: From 99e9ed1f49b31cc7c3b8f5d2c322b2eb26dd2a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Tue, 5 Oct 2010 22:04:26 +0200 Subject: [PATCH 4/5] usb: Add support for multiple-LUN mass storage devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch changes `usb_stor_scan' to scan all the LUNs of each mass storage device. It also fixes the various commands to correctly set the LUN field. Notably, it allows each LUN of GuruPlug's microSD card reader to be accessed. Signed-off-by: Ludovic Courtès Acked-by: Prafulla Wadaskar --- common/usb_storage.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/common/usb_storage.c b/common/usb_storage.c index 76949b85c..613c4f0f1 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -204,6 +204,22 @@ int usb_stor_info(void) return 1; } +static unsigned int usb_get_max_lun(struct us_data *us) +{ + int len; + unsigned char result; + len = usb_control_msg(us->pusb_dev, + usb_rcvctrlpipe(us->pusb_dev, 0), + US_BBB_GET_MAX_LUN, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + 0, us->ifnum, + &result, sizeof(result), + USB_CNTL_TIMEOUT * 5); + USB_STOR_PRINTF("Get Max LUN -> len = %i, result = %i\n", + len, (int) result); + return (len > 0) ? result : 0; +} + /******************************************************************************* * scan the usb and reports device info * to the user if mode = 1 @@ -241,12 +257,21 @@ int usb_stor_scan(int mode) break; /* no more devices avaiable */ if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) { - /* ok, it is a storage devices - * get info and fill it in + /* OK, it's a storage device. Iterate over its LUNs + * and populate `usb_dev_desc'. */ - if (usb_stor_get_info(dev, &usb_stor[usb_max_devs], - &usb_dev_desc[usb_max_devs]) == 1) + int lun, max_lun, start = usb_max_devs; + + max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]); + for (lun = 0; + lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV; + lun++) { + usb_dev_desc[usb_max_devs].lun = lun; + if (usb_stor_get_info(dev, &usb_stor[start], + &usb_dev_desc[usb_max_devs]) == 1) { usb_max_devs++; + } + } } /* if storage device */ if (usb_max_devs == USB_MAX_STOR_DEV) { @@ -882,6 +907,7 @@ static int usb_inquiry(ccb *srb, struct us_data *ss) do { memset(&srb->cmd[0], 0, 12); srb->cmd[0] = SCSI_INQUIRY; + srb->cmd[1] = srb->lun << 5; srb->cmd[4] = 36; srb->datalen = 36; srb->cmdlen = 12; @@ -905,6 +931,7 @@ static int usb_request_sense(ccb *srb, struct us_data *ss) ptr = (char *)srb->pdata; memset(&srb->cmd[0], 0, 12); srb->cmd[0] = SCSI_REQ_SENSE; + srb->cmd[1] = srb->lun << 5; srb->cmd[4] = 18; srb->datalen = 18; srb->pdata = &srb->sense_buf[0]; @@ -924,6 +951,7 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss) do { memset(&srb->cmd[0], 0, 12); srb->cmd[0] = SCSI_TST_U_RDY; + srb->cmd[1] = srb->lun << 5; srb->datalen = 0; srb->cmdlen = 12; if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) @@ -943,6 +971,7 @@ static int usb_read_capacity(ccb *srb, struct us_data *ss) do { memset(&srb->cmd[0], 0, 12); srb->cmd[0] = SCSI_RD_CAPAC; + srb->cmd[1] = srb->lun << 5; srb->datalen = 8; srb->cmdlen = 12; if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) @@ -957,6 +986,7 @@ static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start, { memset(&srb->cmd[0], 0, 12); srb->cmd[0] = SCSI_READ10; + srb->cmd[1] = srb->lun << 5; srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff; srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff; srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff; @@ -973,6 +1003,7 @@ static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start, { memset(&srb->cmd[0], 0, 12); srb->cmd[0] = SCSI_WRITE10; + srb->cmd[1] = srb->lun << 5; srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff; srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff; srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff; From 4ee691f6aced74c30bbe15d9e97313df21037ae3 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Mon, 9 Aug 2010 14:58:24 -0400 Subject: [PATCH 5/5] usb: musb: only write CLRDATATOG when appropriate This is a change similar to what is already in the Linux driver. We should only program the CLRDATATOG bit when the current mode indicates that it is needed. Signed-off-by: Bryan Wu Signed-off-by: Cliff Cai Signed-off-by: Mike Frysinger --- drivers/usb/musb/musb_hcd.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index af989aa78..f38b27909 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -144,19 +144,28 @@ static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out) u16 csr; if (dir_out) { - if (!toggle) - writew(MUSB_TXCSR_CLRDATATOG, &musbr->txcsr); - else { - csr = readw(&musbr->txcsr); + csr = readw(&musbr->txcsr); + if (!toggle) { + if (csr & MUSB_TXCSR_MODE) + csr = MUSB_TXCSR_CLRDATATOG; + else + csr = 0; + writew(csr, &musbr->txcsr); + } else { csr |= MUSB_TXCSR_H_WR_DATATOGGLE; writew(csr, &musbr->txcsr); csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT); writew(csr, &musbr->txcsr); } } else { - if (!toggle) - writew(MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr); - else { + if (!toggle) { + csr = readw(&musbr->txcsr); + if (csr & MUSB_TXCSR_MODE) + csr = MUSB_RXCSR_CLRDATATOG; + else + csr = 0; + writew(csr, &musbr->rxcsr); + } else { csr = readw(&musbr->rxcsr); csr |= MUSB_RXCSR_H_WR_DATATOGGLE; writew(csr, &musbr->rxcsr);