12731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 22731b9a8SJean-Christophe PLAGNIOL-VILLARD * Mentor USB OTG Core host controller driver. 32731b9a8SJean-Christophe PLAGNIOL-VILLARD * 42731b9a8SJean-Christophe PLAGNIOL-VILLARD * Copyright (c) 2008 Texas Instruments 52731b9a8SJean-Christophe PLAGNIOL-VILLARD * 62731b9a8SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 72731b9a8SJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 82731b9a8SJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 92731b9a8SJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 102731b9a8SJean-Christophe PLAGNIOL-VILLARD * 112731b9a8SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 122731b9a8SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 132731b9a8SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 142731b9a8SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 152731b9a8SJean-Christophe PLAGNIOL-VILLARD * 162731b9a8SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 172731b9a8SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 182731b9a8SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 192731b9a8SJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 202731b9a8SJean-Christophe PLAGNIOL-VILLARD * 212731b9a8SJean-Christophe PLAGNIOL-VILLARD * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments 222731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 232731b9a8SJean-Christophe PLAGNIOL-VILLARD 242731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 252731b9a8SJean-Christophe PLAGNIOL-VILLARD #include "musb_hcd.h" 262731b9a8SJean-Christophe PLAGNIOL-VILLARD 272731b9a8SJean-Christophe PLAGNIOL-VILLARD /* MSC control transfers */ 282731b9a8SJean-Christophe PLAGNIOL-VILLARD #define USB_MSC_BBB_RESET 0xFF 292731b9a8SJean-Christophe PLAGNIOL-VILLARD #define USB_MSC_BBB_GET_MAX_LUN 0xFE 302731b9a8SJean-Christophe PLAGNIOL-VILLARD 312731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Endpoint configuration information */ 322731b9a8SJean-Christophe PLAGNIOL-VILLARD static struct musb_epinfo epinfo[3] = { 332731b9a8SJean-Christophe PLAGNIOL-VILLARD {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */ 342731b9a8SJean-Christophe PLAGNIOL-VILLARD {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In - 512 Bytes */ 352731b9a8SJean-Christophe PLAGNIOL-VILLARD {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */ 362731b9a8SJean-Christophe PLAGNIOL-VILLARD }; 372731b9a8SJean-Christophe PLAGNIOL-VILLARD 38*321790f6SBryan Wu /* --- Virtual Root Hub ---------------------------------------------------- */ 39*321790f6SBryan Wu #ifdef MUSB_NO_MULTIPOINT 40*321790f6SBryan Wu static int rh_devnum; 41*321790f6SBryan Wu static u32 port_status; 42*321790f6SBryan Wu 43*321790f6SBryan Wu /* Device descriptor */ 44*321790f6SBryan Wu static u8 root_hub_dev_des[] = { 45*321790f6SBryan Wu 0x12, /* __u8 bLength; */ 46*321790f6SBryan Wu 0x01, /* __u8 bDescriptorType; Device */ 47*321790f6SBryan Wu 0x00, /* __u16 bcdUSB; v1.1 */ 48*321790f6SBryan Wu 0x02, 49*321790f6SBryan Wu 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 50*321790f6SBryan Wu 0x00, /* __u8 bDeviceSubClass; */ 51*321790f6SBryan Wu 0x00, /* __u8 bDeviceProtocol; */ 52*321790f6SBryan Wu 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 53*321790f6SBryan Wu 0x00, /* __u16 idVendor; */ 54*321790f6SBryan Wu 0x00, 55*321790f6SBryan Wu 0x00, /* __u16 idProduct; */ 56*321790f6SBryan Wu 0x00, 57*321790f6SBryan Wu 0x00, /* __u16 bcdDevice; */ 58*321790f6SBryan Wu 0x00, 59*321790f6SBryan Wu 0x00, /* __u8 iManufacturer; */ 60*321790f6SBryan Wu 0x01, /* __u8 iProduct; */ 61*321790f6SBryan Wu 0x00, /* __u8 iSerialNumber; */ 62*321790f6SBryan Wu 0x01 /* __u8 bNumConfigurations; */ 63*321790f6SBryan Wu }; 64*321790f6SBryan Wu 65*321790f6SBryan Wu /* Configuration descriptor */ 66*321790f6SBryan Wu static u8 root_hub_config_des[] = { 67*321790f6SBryan Wu 0x09, /* __u8 bLength; */ 68*321790f6SBryan Wu 0x02, /* __u8 bDescriptorType; Configuration */ 69*321790f6SBryan Wu 0x19, /* __u16 wTotalLength; */ 70*321790f6SBryan Wu 0x00, 71*321790f6SBryan Wu 0x01, /* __u8 bNumInterfaces; */ 72*321790f6SBryan Wu 0x01, /* __u8 bConfigurationValue; */ 73*321790f6SBryan Wu 0x00, /* __u8 iConfiguration; */ 74*321790f6SBryan Wu 0x40, /* __u8 bmAttributes; 75*321790f6SBryan Wu Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ 76*321790f6SBryan Wu 0x00, /* __u8 MaxPower; */ 77*321790f6SBryan Wu 78*321790f6SBryan Wu /* interface */ 79*321790f6SBryan Wu 0x09, /* __u8 if_bLength; */ 80*321790f6SBryan Wu 0x04, /* __u8 if_bDescriptorType; Interface */ 81*321790f6SBryan Wu 0x00, /* __u8 if_bInterfaceNumber; */ 82*321790f6SBryan Wu 0x00, /* __u8 if_bAlternateSetting; */ 83*321790f6SBryan Wu 0x01, /* __u8 if_bNumEndpoints; */ 84*321790f6SBryan Wu 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ 85*321790f6SBryan Wu 0x00, /* __u8 if_bInterfaceSubClass; */ 86*321790f6SBryan Wu 0x00, /* __u8 if_bInterfaceProtocol; */ 87*321790f6SBryan Wu 0x00, /* __u8 if_iInterface; */ 88*321790f6SBryan Wu 89*321790f6SBryan Wu /* endpoint */ 90*321790f6SBryan Wu 0x07, /* __u8 ep_bLength; */ 91*321790f6SBryan Wu 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 92*321790f6SBryan Wu 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 93*321790f6SBryan Wu 0x03, /* __u8 ep_bmAttributes; Interrupt */ 94*321790f6SBryan Wu 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ 95*321790f6SBryan Wu 0x02, 96*321790f6SBryan Wu 0xff /* __u8 ep_bInterval; 255 ms */ 97*321790f6SBryan Wu }; 98*321790f6SBryan Wu 99*321790f6SBryan Wu static unsigned char root_hub_str_index0[] = { 100*321790f6SBryan Wu 0x04, /* __u8 bLength; */ 101*321790f6SBryan Wu 0x03, /* __u8 bDescriptorType; String-descriptor */ 102*321790f6SBryan Wu 0x09, /* __u8 lang ID */ 103*321790f6SBryan Wu 0x04, /* __u8 lang ID */ 104*321790f6SBryan Wu }; 105*321790f6SBryan Wu 106*321790f6SBryan Wu static unsigned char root_hub_str_index1[] = { 107*321790f6SBryan Wu 0x1c, /* __u8 bLength; */ 108*321790f6SBryan Wu 0x03, /* __u8 bDescriptorType; String-descriptor */ 109*321790f6SBryan Wu 'M', /* __u8 Unicode */ 110*321790f6SBryan Wu 0, /* __u8 Unicode */ 111*321790f6SBryan Wu 'U', /* __u8 Unicode */ 112*321790f6SBryan Wu 0, /* __u8 Unicode */ 113*321790f6SBryan Wu 'S', /* __u8 Unicode */ 114*321790f6SBryan Wu 0, /* __u8 Unicode */ 115*321790f6SBryan Wu 'B', /* __u8 Unicode */ 116*321790f6SBryan Wu 0, /* __u8 Unicode */ 117*321790f6SBryan Wu ' ', /* __u8 Unicode */ 118*321790f6SBryan Wu 0, /* __u8 Unicode */ 119*321790f6SBryan Wu 'R', /* __u8 Unicode */ 120*321790f6SBryan Wu 0, /* __u8 Unicode */ 121*321790f6SBryan Wu 'o', /* __u8 Unicode */ 122*321790f6SBryan Wu 0, /* __u8 Unicode */ 123*321790f6SBryan Wu 'o', /* __u8 Unicode */ 124*321790f6SBryan Wu 0, /* __u8 Unicode */ 125*321790f6SBryan Wu 't', /* __u8 Unicode */ 126*321790f6SBryan Wu 0, /* __u8 Unicode */ 127*321790f6SBryan Wu ' ', /* __u8 Unicode */ 128*321790f6SBryan Wu 0, /* __u8 Unicode */ 129*321790f6SBryan Wu 'H', /* __u8 Unicode */ 130*321790f6SBryan Wu 0, /* __u8 Unicode */ 131*321790f6SBryan Wu 'u', /* __u8 Unicode */ 132*321790f6SBryan Wu 0, /* __u8 Unicode */ 133*321790f6SBryan Wu 'b', /* __u8 Unicode */ 134*321790f6SBryan Wu 0, /* __u8 Unicode */ 135*321790f6SBryan Wu }; 136*321790f6SBryan Wu #endif 137*321790f6SBryan Wu 1382731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 1392731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function writes the data toggle value. 1402731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 1412731b9a8SJean-Christophe PLAGNIOL-VILLARD static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out) 1422731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1432731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 toggle = usb_gettoggle(dev, ep, dir_out); 1442731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 1452731b9a8SJean-Christophe PLAGNIOL-VILLARD 1462731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) { 1472731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!toggle) 1482731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(MUSB_TXCSR_CLRDATATOG, &musbr->txcsr); 1492731b9a8SJean-Christophe PLAGNIOL-VILLARD else { 1502731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 1512731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= MUSB_TXCSR_H_WR_DATATOGGLE; 1522731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 1532731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT); 1542731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 1552731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1562731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 1572731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!toggle) 1582731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr); 1592731b9a8SJean-Christophe PLAGNIOL-VILLARD else { 1602731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 1612731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= MUSB_RXCSR_H_WR_DATATOGGLE; 1622731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 1632731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE); 1642731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 1652731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1662731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1672731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1682731b9a8SJean-Christophe PLAGNIOL-VILLARD 1692731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 1702731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function checks if RxStall has occured on the endpoint. If a RxStall 1712731b9a8SJean-Christophe PLAGNIOL-VILLARD * has occured, the RxStall is cleared and 1 is returned. If RxStall has 1722731b9a8SJean-Christophe PLAGNIOL-VILLARD * not occured, 0 is returned. 1732731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 1742731b9a8SJean-Christophe PLAGNIOL-VILLARD static u8 check_stall(u8 ep, u8 dir_out) 1752731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1762731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 1772731b9a8SJean-Christophe PLAGNIOL-VILLARD 1782731b9a8SJean-Christophe PLAGNIOL-VILLARD /* For endpoint 0 */ 1792731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!ep) { 1802731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 1812731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_CSR0_H_RXSTALL) { 1822731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_CSR0_H_RXSTALL; 1832731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 1842731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1; 1852731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1862731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { /* For non-ep0 */ 1872731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) { /* is it tx ep */ 1882731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 1892731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_TXCSR_H_RXSTALL) { 1902731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_TXCSR_H_RXSTALL; 1912731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 1922731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1; 1932731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1942731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { /* is it rx ep */ 1952731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 1962731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_RXCSR_H_RXSTALL) { 1972731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_H_RXSTALL; 1982731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 1992731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1; 2002731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2012731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2022731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2032731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 2042731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2052731b9a8SJean-Christophe PLAGNIOL-VILLARD 2062731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 2072731b9a8SJean-Christophe PLAGNIOL-VILLARD * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout 2082731b9a8SJean-Christophe PLAGNIOL-VILLARD * error and -2 for stall. 2092731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 2102731b9a8SJean-Christophe PLAGNIOL-VILLARD static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask) 2112731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2122731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 2132731b9a8SJean-Christophe PLAGNIOL-VILLARD int result = 1; 214c3a012ceSBryan Wu int timeout = CONFIG_MUSB_TIMEOUT; 2152731b9a8SJean-Christophe PLAGNIOL-VILLARD 2162731b9a8SJean-Christophe PLAGNIOL-VILLARD while (result > 0) { 2172731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 2182731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_CSR0_H_ERROR) { 2192731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_CSR0_H_ERROR; 2202731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 2212731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_CRC_ERR; 2222731b9a8SJean-Christophe PLAGNIOL-VILLARD result = -1; 2232731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 2242731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2252731b9a8SJean-Christophe PLAGNIOL-VILLARD 2262731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (bit_mask) { 2272731b9a8SJean-Christophe PLAGNIOL-VILLARD case MUSB_CSR0_TXPKTRDY: 2282731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(csr & MUSB_CSR0_TXPKTRDY)) { 2292731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(MUSB_CONTROL_EP, 0)) { 2302731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED; 2312731b9a8SJean-Christophe PLAGNIOL-VILLARD result = -2; 2322731b9a8SJean-Christophe PLAGNIOL-VILLARD } else 2332731b9a8SJean-Christophe PLAGNIOL-VILLARD result = 0; 2342731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2352731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 2362731b9a8SJean-Christophe PLAGNIOL-VILLARD 2372731b9a8SJean-Christophe PLAGNIOL-VILLARD case MUSB_CSR0_RXPKTRDY: 2382731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(MUSB_CONTROL_EP, 0)) { 2392731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED; 2402731b9a8SJean-Christophe PLAGNIOL-VILLARD result = -2; 2412731b9a8SJean-Christophe PLAGNIOL-VILLARD } else 2422731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_CSR0_RXPKTRDY) 2432731b9a8SJean-Christophe PLAGNIOL-VILLARD result = 0; 2442731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 2452731b9a8SJean-Christophe PLAGNIOL-VILLARD 2462731b9a8SJean-Christophe PLAGNIOL-VILLARD case MUSB_CSR0_H_REQPKT: 2472731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(csr & MUSB_CSR0_H_REQPKT)) { 2482731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(MUSB_CONTROL_EP, 0)) { 2492731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED; 2502731b9a8SJean-Christophe PLAGNIOL-VILLARD result = -2; 2512731b9a8SJean-Christophe PLAGNIOL-VILLARD } else 2522731b9a8SJean-Christophe PLAGNIOL-VILLARD result = 0; 2532731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2542731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 2552731b9a8SJean-Christophe PLAGNIOL-VILLARD } 256c3a012ceSBryan Wu 257c3a012ceSBryan Wu /* Check the timeout */ 258c3a012ceSBryan Wu if (--timeout) 259c3a012ceSBryan Wu udelay(1); 260c3a012ceSBryan Wu else { 261c3a012ceSBryan Wu dev->status = USB_ST_CRC_ERR; 262c3a012ceSBryan Wu result = -1; 263c3a012ceSBryan Wu break; 2642731b9a8SJean-Christophe PLAGNIOL-VILLARD } 265c3a012ceSBryan Wu } 266c3a012ceSBryan Wu 2672731b9a8SJean-Christophe PLAGNIOL-VILLARD return result; 2682731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2692731b9a8SJean-Christophe PLAGNIOL-VILLARD 2702731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 2712731b9a8SJean-Christophe PLAGNIOL-VILLARD * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error. 2722731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 2732731b9a8SJean-Christophe PLAGNIOL-VILLARD static u8 wait_until_txep_ready(struct usb_device *dev, u8 ep) 2742731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2752731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 276c3a012ceSBryan Wu int timeout = CONFIG_MUSB_TIMEOUT; 2772731b9a8SJean-Christophe PLAGNIOL-VILLARD 2782731b9a8SJean-Christophe PLAGNIOL-VILLARD do { 2792731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(ep, 1)) { 2802731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED; 2812731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 2822731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2832731b9a8SJean-Christophe PLAGNIOL-VILLARD 2842731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 2852731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_TXCSR_H_ERROR) { 2862731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_CRC_ERR; 2872731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 2882731b9a8SJean-Christophe PLAGNIOL-VILLARD } 289c3a012ceSBryan Wu 290c3a012ceSBryan Wu /* Check the timeout */ 291c3a012ceSBryan Wu if (--timeout) 292c3a012ceSBryan Wu udelay(1); 293c3a012ceSBryan Wu else { 294c3a012ceSBryan Wu dev->status = USB_ST_CRC_ERR; 295c3a012ceSBryan Wu return -1; 296c3a012ceSBryan Wu } 297c3a012ceSBryan Wu 2982731b9a8SJean-Christophe PLAGNIOL-VILLARD } while (csr & MUSB_TXCSR_TXPKTRDY); 2992731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1; 3002731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3012731b9a8SJean-Christophe PLAGNIOL-VILLARD 3022731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 3032731b9a8SJean-Christophe PLAGNIOL-VILLARD * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error. 3042731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 3052731b9a8SJean-Christophe PLAGNIOL-VILLARD static u8 wait_until_rxep_ready(struct usb_device *dev, u8 ep) 3062731b9a8SJean-Christophe PLAGNIOL-VILLARD { 3072731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 308c3a012ceSBryan Wu int timeout = CONFIG_MUSB_TIMEOUT; 3092731b9a8SJean-Christophe PLAGNIOL-VILLARD 3102731b9a8SJean-Christophe PLAGNIOL-VILLARD do { 3112731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(ep, 0)) { 3122731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED; 3132731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 3142731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3152731b9a8SJean-Christophe PLAGNIOL-VILLARD 3162731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 3172731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_RXCSR_H_ERROR) { 3182731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_CRC_ERR; 3192731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 3202731b9a8SJean-Christophe PLAGNIOL-VILLARD } 321c3a012ceSBryan Wu 322c3a012ceSBryan Wu /* Check the timeout */ 323c3a012ceSBryan Wu if (--timeout) 324c3a012ceSBryan Wu udelay(1); 325c3a012ceSBryan Wu else { 326c3a012ceSBryan Wu dev->status = USB_ST_CRC_ERR; 327c3a012ceSBryan Wu return -1; 328c3a012ceSBryan Wu } 329c3a012ceSBryan Wu 3302731b9a8SJean-Christophe PLAGNIOL-VILLARD } while (!(csr & MUSB_RXCSR_RXPKTRDY)); 3312731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1; 3322731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3332731b9a8SJean-Christophe PLAGNIOL-VILLARD 3342731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 3352731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function performs the setup phase of the control transfer 3362731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 3372731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup) 3382731b9a8SJean-Christophe PLAGNIOL-VILLARD { 3392731b9a8SJean-Christophe PLAGNIOL-VILLARD int result; 3402731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 3412731b9a8SJean-Christophe PLAGNIOL-VILLARD 3422731b9a8SJean-Christophe PLAGNIOL-VILLARD /* write the control request to ep0 fifo */ 3432731b9a8SJean-Christophe PLAGNIOL-VILLARD write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup); 3442731b9a8SJean-Christophe PLAGNIOL-VILLARD 3452731b9a8SJean-Christophe PLAGNIOL-VILLARD /* enable transfer of setup packet */ 3462731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 3472731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT); 3482731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 3492731b9a8SJean-Christophe PLAGNIOL-VILLARD 3502731b9a8SJean-Christophe PLAGNIOL-VILLARD /* wait until the setup packet is transmitted */ 3512731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); 3522731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = 0; 3532731b9a8SJean-Christophe PLAGNIOL-VILLARD return result; 3542731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3552731b9a8SJean-Christophe PLAGNIOL-VILLARD 3562731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 3572731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles the control transfer in data phase 3582731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 3592731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer) 3602731b9a8SJean-Christophe PLAGNIOL-VILLARD { 3612731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 3622731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 rxlen = 0; 3632731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0; 3642731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 maxpktsize = (1 << dev->maxpacketsize) * 8; 3652731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 *rxbuff = (u8 *)buffer; 3662731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 rxedlength; 3672731b9a8SJean-Christophe PLAGNIOL-VILLARD int result; 3682731b9a8SJean-Christophe PLAGNIOL-VILLARD 3692731b9a8SJean-Christophe PLAGNIOL-VILLARD while (rxlen < len) { 3702731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Determine the next read length */ 3712731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen); 3722731b9a8SJean-Christophe PLAGNIOL-VILLARD 3732731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the ReqPkt bit */ 3742731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 3752731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr); 3762731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY); 3772731b9a8SJean-Christophe PLAGNIOL-VILLARD if (result < 0) 3782731b9a8SJean-Christophe PLAGNIOL-VILLARD return result; 3792731b9a8SJean-Christophe PLAGNIOL-VILLARD 3802731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Actual number of bytes received by usb */ 3812731b9a8SJean-Christophe PLAGNIOL-VILLARD rxedlength = readb(&musbr->rxcount); 3822731b9a8SJean-Christophe PLAGNIOL-VILLARD 3832731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Read the data from the RxFIFO */ 3842731b9a8SJean-Christophe PLAGNIOL-VILLARD read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]); 3852731b9a8SJean-Christophe PLAGNIOL-VILLARD 3862731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Clear the RxPktRdy Bit */ 3872731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 3882731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_CSR0_RXPKTRDY; 3892731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 3902731b9a8SJean-Christophe PLAGNIOL-VILLARD 3912731b9a8SJean-Christophe PLAGNIOL-VILLARD /* short packet? */ 3922731b9a8SJean-Christophe PLAGNIOL-VILLARD if (rxedlength != nextlen) { 3932731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len += rxedlength; 3942731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 3952731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3962731b9a8SJean-Christophe PLAGNIOL-VILLARD rxlen += nextlen; 3972731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = rxlen; 3982731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3992731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 4002731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4012731b9a8SJean-Christophe PLAGNIOL-VILLARD 4022731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 4032731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles the control transfer out data phase 4042731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4052731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer) 4062731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4072731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 4082731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 txlen = 0; 4092731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0; 4102731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 maxpktsize = (1 << dev->maxpacketsize) * 8; 4112731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 *txbuff = (u8 *)buffer; 4122731b9a8SJean-Christophe PLAGNIOL-VILLARD int result = 0; 4132731b9a8SJean-Christophe PLAGNIOL-VILLARD 4142731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) { 4152731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Determine the next write length */ 4162731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen); 4172731b9a8SJean-Christophe PLAGNIOL-VILLARD 4182731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Load the data to send in FIFO */ 4192731b9a8SJean-Christophe PLAGNIOL-VILLARD write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]); 4202731b9a8SJean-Christophe PLAGNIOL-VILLARD 4212731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set TXPKTRDY bit */ 4222731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 4232731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr | MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY, 4242731b9a8SJean-Christophe PLAGNIOL-VILLARD &musbr->txcsr); 4252731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); 4262731b9a8SJean-Christophe PLAGNIOL-VILLARD if (result < 0) 4272731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 4282731b9a8SJean-Christophe PLAGNIOL-VILLARD 4292731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen; 4302731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen; 4312731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4322731b9a8SJean-Christophe PLAGNIOL-VILLARD return result; 4332731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4342731b9a8SJean-Christophe PLAGNIOL-VILLARD 4352731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 4362731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles the control transfer out status phase 4372731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4382731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_out_status_phase(struct usb_device *dev) 4392731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4402731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 4412731b9a8SJean-Christophe PLAGNIOL-VILLARD int result; 4422731b9a8SJean-Christophe PLAGNIOL-VILLARD 4432731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the StatusPkt bit */ 4442731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 4452731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= (MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY | 4462731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_CSR0_H_STATUSPKT); 4472731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 4482731b9a8SJean-Christophe PLAGNIOL-VILLARD 4492731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until TXPKTRDY bit is cleared */ 4502731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); 4512731b9a8SJean-Christophe PLAGNIOL-VILLARD return result; 4522731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4532731b9a8SJean-Christophe PLAGNIOL-VILLARD 4542731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 4552731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles the control transfer in status phase 4562731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4572731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_in_status_phase(struct usb_device *dev) 4582731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4592731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 4602731b9a8SJean-Christophe PLAGNIOL-VILLARD int result; 4612731b9a8SJean-Christophe PLAGNIOL-VILLARD 4622731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the StatusPkt bit and ReqPkt bit */ 4632731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = MUSB_CSR0_H_DIS_PING | MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT; 4642731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 4652731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT); 4662731b9a8SJean-Christophe PLAGNIOL-VILLARD 4672731b9a8SJean-Christophe PLAGNIOL-VILLARD /* clear StatusPkt bit and RxPktRdy bit */ 4682731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 4692731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT); 4702731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr); 4712731b9a8SJean-Christophe PLAGNIOL-VILLARD return result; 4722731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4732731b9a8SJean-Christophe PLAGNIOL-VILLARD 4742731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 4752731b9a8SJean-Christophe PLAGNIOL-VILLARD * determines the speed of the device (High/Full/Slow) 4762731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4772731b9a8SJean-Christophe PLAGNIOL-VILLARD static u8 get_dev_speed(struct usb_device *dev) 4782731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4792731b9a8SJean-Christophe PLAGNIOL-VILLARD return (dev->speed & USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH : 4802731b9a8SJean-Christophe PLAGNIOL-VILLARD ((dev->speed & USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW : 4812731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_TYPE_SPEED_FULL); 4822731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4832731b9a8SJean-Christophe PLAGNIOL-VILLARD 4842731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 4852731b9a8SJean-Christophe PLAGNIOL-VILLARD * configure the hub address and the port address. 4862731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4872731b9a8SJean-Christophe PLAGNIOL-VILLARD static void config_hub_port(struct usb_device *dev, u8 ep) 4882731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4892731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 chid; 4902731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 hub; 4912731b9a8SJean-Christophe PLAGNIOL-VILLARD 4922731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Find out the nearest parent which is high speed */ 4932731b9a8SJean-Christophe PLAGNIOL-VILLARD while (dev->parent->parent != NULL) 4942731b9a8SJean-Christophe PLAGNIOL-VILLARD if (get_dev_speed(dev->parent) != MUSB_TYPE_SPEED_HIGH) 4952731b9a8SJean-Christophe PLAGNIOL-VILLARD dev = dev->parent; 4962731b9a8SJean-Christophe PLAGNIOL-VILLARD else 4972731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 4982731b9a8SJean-Christophe PLAGNIOL-VILLARD 4992731b9a8SJean-Christophe PLAGNIOL-VILLARD /* determine the port address at that hub */ 5002731b9a8SJean-Christophe PLAGNIOL-VILLARD hub = dev->parent->devnum; 5012731b9a8SJean-Christophe PLAGNIOL-VILLARD for (chid = 0; chid < USB_MAXCHILDREN; chid++) 5022731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dev->parent->children[chid] == dev) 5032731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 5042731b9a8SJean-Christophe PLAGNIOL-VILLARD 5058868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 5062731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port address */ 5072731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(hub, &musbr->tar[ep].txhubaddr); 5082731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb((chid + 1), &musbr->tar[ep].txhubport); 5092731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(hub, &musbr->tar[ep].rxhubaddr); 5102731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb((chid + 1), &musbr->tar[ep].rxhubport); 5118868fd44SBryan Wu #endif 5122731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5132731b9a8SJean-Christophe PLAGNIOL-VILLARD 514*321790f6SBryan Wu #ifdef MUSB_NO_MULTIPOINT 515*321790f6SBryan Wu 516*321790f6SBryan Wu static void musb_port_reset(int do_reset) 517*321790f6SBryan Wu { 518*321790f6SBryan Wu u8 power = readb(&musbr->power); 519*321790f6SBryan Wu 520*321790f6SBryan Wu if (do_reset) { 521*321790f6SBryan Wu power &= 0xf0; 522*321790f6SBryan Wu writeb(power | MUSB_POWER_RESET, &musbr->power); 523*321790f6SBryan Wu port_status |= USB_PORT_STAT_RESET; 524*321790f6SBryan Wu port_status &= ~USB_PORT_STAT_ENABLE; 525*321790f6SBryan Wu udelay(30000); 526*321790f6SBryan Wu } else { 527*321790f6SBryan Wu writeb(power & ~MUSB_POWER_RESET, &musbr->power); 528*321790f6SBryan Wu 529*321790f6SBryan Wu power = readb(&musbr->power); 530*321790f6SBryan Wu if (power & MUSB_POWER_HSMODE) 531*321790f6SBryan Wu port_status |= USB_PORT_STAT_HIGH_SPEED; 532*321790f6SBryan Wu 533*321790f6SBryan Wu port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16)); 534*321790f6SBryan Wu port_status |= USB_PORT_STAT_ENABLE 535*321790f6SBryan Wu | (USB_PORT_STAT_C_RESET << 16) 536*321790f6SBryan Wu | (USB_PORT_STAT_C_ENABLE << 16); 537*321790f6SBryan Wu } 538*321790f6SBryan Wu } 539*321790f6SBryan Wu 540*321790f6SBryan Wu /* 541*321790f6SBryan Wu * root hub control 542*321790f6SBryan Wu */ 543*321790f6SBryan Wu static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe, 544*321790f6SBryan Wu void *buffer, int transfer_len, 545*321790f6SBryan Wu struct devrequest *cmd) 546*321790f6SBryan Wu { 547*321790f6SBryan Wu int leni = transfer_len; 548*321790f6SBryan Wu int len = 0; 549*321790f6SBryan Wu int stat = 0; 550*321790f6SBryan Wu u32 datab[4]; 551*321790f6SBryan Wu u8 *data_buf = (u8 *) datab; 552*321790f6SBryan Wu u16 bmRType_bReq; 553*321790f6SBryan Wu u16 wValue; 554*321790f6SBryan Wu u16 wIndex; 555*321790f6SBryan Wu u16 wLength; 556*321790f6SBryan Wu u16 int_usb; 557*321790f6SBryan Wu 558*321790f6SBryan Wu if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { 559*321790f6SBryan Wu debug("Root-Hub submit IRQ: NOT implemented\n"); 560*321790f6SBryan Wu return 0; 561*321790f6SBryan Wu } 562*321790f6SBryan Wu 563*321790f6SBryan Wu bmRType_bReq = cmd->requesttype | (cmd->request << 8); 564*321790f6SBryan Wu wValue = swap_16(cmd->value); 565*321790f6SBryan Wu wIndex = swap_16(cmd->index); 566*321790f6SBryan Wu wLength = swap_16(cmd->length); 567*321790f6SBryan Wu 568*321790f6SBryan Wu debug("--- HUB ----------------------------------------\n"); 569*321790f6SBryan Wu debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n", 570*321790f6SBryan Wu bmRType_bReq, wValue, wIndex, wLength); 571*321790f6SBryan Wu debug("------------------------------------------------\n"); 572*321790f6SBryan Wu 573*321790f6SBryan Wu switch (bmRType_bReq) { 574*321790f6SBryan Wu case RH_GET_STATUS: 575*321790f6SBryan Wu debug("RH_GET_STATUS\n"); 576*321790f6SBryan Wu 577*321790f6SBryan Wu *(__u16 *) data_buf = swap_16(1); 578*321790f6SBryan Wu len = 2; 579*321790f6SBryan Wu break; 580*321790f6SBryan Wu 581*321790f6SBryan Wu case RH_GET_STATUS | RH_INTERFACE: 582*321790f6SBryan Wu debug("RH_GET_STATUS | RH_INTERFACE\n"); 583*321790f6SBryan Wu 584*321790f6SBryan Wu *(__u16 *) data_buf = swap_16(0); 585*321790f6SBryan Wu len = 2; 586*321790f6SBryan Wu break; 587*321790f6SBryan Wu 588*321790f6SBryan Wu case RH_GET_STATUS | RH_ENDPOINT: 589*321790f6SBryan Wu debug("RH_GET_STATUS | RH_ENDPOINT\n"); 590*321790f6SBryan Wu 591*321790f6SBryan Wu *(__u16 *) data_buf = swap_16(0); 592*321790f6SBryan Wu len = 2; 593*321790f6SBryan Wu break; 594*321790f6SBryan Wu 595*321790f6SBryan Wu case RH_GET_STATUS | RH_CLASS: 596*321790f6SBryan Wu debug("RH_GET_STATUS | RH_CLASS\n"); 597*321790f6SBryan Wu 598*321790f6SBryan Wu *(__u32 *) data_buf = swap_32(0); 599*321790f6SBryan Wu len = 4; 600*321790f6SBryan Wu break; 601*321790f6SBryan Wu 602*321790f6SBryan Wu case RH_GET_STATUS | RH_OTHER | RH_CLASS: 603*321790f6SBryan Wu debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n"); 604*321790f6SBryan Wu 605*321790f6SBryan Wu int_usb = readw(&musbr->intrusb); 606*321790f6SBryan Wu if (int_usb & MUSB_INTR_CONNECT) { 607*321790f6SBryan Wu port_status |= USB_PORT_STAT_CONNECTION 608*321790f6SBryan Wu | (USB_PORT_STAT_C_CONNECTION << 16); 609*321790f6SBryan Wu port_status |= USB_PORT_STAT_HIGH_SPEED 610*321790f6SBryan Wu | USB_PORT_STAT_ENABLE; 611*321790f6SBryan Wu } 612*321790f6SBryan Wu 613*321790f6SBryan Wu if (port_status & USB_PORT_STAT_RESET) 614*321790f6SBryan Wu musb_port_reset(0); 615*321790f6SBryan Wu 616*321790f6SBryan Wu *(__u32 *) data_buf = swap_32(port_status); 617*321790f6SBryan Wu len = 4; 618*321790f6SBryan Wu break; 619*321790f6SBryan Wu 620*321790f6SBryan Wu case RH_CLEAR_FEATURE | RH_ENDPOINT: 621*321790f6SBryan Wu debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n"); 622*321790f6SBryan Wu 623*321790f6SBryan Wu switch (wValue) { 624*321790f6SBryan Wu case RH_ENDPOINT_STALL: 625*321790f6SBryan Wu debug("C_HUB_ENDPOINT_STALL\n"); 626*321790f6SBryan Wu len = 0; 627*321790f6SBryan Wu break; 628*321790f6SBryan Wu } 629*321790f6SBryan Wu port_status &= ~(1 << wValue); 630*321790f6SBryan Wu break; 631*321790f6SBryan Wu 632*321790f6SBryan Wu case RH_CLEAR_FEATURE | RH_CLASS: 633*321790f6SBryan Wu debug("RH_CLEAR_FEATURE | RH_CLASS\n"); 634*321790f6SBryan Wu 635*321790f6SBryan Wu switch (wValue) { 636*321790f6SBryan Wu case RH_C_HUB_LOCAL_POWER: 637*321790f6SBryan Wu debug("C_HUB_LOCAL_POWER\n"); 638*321790f6SBryan Wu len = 0; 639*321790f6SBryan Wu break; 640*321790f6SBryan Wu 641*321790f6SBryan Wu case RH_C_HUB_OVER_CURRENT: 642*321790f6SBryan Wu debug("C_HUB_OVER_CURRENT\n"); 643*321790f6SBryan Wu len = 0; 644*321790f6SBryan Wu break; 645*321790f6SBryan Wu } 646*321790f6SBryan Wu port_status &= ~(1 << wValue); 647*321790f6SBryan Wu break; 648*321790f6SBryan Wu 649*321790f6SBryan Wu case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: 650*321790f6SBryan Wu debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n"); 651*321790f6SBryan Wu 652*321790f6SBryan Wu switch (wValue) { 653*321790f6SBryan Wu case RH_PORT_ENABLE: 654*321790f6SBryan Wu len = 0; 655*321790f6SBryan Wu break; 656*321790f6SBryan Wu 657*321790f6SBryan Wu case RH_PORT_SUSPEND: 658*321790f6SBryan Wu len = 0; 659*321790f6SBryan Wu break; 660*321790f6SBryan Wu 661*321790f6SBryan Wu case RH_PORT_POWER: 662*321790f6SBryan Wu len = 0; 663*321790f6SBryan Wu break; 664*321790f6SBryan Wu 665*321790f6SBryan Wu case RH_C_PORT_CONNECTION: 666*321790f6SBryan Wu len = 0; 667*321790f6SBryan Wu break; 668*321790f6SBryan Wu 669*321790f6SBryan Wu case RH_C_PORT_ENABLE: 670*321790f6SBryan Wu len = 0; 671*321790f6SBryan Wu break; 672*321790f6SBryan Wu 673*321790f6SBryan Wu case RH_C_PORT_SUSPEND: 674*321790f6SBryan Wu len = 0; 675*321790f6SBryan Wu break; 676*321790f6SBryan Wu 677*321790f6SBryan Wu case RH_C_PORT_OVER_CURRENT: 678*321790f6SBryan Wu len = 0; 679*321790f6SBryan Wu break; 680*321790f6SBryan Wu 681*321790f6SBryan Wu case RH_C_PORT_RESET: 682*321790f6SBryan Wu len = 0; 683*321790f6SBryan Wu break; 684*321790f6SBryan Wu 685*321790f6SBryan Wu default: 686*321790f6SBryan Wu debug("invalid wValue\n"); 687*321790f6SBryan Wu stat = USB_ST_STALLED; 688*321790f6SBryan Wu } 689*321790f6SBryan Wu 690*321790f6SBryan Wu port_status &= ~(1 << wValue); 691*321790f6SBryan Wu break; 692*321790f6SBryan Wu 693*321790f6SBryan Wu case RH_SET_FEATURE | RH_OTHER | RH_CLASS: 694*321790f6SBryan Wu debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n"); 695*321790f6SBryan Wu 696*321790f6SBryan Wu switch (wValue) { 697*321790f6SBryan Wu case RH_PORT_SUSPEND: 698*321790f6SBryan Wu len = 0; 699*321790f6SBryan Wu break; 700*321790f6SBryan Wu 701*321790f6SBryan Wu case RH_PORT_RESET: 702*321790f6SBryan Wu musb_port_reset(1); 703*321790f6SBryan Wu len = 0; 704*321790f6SBryan Wu break; 705*321790f6SBryan Wu 706*321790f6SBryan Wu case RH_PORT_POWER: 707*321790f6SBryan Wu len = 0; 708*321790f6SBryan Wu break; 709*321790f6SBryan Wu 710*321790f6SBryan Wu case RH_PORT_ENABLE: 711*321790f6SBryan Wu len = 0; 712*321790f6SBryan Wu break; 713*321790f6SBryan Wu 714*321790f6SBryan Wu default: 715*321790f6SBryan Wu debug("invalid wValue\n"); 716*321790f6SBryan Wu stat = USB_ST_STALLED; 717*321790f6SBryan Wu } 718*321790f6SBryan Wu 719*321790f6SBryan Wu port_status |= 1 << wValue; 720*321790f6SBryan Wu break; 721*321790f6SBryan Wu 722*321790f6SBryan Wu case RH_SET_ADDRESS: 723*321790f6SBryan Wu debug("RH_SET_ADDRESS\n"); 724*321790f6SBryan Wu 725*321790f6SBryan Wu rh_devnum = wValue; 726*321790f6SBryan Wu len = 0; 727*321790f6SBryan Wu break; 728*321790f6SBryan Wu 729*321790f6SBryan Wu case RH_GET_DESCRIPTOR: 730*321790f6SBryan Wu debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength); 731*321790f6SBryan Wu 732*321790f6SBryan Wu switch (wValue) { 733*321790f6SBryan Wu case (USB_DT_DEVICE << 8): /* device descriptor */ 734*321790f6SBryan Wu len = min_t(unsigned int, 735*321790f6SBryan Wu leni, min_t(unsigned int, 736*321790f6SBryan Wu sizeof(root_hub_dev_des), 737*321790f6SBryan Wu wLength)); 738*321790f6SBryan Wu data_buf = root_hub_dev_des; 739*321790f6SBryan Wu break; 740*321790f6SBryan Wu 741*321790f6SBryan Wu case (USB_DT_CONFIG << 8): /* configuration descriptor */ 742*321790f6SBryan Wu len = min_t(unsigned int, 743*321790f6SBryan Wu leni, min_t(unsigned int, 744*321790f6SBryan Wu sizeof(root_hub_config_des), 745*321790f6SBryan Wu wLength)); 746*321790f6SBryan Wu data_buf = root_hub_config_des; 747*321790f6SBryan Wu break; 748*321790f6SBryan Wu 749*321790f6SBryan Wu case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */ 750*321790f6SBryan Wu len = min_t(unsigned int, 751*321790f6SBryan Wu leni, min_t(unsigned int, 752*321790f6SBryan Wu sizeof(root_hub_str_index0), 753*321790f6SBryan Wu wLength)); 754*321790f6SBryan Wu data_buf = root_hub_str_index0; 755*321790f6SBryan Wu break; 756*321790f6SBryan Wu 757*321790f6SBryan Wu case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */ 758*321790f6SBryan Wu len = min_t(unsigned int, 759*321790f6SBryan Wu leni, min_t(unsigned int, 760*321790f6SBryan Wu sizeof(root_hub_str_index1), 761*321790f6SBryan Wu wLength)); 762*321790f6SBryan Wu data_buf = root_hub_str_index1; 763*321790f6SBryan Wu break; 764*321790f6SBryan Wu 765*321790f6SBryan Wu default: 766*321790f6SBryan Wu debug("invalid wValue\n"); 767*321790f6SBryan Wu stat = USB_ST_STALLED; 768*321790f6SBryan Wu } 769*321790f6SBryan Wu 770*321790f6SBryan Wu break; 771*321790f6SBryan Wu 772*321790f6SBryan Wu case RH_GET_DESCRIPTOR | RH_CLASS: 773*321790f6SBryan Wu debug("RH_GET_DESCRIPTOR | RH_CLASS\n"); 774*321790f6SBryan Wu 775*321790f6SBryan Wu data_buf[0] = 0x09; /* min length; */ 776*321790f6SBryan Wu data_buf[1] = 0x29; 777*321790f6SBryan Wu data_buf[2] = 0x1; /* 1 port */ 778*321790f6SBryan Wu data_buf[3] = 0x01; /* per-port power switching */ 779*321790f6SBryan Wu data_buf[3] |= 0x10; /* no overcurrent reporting */ 780*321790f6SBryan Wu 781*321790f6SBryan Wu /* Corresponds to data_buf[4-7] */ 782*321790f6SBryan Wu data_buf[4] = 0; 783*321790f6SBryan Wu data_buf[5] = 5; 784*321790f6SBryan Wu data_buf[6] = 0; 785*321790f6SBryan Wu data_buf[7] = 0x02; 786*321790f6SBryan Wu data_buf[8] = 0xff; 787*321790f6SBryan Wu 788*321790f6SBryan Wu len = min_t(unsigned int, leni, 789*321790f6SBryan Wu min_t(unsigned int, data_buf[0], wLength)); 790*321790f6SBryan Wu break; 791*321790f6SBryan Wu 792*321790f6SBryan Wu case RH_GET_CONFIGURATION: 793*321790f6SBryan Wu debug("RH_GET_CONFIGURATION\n"); 794*321790f6SBryan Wu 795*321790f6SBryan Wu *(__u8 *) data_buf = 0x01; 796*321790f6SBryan Wu len = 1; 797*321790f6SBryan Wu break; 798*321790f6SBryan Wu 799*321790f6SBryan Wu case RH_SET_CONFIGURATION: 800*321790f6SBryan Wu debug("RH_SET_CONFIGURATION\n"); 801*321790f6SBryan Wu 802*321790f6SBryan Wu len = 0; 803*321790f6SBryan Wu break; 804*321790f6SBryan Wu 805*321790f6SBryan Wu default: 806*321790f6SBryan Wu debug("*** *** *** unsupported root hub command *** *** ***\n"); 807*321790f6SBryan Wu stat = USB_ST_STALLED; 808*321790f6SBryan Wu } 809*321790f6SBryan Wu 810*321790f6SBryan Wu len = min_t(int, len, leni); 811*321790f6SBryan Wu if (buffer != data_buf) 812*321790f6SBryan Wu memcpy(buffer, data_buf, len); 813*321790f6SBryan Wu 814*321790f6SBryan Wu dev->act_len = len; 815*321790f6SBryan Wu dev->status = stat; 816*321790f6SBryan Wu debug("dev act_len %d, status %d\n", dev->act_len, dev->status); 817*321790f6SBryan Wu 818*321790f6SBryan Wu return stat; 819*321790f6SBryan Wu } 820*321790f6SBryan Wu 821*321790f6SBryan Wu static void musb_rh_init(void) 822*321790f6SBryan Wu { 823*321790f6SBryan Wu rh_devnum = 0; 824*321790f6SBryan Wu port_status = 0; 825*321790f6SBryan Wu } 826*321790f6SBryan Wu 827*321790f6SBryan Wu #else 828*321790f6SBryan Wu 829*321790f6SBryan Wu static void musb_rh_init(void) {} 830*321790f6SBryan Wu 831*321790f6SBryan Wu #endif 832*321790f6SBryan Wu 8332731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 8342731b9a8SJean-Christophe PLAGNIOL-VILLARD * do a control transfer 8352731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 8362731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 8372731b9a8SJean-Christophe PLAGNIOL-VILLARD int len, struct devrequest *setup) 8382731b9a8SJean-Christophe PLAGNIOL-VILLARD { 8392731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe); 8402731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 8412731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 devspeed; 8422731b9a8SJean-Christophe PLAGNIOL-VILLARD 843*321790f6SBryan Wu #ifdef MUSB_NO_MULTIPOINT 844*321790f6SBryan Wu /* Control message is for the HUB? */ 845*321790f6SBryan Wu if (devnum == rh_devnum) 846*321790f6SBryan Wu return musb_submit_rh_msg(dev, pipe, buffer, len, setup); 847*321790f6SBryan Wu #endif 848*321790f6SBryan Wu 8492731b9a8SJean-Christophe PLAGNIOL-VILLARD /* select control endpoint */ 8502731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(MUSB_CONTROL_EP, &musbr->index); 8512731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 8522731b9a8SJean-Christophe PLAGNIOL-VILLARD 8538868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 8542731b9a8SJean-Christophe PLAGNIOL-VILLARD /* target addr and (for multipoint) hub addr/port */ 8552731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr); 8562731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr); 8578868fd44SBryan Wu #endif 8582731b9a8SJean-Christophe PLAGNIOL-VILLARD 8592731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port number as required */ 8602731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = get_dev_speed(dev); 8612731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((musb_ishighspeed()) && (dev->parent != NULL) && 8622731b9a8SJean-Christophe PLAGNIOL-VILLARD (devspeed != MUSB_TYPE_SPEED_HIGH)) { 8632731b9a8SJean-Christophe PLAGNIOL-VILLARD config_hub_port(dev, MUSB_CONTROL_EP); 8642731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devspeed << 6, &musbr->txtype); 8652731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 8662731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(musb_cfg.musb_speed << 6, &musbr->txtype); 8678868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 8682731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr); 8692731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport); 8702731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr); 8712731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport); 8728868fd44SBryan Wu #endif 8732731b9a8SJean-Christophe PLAGNIOL-VILLARD } 8742731b9a8SJean-Christophe PLAGNIOL-VILLARD 8752731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Control transfer setup phase */ 8762731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_setup_phase(dev, setup) < 0) 8772731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 8782731b9a8SJean-Christophe PLAGNIOL-VILLARD 8792731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (setup->request) { 8802731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_DESCRIPTOR: 8812731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_CONFIGURATION: 8822731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_INTERFACE: 8832731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_STATUS: 8842731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_MSC_BBB_GET_MAX_LUN: 8852731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer in-data-phase */ 8862731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_in_data_phase(dev, len, buffer) < 0) 8872731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 8882731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer out-status-phase */ 8892731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_out_status_phase(dev) < 0) 8902731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 8912731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 8922731b9a8SJean-Christophe PLAGNIOL-VILLARD 8932731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_ADDRESS: 8942731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_CONFIGURATION: 8952731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_FEATURE: 8962731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_INTERFACE: 8972731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_CLEAR_FEATURE: 8982731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_MSC_BBB_RESET: 8992731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer in status phase */ 9002731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_in_status_phase(dev) < 0) 9012731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 9022731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 9032731b9a8SJean-Christophe PLAGNIOL-VILLARD 9042731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_DESCRIPTOR: 9052731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer out data phase */ 9062731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_out_data_phase(dev, len, buffer) < 0) 9072731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 9082731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer in status phase */ 9092731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_in_status_phase(dev) < 0) 9102731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 9112731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 9122731b9a8SJean-Christophe PLAGNIOL-VILLARD 9132731b9a8SJean-Christophe PLAGNIOL-VILLARD default: 9142731b9a8SJean-Christophe PLAGNIOL-VILLARD /* unhandled control transfer */ 9152731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 9162731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9172731b9a8SJean-Christophe PLAGNIOL-VILLARD 9182731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 9192731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = len; 9202731b9a8SJean-Christophe PLAGNIOL-VILLARD return len; 9212731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9222731b9a8SJean-Christophe PLAGNIOL-VILLARD 9232731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 9242731b9a8SJean-Christophe PLAGNIOL-VILLARD * do a bulk transfer 9252731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 9262731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, 9272731b9a8SJean-Christophe PLAGNIOL-VILLARD void *buffer, int len) 9282731b9a8SJean-Christophe PLAGNIOL-VILLARD { 9292731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_out = usb_pipeout(pipe); 9302731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe); 9318868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 9322731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe); 9338868fd44SBryan Wu #endif 9342731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 type; 9352731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 9362731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 txlen = 0; 9372731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0; 9382731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 devspeed; 9392731b9a8SJean-Christophe PLAGNIOL-VILLARD 9402731b9a8SJean-Christophe PLAGNIOL-VILLARD /* select bulk endpoint */ 9412731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(MUSB_BULK_EP, &musbr->index); 9422731b9a8SJean-Christophe PLAGNIOL-VILLARD 9438868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 9442731b9a8SJean-Christophe PLAGNIOL-VILLARD /* write the address of the device */ 9452731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) 9462731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr); 9472731b9a8SJean-Christophe PLAGNIOL-VILLARD else 9482731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr); 9498868fd44SBryan Wu #endif 9502731b9a8SJean-Christophe PLAGNIOL-VILLARD 9512731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port number as required */ 9522731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = get_dev_speed(dev); 9532731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((musb_ishighspeed()) && (dev->parent != NULL) && 9542731b9a8SJean-Christophe PLAGNIOL-VILLARD (devspeed != MUSB_TYPE_SPEED_HIGH)) { 9552731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 9562731b9a8SJean-Christophe PLAGNIOL-VILLARD * MUSB is in high speed and the destination device is full 9572731b9a8SJean-Christophe PLAGNIOL-VILLARD * speed device. So configure the hub address and port 9582731b9a8SJean-Christophe PLAGNIOL-VILLARD * address registers. 9592731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 9602731b9a8SJean-Christophe PLAGNIOL-VILLARD config_hub_port(dev, MUSB_BULK_EP); 9612731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 9628868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 9632731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) { 9642731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr); 9652731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport); 9662731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 9672731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr); 9682731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport); 9692731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9708868fd44SBryan Wu #endif 9712731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = musb_cfg.musb_speed; 9722731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9732731b9a8SJean-Christophe PLAGNIOL-VILLARD 9742731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */ 9752731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out); 9762731b9a8SJean-Christophe PLAGNIOL-VILLARD 9772731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) { /* bulk-out transfer */ 9782731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Program the TxType register */ 9792731b9a8SJean-Christophe PLAGNIOL-VILLARD type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | 9802731b9a8SJean-Christophe PLAGNIOL-VILLARD (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | 9812731b9a8SJean-Christophe PLAGNIOL-VILLARD (ep & MUSB_TYPE_REMOTE_END); 9822731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(type, &musbr->txtype); 9832731b9a8SJean-Christophe PLAGNIOL-VILLARD 9842731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write maximum packet size to the TxMaxp register */ 9852731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(dev->epmaxpacketout[ep], &musbr->txmaxp); 9862731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) { 9872731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ? 9882731b9a8SJean-Christophe PLAGNIOL-VILLARD (len-txlen) : dev->epmaxpacketout[ep]; 9892731b9a8SJean-Christophe PLAGNIOL-VILLARD 9902731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the data to the FIFO */ 9912731b9a8SJean-Christophe PLAGNIOL-VILLARD write_fifo(MUSB_BULK_EP, nextlen, 9922731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen)); 9932731b9a8SJean-Christophe PLAGNIOL-VILLARD 9942731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the TxPktRdy bit */ 9952731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 9962731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr); 9972731b9a8SJean-Christophe PLAGNIOL-VILLARD 9982731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the TxPktRdy bit is cleared */ 9992731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!wait_until_txep_ready(dev, MUSB_BULK_EP)) { 10002731b9a8SJean-Christophe PLAGNIOL-VILLARD readw(&musbr->txcsr); 10012731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 10022731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); 10032731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen; 10042731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 10052731b9a8SJean-Christophe PLAGNIOL-VILLARD } 10062731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen; 10072731b9a8SJean-Christophe PLAGNIOL-VILLARD } 10082731b9a8SJean-Christophe PLAGNIOL-VILLARD 10092731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */ 10102731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 10112731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 10122731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); 10132731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { /* bulk-in transfer */ 10142731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */ 10152731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out); 10162731b9a8SJean-Christophe PLAGNIOL-VILLARD 10172731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Program the RxType register */ 10182731b9a8SJean-Christophe PLAGNIOL-VILLARD type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | 10192731b9a8SJean-Christophe PLAGNIOL-VILLARD (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | 10202731b9a8SJean-Christophe PLAGNIOL-VILLARD (ep & MUSB_TYPE_REMOTE_END); 10212731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(type, &musbr->rxtype); 10222731b9a8SJean-Christophe PLAGNIOL-VILLARD 10232731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the maximum packet size to the RxMaxp register */ 10242731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); 10252731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) { 10262731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? 10272731b9a8SJean-Christophe PLAGNIOL-VILLARD (len-txlen) : dev->epmaxpacketin[ep]; 10282731b9a8SJean-Christophe PLAGNIOL-VILLARD 10292731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the ReqPkt bit */ 1030bc72a919SBryan Wu csr = readw(&musbr->rxcsr); 1031bc72a919SBryan Wu writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); 10322731b9a8SJean-Christophe PLAGNIOL-VILLARD 10332731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the RxPktRdy bit is set */ 10342731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!wait_until_rxep_ready(dev, MUSB_BULK_EP)) { 10352731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 10362731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 10372731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); 10382731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY; 10392731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 10402731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen; 10412731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 10422731b9a8SJean-Christophe PLAGNIOL-VILLARD } 10432731b9a8SJean-Christophe PLAGNIOL-VILLARD 10442731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Read the data from the FIFO */ 10452731b9a8SJean-Christophe PLAGNIOL-VILLARD read_fifo(MUSB_BULK_EP, nextlen, 10462731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen)); 10472731b9a8SJean-Christophe PLAGNIOL-VILLARD 10482731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Clear the RxPktRdy bit */ 10492731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 10502731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY; 10512731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 10522731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen; 10532731b9a8SJean-Christophe PLAGNIOL-VILLARD } 10542731b9a8SJean-Christophe PLAGNIOL-VILLARD 10552731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */ 10562731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 10572731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 10582731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); 10592731b9a8SJean-Christophe PLAGNIOL-VILLARD } 10602731b9a8SJean-Christophe PLAGNIOL-VILLARD 10612731b9a8SJean-Christophe PLAGNIOL-VILLARD /* bulk transfer is complete */ 10622731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 10632731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = len; 10642731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 10652731b9a8SJean-Christophe PLAGNIOL-VILLARD } 10662731b9a8SJean-Christophe PLAGNIOL-VILLARD 10672731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 10682731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function initializes the usb controller module. 10692731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 10702731b9a8SJean-Christophe PLAGNIOL-VILLARD int usb_lowlevel_init(void) 10712731b9a8SJean-Christophe PLAGNIOL-VILLARD { 10722731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 power; 10732731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 timeout; 10742731b9a8SJean-Christophe PLAGNIOL-VILLARD 1075*321790f6SBryan Wu musb_rh_init(); 1076*321790f6SBryan Wu 10772731b9a8SJean-Christophe PLAGNIOL-VILLARD if (musb_platform_init() == -1) 10782731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 10792731b9a8SJean-Christophe PLAGNIOL-VILLARD 10802731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Configure all the endpoint FIFO's and start usb controller */ 10812731b9a8SJean-Christophe PLAGNIOL-VILLARD musbr = musb_cfg.regs; 10822731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_configure_ep(&epinfo[0], 10832731b9a8SJean-Christophe PLAGNIOL-VILLARD sizeof(epinfo) / sizeof(struct musb_epinfo)); 10842731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_start(); 10852731b9a8SJean-Christophe PLAGNIOL-VILLARD 10862731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 10872731b9a8SJean-Christophe PLAGNIOL-VILLARD * Wait until musb is enabled in host mode with a timeout. There 10882731b9a8SJean-Christophe PLAGNIOL-VILLARD * should be a usb device connected. 10892731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 10902731b9a8SJean-Christophe PLAGNIOL-VILLARD timeout = musb_cfg.timeout; 10912731b9a8SJean-Christophe PLAGNIOL-VILLARD while (timeout--) 10922731b9a8SJean-Christophe PLAGNIOL-VILLARD if (readb(&musbr->devctl) & MUSB_DEVCTL_HM) 10932731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 10942731b9a8SJean-Christophe PLAGNIOL-VILLARD 10952731b9a8SJean-Christophe PLAGNIOL-VILLARD /* if musb core is not in host mode, then return */ 10962731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!timeout) 10972731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 10982731b9a8SJean-Christophe PLAGNIOL-VILLARD 10992731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start usb bus reset */ 11002731b9a8SJean-Christophe PLAGNIOL-VILLARD power = readb(&musbr->power); 11012731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(power | MUSB_POWER_RESET, &musbr->power); 11022731b9a8SJean-Christophe PLAGNIOL-VILLARD 11032731b9a8SJean-Christophe PLAGNIOL-VILLARD /* After initiating a usb reset, wait for about 20ms to 30ms */ 11042731b9a8SJean-Christophe PLAGNIOL-VILLARD udelay(30000); 11052731b9a8SJean-Christophe PLAGNIOL-VILLARD 11062731b9a8SJean-Christophe PLAGNIOL-VILLARD /* stop usb bus reset */ 11072731b9a8SJean-Christophe PLAGNIOL-VILLARD power = readb(&musbr->power); 11082731b9a8SJean-Christophe PLAGNIOL-VILLARD power &= ~MUSB_POWER_RESET; 11092731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(power, &musbr->power); 11102731b9a8SJean-Christophe PLAGNIOL-VILLARD 11112731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Determine if the connected device is a high/full/low speed device */ 11122731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ? 11132731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_TYPE_SPEED_HIGH : 11142731b9a8SJean-Christophe PLAGNIOL-VILLARD ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ? 11152731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW); 11162731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 11172731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11182731b9a8SJean-Christophe PLAGNIOL-VILLARD 11192731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 11202731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function stops the operation of the davinci usb module. 11212731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 11222731b9a8SJean-Christophe PLAGNIOL-VILLARD int usb_lowlevel_stop(void) 11232731b9a8SJean-Christophe PLAGNIOL-VILLARD { 11242731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Reset the USB module */ 11252731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_platform_deinit(); 11262731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->devctl); 11272731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 11282731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11292731b9a8SJean-Christophe PLAGNIOL-VILLARD 11302731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 11312731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function supports usb interrupt transfers. Currently, usb interrupt 11322731b9a8SJean-Christophe PLAGNIOL-VILLARD * transfers are not supported. 11332731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 11342731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_int_msg(struct usb_device *dev, unsigned long pipe, 11352731b9a8SJean-Christophe PLAGNIOL-VILLARD void *buffer, int len, int interval) 11362731b9a8SJean-Christophe PLAGNIOL-VILLARD { 11372731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_out = usb_pipeout(pipe); 11382731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe); 11398868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 11402731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe); 11418868fd44SBryan Wu #endif 11422731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 type; 11432731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 11442731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 txlen = 0; 11452731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0; 11462731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 devspeed; 11472731b9a8SJean-Christophe PLAGNIOL-VILLARD 11482731b9a8SJean-Christophe PLAGNIOL-VILLARD /* select interrupt endpoint */ 11492731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(MUSB_INTR_EP, &musbr->index); 11502731b9a8SJean-Christophe PLAGNIOL-VILLARD 11518868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 11522731b9a8SJean-Christophe PLAGNIOL-VILLARD /* write the address of the device */ 11532731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) 11542731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr); 11552731b9a8SJean-Christophe PLAGNIOL-VILLARD else 11562731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr); 11578868fd44SBryan Wu #endif 11582731b9a8SJean-Christophe PLAGNIOL-VILLARD 11592731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port number as required */ 11602731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = get_dev_speed(dev); 11612731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((musb_ishighspeed()) && (dev->parent != NULL) && 11622731b9a8SJean-Christophe PLAGNIOL-VILLARD (devspeed != MUSB_TYPE_SPEED_HIGH)) { 11632731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 11642731b9a8SJean-Christophe PLAGNIOL-VILLARD * MUSB is in high speed and the destination device is full 11652731b9a8SJean-Christophe PLAGNIOL-VILLARD * speed device. So configure the hub address and port 11662731b9a8SJean-Christophe PLAGNIOL-VILLARD * address registers. 11672731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 11682731b9a8SJean-Christophe PLAGNIOL-VILLARD config_hub_port(dev, MUSB_INTR_EP); 11692731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 11708868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 11712731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) { 11722731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr); 11732731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport); 11742731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 11752731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr); 11762731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport); 11772731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11788868fd44SBryan Wu #endif 11792731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = musb_cfg.musb_speed; 11802731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11812731b9a8SJean-Christophe PLAGNIOL-VILLARD 11822731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */ 11832731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out); 11842731b9a8SJean-Christophe PLAGNIOL-VILLARD 11852731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!dir_out) { /* intrrupt-in transfer */ 11862731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */ 11872731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out); 11882731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(interval, &musbr->rxinterval); 11892731b9a8SJean-Christophe PLAGNIOL-VILLARD 11902731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Program the RxType register */ 11912731b9a8SJean-Christophe PLAGNIOL-VILLARD type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | 11922731b9a8SJean-Christophe PLAGNIOL-VILLARD (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) | 11932731b9a8SJean-Christophe PLAGNIOL-VILLARD (ep & MUSB_TYPE_REMOTE_END); 11942731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(type, &musbr->rxtype); 11952731b9a8SJean-Christophe PLAGNIOL-VILLARD 11962731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the maximum packet size to the RxMaxp register */ 11972731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); 11982731b9a8SJean-Christophe PLAGNIOL-VILLARD 11992731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) { 12002731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? 12012731b9a8SJean-Christophe PLAGNIOL-VILLARD (len-txlen) : dev->epmaxpacketin[ep]; 12022731b9a8SJean-Christophe PLAGNIOL-VILLARD 12032731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the ReqPkt bit */ 1204bc72a919SBryan Wu csr = readw(&musbr->rxcsr); 1205bc72a919SBryan Wu writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); 12062731b9a8SJean-Christophe PLAGNIOL-VILLARD 12072731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the RxPktRdy bit is set */ 12082731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!wait_until_rxep_ready(dev, MUSB_INTR_EP)) { 12092731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 12102731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 12112731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); 12122731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY; 12132731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 12142731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen; 12152731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 12162731b9a8SJean-Christophe PLAGNIOL-VILLARD } 12172731b9a8SJean-Christophe PLAGNIOL-VILLARD 12182731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Read the data from the FIFO */ 12192731b9a8SJean-Christophe PLAGNIOL-VILLARD read_fifo(MUSB_INTR_EP, nextlen, 12202731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen)); 12212731b9a8SJean-Christophe PLAGNIOL-VILLARD 12222731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Clear the RxPktRdy bit */ 12232731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 12242731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY; 12252731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 12262731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen; 12272731b9a8SJean-Christophe PLAGNIOL-VILLARD } 12282731b9a8SJean-Christophe PLAGNIOL-VILLARD 12292731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */ 12302731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 12312731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 12322731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); 12332731b9a8SJean-Christophe PLAGNIOL-VILLARD } 12342731b9a8SJean-Christophe PLAGNIOL-VILLARD 12352731b9a8SJean-Christophe PLAGNIOL-VILLARD /* interrupt transfer is complete */ 12362731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_status = 0; 12372731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_act_len = len; 12382731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_handle(dev); 12392731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 12402731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = len; 12412731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 12422731b9a8SJean-Christophe PLAGNIOL-VILLARD } 12432731b9a8SJean-Christophe PLAGNIOL-VILLARD 12442731b9a8SJean-Christophe PLAGNIOL-VILLARD 12452731b9a8SJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_USB_EVENT_POLL 12462731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 12472731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function polls for USB keyboard data. 12482731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 12492731b9a8SJean-Christophe PLAGNIOL-VILLARD void usb_event_poll() 12502731b9a8SJean-Christophe PLAGNIOL-VILLARD { 125152cb4d4fSJean-Christophe PLAGNIOL-VILLARD struct stdio_dev *dev; 12522731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_device *usb_kbd_dev; 12538f8bd565STom Rix struct usb_interface *iface; 12542731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_endpoint_descriptor *ep; 12552731b9a8SJean-Christophe PLAGNIOL-VILLARD int pipe; 12562731b9a8SJean-Christophe PLAGNIOL-VILLARD int maxp; 12572731b9a8SJean-Christophe PLAGNIOL-VILLARD 12582731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Get the pointer to USB Keyboard device pointer */ 125952cb4d4fSJean-Christophe PLAGNIOL-VILLARD dev = stdio_get_by_name("usbkbd"); 12602731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_kbd_dev = (struct usb_device *)dev->priv; 12612731b9a8SJean-Christophe PLAGNIOL-VILLARD iface = &usb_kbd_dev->config.if_desc[0]; 12622731b9a8SJean-Christophe PLAGNIOL-VILLARD ep = &iface->ep_desc[0]; 12632731b9a8SJean-Christophe PLAGNIOL-VILLARD pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress); 12642731b9a8SJean-Christophe PLAGNIOL-VILLARD 12652731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Submit a interrupt transfer request */ 12662731b9a8SJean-Christophe PLAGNIOL-VILLARD maxp = usb_maxpacket(usb_kbd_dev, pipe); 12672731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_submit_int_msg(usb_kbd_dev, pipe, &new[0], 12682731b9a8SJean-Christophe PLAGNIOL-VILLARD maxp > 8 ? 8 : maxp, ep->bInterval); 12692731b9a8SJean-Christophe PLAGNIOL-VILLARD } 12702731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_USB_EVENT_POLL */ 1271