12731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 22731b9a8SJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2004 32731b9a8SJean-Christophe PLAGNIOL-VILLARD * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 42731b9a8SJean-Christophe PLAGNIOL-VILLARD * 52731b9a8SJean-Christophe PLAGNIOL-VILLARD * This code is based on linux driver for sl811hs chip, source at 62731b9a8SJean-Christophe PLAGNIOL-VILLARD * drivers/usb/host/sl811.c: 72731b9a8SJean-Christophe PLAGNIOL-VILLARD * 82731b9a8SJean-Christophe PLAGNIOL-VILLARD * SL811 Host Controller Interface driver for USB. 92731b9a8SJean-Christophe PLAGNIOL-VILLARD * 102731b9a8SJean-Christophe PLAGNIOL-VILLARD * Copyright (c) 2003/06, Courage Co., Ltd. 112731b9a8SJean-Christophe PLAGNIOL-VILLARD * 122731b9a8SJean-Christophe PLAGNIOL-VILLARD * Based on: 132731b9a8SJean-Christophe PLAGNIOL-VILLARD * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap, 142731b9a8SJean-Christophe PLAGNIOL-VILLARD * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, 152731b9a8SJean-Christophe PLAGNIOL-VILLARD * Adam Richter, Gregory P. Smith; 162731b9a8SJean-Christophe PLAGNIOL-VILLARD * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com> 172731b9a8SJean-Christophe PLAGNIOL-VILLARD * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn> 182731b9a8SJean-Christophe PLAGNIOL-VILLARD * 192731b9a8SJean-Christophe PLAGNIOL-VILLARD * See file CREDITS for list of people who contributed to this 202731b9a8SJean-Christophe PLAGNIOL-VILLARD * project. 212731b9a8SJean-Christophe PLAGNIOL-VILLARD * 222731b9a8SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 232731b9a8SJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 242731b9a8SJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 252731b9a8SJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 262731b9a8SJean-Christophe PLAGNIOL-VILLARD * 272731b9a8SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 282731b9a8SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 292731b9a8SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 302731b9a8SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 312731b9a8SJean-Christophe PLAGNIOL-VILLARD * 322731b9a8SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 332731b9a8SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 342731b9a8SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 352731b9a8SJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 362731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 372731b9a8SJean-Christophe PLAGNIOL-VILLARD 382731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 392731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <mpc8xx.h> 402731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <usb.h> 412731b9a8SJean-Christophe PLAGNIOL-VILLARD #include "sl811.h" 422731b9a8SJean-Christophe PLAGNIOL-VILLARD 432731b9a8SJean-Christophe PLAGNIOL-VILLARD #include "../../../board/kup/common/kup.h" 442731b9a8SJean-Christophe PLAGNIOL-VILLARD 452731b9a8SJean-Christophe PLAGNIOL-VILLARD #ifdef __PPC__ 462731b9a8SJean-Christophe PLAGNIOL-VILLARD # define EIEIO __asm__ volatile ("eieio") 472731b9a8SJean-Christophe PLAGNIOL-VILLARD #else 482731b9a8SJean-Christophe PLAGNIOL-VILLARD # define EIEIO /* nothing */ 492731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif 502731b9a8SJean-Christophe PLAGNIOL-VILLARD 512731b9a8SJean-Christophe PLAGNIOL-VILLARD #define SL811_ADR (0x50000000) 522731b9a8SJean-Christophe PLAGNIOL-VILLARD #define SL811_DAT (0x50000001) 532731b9a8SJean-Christophe PLAGNIOL-VILLARD 542731b9a8SJean-Christophe PLAGNIOL-VILLARD #ifdef SL811_DEBUG 552731b9a8SJean-Christophe PLAGNIOL-VILLARD static int debug = 9; 562731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif 572731b9a8SJean-Christophe PLAGNIOL-VILLARD 582731b9a8SJean-Christophe PLAGNIOL-VILLARD static int root_hub_devnum = 0; 592731b9a8SJean-Christophe PLAGNIOL-VILLARD static struct usb_port_status rh_status = { 0 };/* root hub port status */ 602731b9a8SJean-Christophe PLAGNIOL-VILLARD 612731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe, 622731b9a8SJean-Christophe PLAGNIOL-VILLARD void *data, int buf_len, struct devrequest *cmd); 632731b9a8SJean-Christophe PLAGNIOL-VILLARD 642731b9a8SJean-Christophe PLAGNIOL-VILLARD static void sl811_write (__u8 index, __u8 data) 652731b9a8SJean-Christophe PLAGNIOL-VILLARD { 662731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = index; 672731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 682731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_DAT) = data; 692731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 702731b9a8SJean-Christophe PLAGNIOL-VILLARD } 712731b9a8SJean-Christophe PLAGNIOL-VILLARD 722731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_read (__u8 index) 732731b9a8SJean-Christophe PLAGNIOL-VILLARD { 742731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 data; 752731b9a8SJean-Christophe PLAGNIOL-VILLARD 762731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = index; 772731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 782731b9a8SJean-Christophe PLAGNIOL-VILLARD data = *(volatile unsigned char *) (SL811_DAT); 792731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 802731b9a8SJean-Christophe PLAGNIOL-VILLARD return (data); 812731b9a8SJean-Christophe PLAGNIOL-VILLARD } 822731b9a8SJean-Christophe PLAGNIOL-VILLARD 832731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 842731b9a8SJean-Christophe PLAGNIOL-VILLARD * Read consecutive bytes of data from the SL811H/SL11H buffer 852731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 862731b9a8SJean-Christophe PLAGNIOL-VILLARD static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size) 872731b9a8SJean-Christophe PLAGNIOL-VILLARD { 882731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = offset; 892731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 902731b9a8SJean-Christophe PLAGNIOL-VILLARD while (size--) { 912731b9a8SJean-Christophe PLAGNIOL-VILLARD *buf++ = *(volatile unsigned char *) (SL811_DAT); 922731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 932731b9a8SJean-Christophe PLAGNIOL-VILLARD } 942731b9a8SJean-Christophe PLAGNIOL-VILLARD } 952731b9a8SJean-Christophe PLAGNIOL-VILLARD 962731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 972731b9a8SJean-Christophe PLAGNIOL-VILLARD * Write consecutive bytes of data to the SL811H/SL11H buffer 982731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 992731b9a8SJean-Christophe PLAGNIOL-VILLARD static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size) 1002731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1012731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = offset; 1022731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 1032731b9a8SJean-Christophe PLAGNIOL-VILLARD while (size--) { 1042731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_DAT) = *buf++; 1052731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 1062731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1072731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1082731b9a8SJean-Christophe PLAGNIOL-VILLARD 1092731b9a8SJean-Christophe PLAGNIOL-VILLARD int usb_init_kup4x (void) 1102731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1112731b9a8SJean-Christophe PLAGNIOL-VILLARD volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; 1122731b9a8SJean-Christophe PLAGNIOL-VILLARD volatile memctl8xx_t *memctl = &immap->im_memctl; 1132731b9a8SJean-Christophe PLAGNIOL-VILLARD int i; 1142731b9a8SJean-Christophe PLAGNIOL-VILLARD unsigned char tmp; 1152731b9a8SJean-Christophe PLAGNIOL-VILLARD 1162731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl = &immap->im_memctl; 1172731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl->memc_or7 = 0xFFFF8726; 1182731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl->memc_br7 = 0x50000401; /* start at 0x50000000 */ 1192731b9a8SJean-Christophe PLAGNIOL-VILLARD /* BP 14 low = USB ON */ 1202731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC); 1212731b9a8SJean-Christophe PLAGNIOL-VILLARD /* PB 14 nomal port */ 1222731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC); 1232731b9a8SJean-Christophe PLAGNIOL-VILLARD /* output */ 1242731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbdir |= (BP_USB_VCC); 1252731b9a8SJean-Christophe PLAGNIOL-VILLARD 1262731b9a8SJean-Christophe PLAGNIOL-VILLARD puts ("USB: "); 1272731b9a8SJean-Christophe PLAGNIOL-VILLARD 1282731b9a8SJean-Christophe PLAGNIOL-VILLARD for (i = 0x10; i < 0xff; i++) { 1292731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(i, i); 1302731b9a8SJean-Christophe PLAGNIOL-VILLARD tmp = (sl811_read(i)); 1312731b9a8SJean-Christophe PLAGNIOL-VILLARD if (tmp != i) { 1322731b9a8SJean-Christophe PLAGNIOL-VILLARD printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp); 1332731b9a8SJean-Christophe PLAGNIOL-VILLARD return (-1); 1342731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1352731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1362731b9a8SJean-Christophe PLAGNIOL-VILLARD printf ("SL811 ready\n"); 1372731b9a8SJean-Christophe PLAGNIOL-VILLARD return (0); 1382731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1392731b9a8SJean-Christophe PLAGNIOL-VILLARD 1402731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 1412731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function resets SL811HS controller and detects the speed of 1422731b9a8SJean-Christophe PLAGNIOL-VILLARD * the connecting device 1432731b9a8SJean-Christophe PLAGNIOL-VILLARD * 1442731b9a8SJean-Christophe PLAGNIOL-VILLARD * Return: 0 = no device attached; 1 = USB device attached 1452731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 1462731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_hc_reset(void) 1472731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1482731b9a8SJean-Christophe PLAGNIOL-VILLARD int status ; 1492731b9a8SJean-Christophe PLAGNIOL-VILLARD 1502731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI); 1512731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET); 1522731b9a8SJean-Christophe PLAGNIOL-VILLARD 1532731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20); 1542731b9a8SJean-Christophe PLAGNIOL-VILLARD 1552731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Disable hardware SOF generation, clear all irq status. */ 1562731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, 0); 1572731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2); 1582731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 1592731b9a8SJean-Christophe PLAGNIOL-VILLARD status = sl811_read(SL811_INTRSTS); 1602731b9a8SJean-Christophe PLAGNIOL-VILLARD 1612731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_INTR_NOTPRESENT) { 1622731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Device is not present */ 1632731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "Device not present\n"); 1642731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE); 1652731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION; 1662731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTR, SL811_INTR_INSRMV); 1672731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 1682731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1692731b9a8SJean-Christophe PLAGNIOL-VILLARD 1702731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Send SOF to address 0, endpoint 0. */ 1712731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_LEN_B, 0); 1722731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0)); 1732731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_B, 0x00); 1742731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_SOFLOW, SL811_12M_LOW); 1752731b9a8SJean-Christophe PLAGNIOL-VILLARD 1762731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_INTR_SPEED_FULL) { 1772731b9a8SJean-Christophe PLAGNIOL-VILLARD /* full speed device connect directly to root hub */ 1782731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG (0, "Full speed Device attached\n"); 1792731b9a8SJean-Christophe PLAGNIOL-VILLARD 1802731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET); 1812731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20); 1822731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI); 1832731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_SOF); 1842731b9a8SJean-Christophe PLAGNIOL-VILLARD 1852731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start the SOF or EOP */ 1862731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM); 1872731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION; 1882731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED; 1892731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2); 1902731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 1912731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 1922731b9a8SJean-Christophe PLAGNIOL-VILLARD /* slow speed device connect directly to root-hub */ 1932731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "Low speed Device attached\n"); 1942731b9a8SJean-Christophe PLAGNIOL-VILLARD 1952731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET); 1962731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20); 1972731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI); 1982731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF); 1992731b9a8SJean-Christophe PLAGNIOL-VILLARD 2002731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start the SOF or EOP */ 2012731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM); 2022731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED; 2032731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2); 2042731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 2052731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2062731b9a8SJean-Christophe PLAGNIOL-VILLARD 2072731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION; 2082731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A); 2092731b9a8SJean-Christophe PLAGNIOL-VILLARD 2102731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1; 2112731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2122731b9a8SJean-Christophe PLAGNIOL-VILLARD 213c7e3b2b5SLucas Stach int usb_lowlevel_init(int index, void **controller) 2142731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2152731b9a8SJean-Christophe PLAGNIOL-VILLARD root_hub_devnum = 0; 2162731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_hc_reset(); 2172731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 2182731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2192731b9a8SJean-Christophe PLAGNIOL-VILLARD 220c7e3b2b5SLucas Stach int usb_lowlevel_stop(int index) 2212731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2222731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_hc_reset(); 2232731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 2242731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2252731b9a8SJean-Christophe PLAGNIOL-VILLARD 2262731b9a8SJean-Christophe PLAGNIOL-VILLARD static int calc_needed_buswidth(int bytes, int need_preamble) 2272731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2282731b9a8SJean-Christophe PLAGNIOL-VILLARD return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048; 2292731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2302731b9a8SJean-Christophe PLAGNIOL-VILLARD 2312731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len) 2322731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2332731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE; 2342731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 status = 0; 2352731b9a8SJean-Christophe PLAGNIOL-VILLARD int err = 0, time_start = get_timer(0); 2362731b9a8SJean-Christophe PLAGNIOL-VILLARD int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) && 237*c60795f4SIlya Yanok (dev->speed == USB_SPEED_LOW); 2382731b9a8SJean-Christophe PLAGNIOL-VILLARD 2392731b9a8SJean-Christophe PLAGNIOL-VILLARD if (len > 239) 2402731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2412731b9a8SJean-Christophe PLAGNIOL-VILLARD 2422731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeout(pipe)) 2432731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_DIR_OUT; 2442731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) 2452731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_TOGGLE_1; 2462731b9a8SJean-Christophe PLAGNIOL-VILLARD if (need_preamble) 2472731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_PREAMBLE; 2482731b9a8SJean-Christophe PLAGNIOL-VILLARD 2492731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 2502731b9a8SJean-Christophe PLAGNIOL-VILLARD 2512731b9a8SJean-Christophe PLAGNIOL-VILLARD while (err < 3) { 2522731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_ADDR_A, 0x10); 2532731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_LEN_A, len); 2542731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeout(pipe) && len) 2552731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write_buf(0x10, buffer, len); 2562731b9a8SJean-Christophe PLAGNIOL-VILLARD 2572731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) && 2582731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble)) 2592731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_SOF; 2602731b9a8SJean-Christophe PLAGNIOL-VILLARD else 2612731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl &= ~SL811_USB_CTRL_SOF; 2622731b9a8SJean-Christophe PLAGNIOL-VILLARD 2632731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_A, ctrl); 2642731b9a8SJean-Christophe PLAGNIOL-VILLARD while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) { 2652731b9a8SJean-Christophe PLAGNIOL-VILLARD if (5*CONFIG_SYS_HZ < get_timer(time_start)) { 2662731b9a8SJean-Christophe PLAGNIOL-VILLARD printf("USB transmit timed out\n"); 2672731b9a8SJean-Christophe PLAGNIOL-VILLARD return -USB_ST_CRC_ERR; 2682731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2692731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2702731b9a8SJean-Christophe PLAGNIOL-VILLARD 2712731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 2722731b9a8SJean-Christophe PLAGNIOL-VILLARD status = sl811_read(SL811_STS_A); 2732731b9a8SJean-Christophe PLAGNIOL-VILLARD 2742731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_ACK) { 2752731b9a8SJean-Christophe PLAGNIOL-VILLARD int remainder = sl811_read(SL811_CNT_A); 2762731b9a8SJean-Christophe PLAGNIOL-VILLARD if (remainder) { 2772731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "usb transfer remainder = %d\n", remainder); 2782731b9a8SJean-Christophe PLAGNIOL-VILLARD len -= remainder; 2792731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2802731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipein(pipe) && len) 2812731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_read_buf(0x10, buffer, len); 2822731b9a8SJean-Christophe PLAGNIOL-VILLARD return len; 2832731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2842731b9a8SJean-Christophe PLAGNIOL-VILLARD 2852731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK) 2862731b9a8SJean-Christophe PLAGNIOL-VILLARD continue; 2872731b9a8SJean-Christophe PLAGNIOL-VILLARD 2882731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "usb transfer error %#x\n", (int)status); 2892731b9a8SJean-Christophe PLAGNIOL-VILLARD err++; 2902731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2912731b9a8SJean-Christophe PLAGNIOL-VILLARD 2922731b9a8SJean-Christophe PLAGNIOL-VILLARD err = 0; 2932731b9a8SJean-Christophe PLAGNIOL-VILLARD 2942731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_ERROR) 2952731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_BUF_ERR; 2962731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_TIMEOUT) 2972731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_CRC_ERR; 2982731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_STALL) 2992731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_STALLED; 3002731b9a8SJean-Christophe PLAGNIOL-VILLARD 3012731b9a8SJean-Christophe PLAGNIOL-VILLARD return -err; 3022731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3032731b9a8SJean-Christophe PLAGNIOL-VILLARD 3042731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 3052731b9a8SJean-Christophe PLAGNIOL-VILLARD int len) 3062731b9a8SJean-Christophe PLAGNIOL-VILLARD { 3072731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_out = usb_pipeout(pipe); 3082731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe); 3092731b9a8SJean-Christophe PLAGNIOL-VILLARD int max = usb_maxpacket(dev, pipe); 3102731b9a8SJean-Christophe PLAGNIOL-VILLARD int done = 0; 3112731b9a8SJean-Christophe PLAGNIOL-VILLARD 3122731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n", 3132731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out); 3142731b9a8SJean-Christophe PLAGNIOL-VILLARD 3152731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 3162731b9a8SJean-Christophe PLAGNIOL-VILLARD 3172731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_A, usb_pipedevice(pipe)); 3182731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep)); 3192731b9a8SJean-Christophe PLAGNIOL-VILLARD while (done < len) { 3202731b9a8SJean-Christophe PLAGNIOL-VILLARD int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done, 3212731b9a8SJean-Christophe PLAGNIOL-VILLARD max > len - done ? len - done : max); 3222731b9a8SJean-Christophe PLAGNIOL-VILLARD if (res < 0) { 3232731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -res; 3242731b9a8SJean-Christophe PLAGNIOL-VILLARD return res; 3252731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3262731b9a8SJean-Christophe PLAGNIOL-VILLARD 3272731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!dir_out && res < max) /* short packet */ 3282731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 3292731b9a8SJean-Christophe PLAGNIOL-VILLARD 3302731b9a8SJean-Christophe PLAGNIOL-VILLARD done += res; 3312731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dotoggle(dev, ep, dir_out); 3322731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3332731b9a8SJean-Christophe PLAGNIOL-VILLARD 3342731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = done; 3352731b9a8SJean-Christophe PLAGNIOL-VILLARD 3362731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 3372731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3382731b9a8SJean-Christophe PLAGNIOL-VILLARD 3392731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 3402731b9a8SJean-Christophe PLAGNIOL-VILLARD int len,struct devrequest *setup) 3412731b9a8SJean-Christophe PLAGNIOL-VILLARD { 3422731b9a8SJean-Christophe PLAGNIOL-VILLARD int done = 0; 3432731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe); 3442731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe); 3452731b9a8SJean-Christophe PLAGNIOL-VILLARD 3462731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 3472731b9a8SJean-Christophe PLAGNIOL-VILLARD 3482731b9a8SJean-Christophe PLAGNIOL-VILLARD if (devnum == root_hub_devnum) 3492731b9a8SJean-Christophe PLAGNIOL-VILLARD return sl811_rh_submit_urb(dev, pipe, buffer, len, setup); 3502731b9a8SJean-Christophe PLAGNIOL-VILLARD 3512731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n", 3522731b9a8SJean-Christophe PLAGNIOL-VILLARD devnum, ep, buffer, len, (int)setup->requesttype, 3532731b9a8SJean-Christophe PLAGNIOL-VILLARD (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64); 3542731b9a8SJean-Christophe PLAGNIOL-VILLARD 3552731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_A, devnum); 3562731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep)); 3572731b9a8SJean-Christophe PLAGNIOL-VILLARD /* setup phase */ 3582731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, 1, 0); 3592731b9a8SJean-Christophe PLAGNIOL-VILLARD if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep), 3602731b9a8SJean-Christophe PLAGNIOL-VILLARD (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) { 3612731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_in = usb_pipein(pipe); 3622731b9a8SJean-Christophe PLAGNIOL-VILLARD int max = usb_maxpacket(dev, pipe); 3632731b9a8SJean-Christophe PLAGNIOL-VILLARD 3642731b9a8SJean-Christophe PLAGNIOL-VILLARD /* data phase */ 3652731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, 3662731b9a8SJean-Christophe PLAGNIOL-VILLARD PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep)); 3672731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, usb_pipeout(pipe), 1); 3682731b9a8SJean-Christophe PLAGNIOL-VILLARD while (done < len) { 3692731b9a8SJean-Christophe PLAGNIOL-VILLARD int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done, 3702731b9a8SJean-Christophe PLAGNIOL-VILLARD max > len - done ? len - done : max); 3712731b9a8SJean-Christophe PLAGNIOL-VILLARD if (res < 0) { 3722731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "status data failed!\n"); 3732731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -res; 3742731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 3752731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3762731b9a8SJean-Christophe PLAGNIOL-VILLARD done += res; 3772731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dotoggle(dev, ep, usb_pipeout(pipe)); 3782731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_in && res < max) /* short packet */ 3792731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 3802731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3812731b9a8SJean-Christophe PLAGNIOL-VILLARD 3822731b9a8SJean-Christophe PLAGNIOL-VILLARD /* status phase */ 3832731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, 3842731b9a8SJean-Christophe PLAGNIOL-VILLARD PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep)); 3852731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, !usb_pipeout(pipe), 1); 3862731b9a8SJean-Christophe PLAGNIOL-VILLARD if (sl811_send_packet(dev, 3872731b9a8SJean-Christophe PLAGNIOL-VILLARD !dir_in ? usb_rcvctrlpipe(dev, ep) : 3882731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_sndctrlpipe(dev, ep), 3892731b9a8SJean-Christophe PLAGNIOL-VILLARD 0, 0) < 0) { 3902731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "status phase failed!\n"); 3912731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -1; 3922731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3932731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 3942731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "setup phase failed!\n"); 3952731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -1; 3962731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3972731b9a8SJean-Christophe PLAGNIOL-VILLARD 3982731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = done; 3992731b9a8SJean-Christophe PLAGNIOL-VILLARD 4002731b9a8SJean-Christophe PLAGNIOL-VILLARD return done; 4012731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4022731b9a8SJean-Christophe PLAGNIOL-VILLARD 4032731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 4042731b9a8SJean-Christophe PLAGNIOL-VILLARD int len, int interval) 4052731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4062731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe, 4072731b9a8SJean-Christophe PLAGNIOL-VILLARD buffer, len, interval); 4082731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 4092731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4102731b9a8SJean-Christophe PLAGNIOL-VILLARD 4112731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 4122731b9a8SJean-Christophe PLAGNIOL-VILLARD * SL811 Virtual Root Hub 4132731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4142731b9a8SJean-Christophe PLAGNIOL-VILLARD 4152731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Device descriptor */ 4162731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_dev_des[] = 4172731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4182731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x12, /* __u8 bLength; */ 4192731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bDescriptorType; Device */ 4202731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x10, /* __u16 bcdUSB; v1.1 */ 4212731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, 4222731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 4232731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bDeviceSubClass; */ 4242731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bDeviceProtocol; */ 4252731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 4262731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 idVendor; */ 4272731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 4282731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 idProduct; */ 4292731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 4302731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 bcdDevice; */ 4312731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 4322731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 iManufacturer; */ 4332731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x02, /* __u8 iProduct; */ 4342731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 iSerialNumber; */ 4352731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01 /* __u8 bNumConfigurations; */ 4362731b9a8SJean-Christophe PLAGNIOL-VILLARD }; 4372731b9a8SJean-Christophe PLAGNIOL-VILLARD 4382731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Configuration descriptor */ 4392731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_config_des[] = 4402731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4412731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bLength; */ 4422731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x02, /* __u8 bDescriptorType; Configuration */ 4432731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x19, /* __u16 wTotalLength; */ 4442731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 4452731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bNumInterfaces; */ 4462731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bConfigurationValue; */ 4472731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 iConfiguration; */ 4482731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x40, /* __u8 bmAttributes; 4492731b9a8SJean-Christophe PLAGNIOL-VILLARD Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4502731b9a8SJean-Christophe PLAGNIOL-VILLARD 4..0: resvd */ 4512731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 MaxPower; */ 4522731b9a8SJean-Christophe PLAGNIOL-VILLARD 4532731b9a8SJean-Christophe PLAGNIOL-VILLARD /* interface */ 4542731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 if_bLength; */ 4552731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x04, /* __u8 if_bDescriptorType; Interface */ 4562731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceNumber; */ 4572731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bAlternateSetting; */ 4582731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 if_bNumEndpoints; */ 4592731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ 4602731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceSubClass; */ 4612731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceProtocol; */ 4622731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_iInterface; */ 4632731b9a8SJean-Christophe PLAGNIOL-VILLARD 4642731b9a8SJean-Christophe PLAGNIOL-VILLARD /* endpoint */ 4652731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x07, /* __u8 ep_bLength; */ 4662731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 4672731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 4682731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x03, /* __u8 ep_bmAttributes; Interrupt */ 4692731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x08, /* __u16 ep_wMaxPacketSize; */ 4702731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 4712731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xff /* __u8 ep_bInterval; 255 ms */ 4722731b9a8SJean-Christophe PLAGNIOL-VILLARD }; 4732731b9a8SJean-Christophe PLAGNIOL-VILLARD 4742731b9a8SJean-Christophe PLAGNIOL-VILLARD /* root hub class descriptor*/ 4752731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_hub_des[] = 4762731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4772731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bLength; */ 4782731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x29, /* __u8 bDescriptorType; Hub-descriptor */ 4792731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bNbrPorts; */ 4802731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 wHubCharacteristics; */ 4812731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 4822731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x50, /* __u8 bPwrOn2pwrGood; 2ms */ 4832731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bHubContrCurrent; 0 mA */ 4842731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */ 4852731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ 4862731b9a8SJean-Christophe PLAGNIOL-VILLARD }; 4872731b9a8SJean-Christophe PLAGNIOL-VILLARD 4882731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 4892731b9a8SJean-Christophe PLAGNIOL-VILLARD * helper routine for returning string descriptors in UTF-16LE 4902731b9a8SJean-Christophe PLAGNIOL-VILLARD * input can actually be ISO-8859-1; ASCII is its 7-bit subset 4912731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4922731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ascii2utf (char *s, u8 *utf, int utfmax) 4932731b9a8SJean-Christophe PLAGNIOL-VILLARD { 4942731b9a8SJean-Christophe PLAGNIOL-VILLARD int retval; 4952731b9a8SJean-Christophe PLAGNIOL-VILLARD 4962731b9a8SJean-Christophe PLAGNIOL-VILLARD for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { 4972731b9a8SJean-Christophe PLAGNIOL-VILLARD *utf++ = *s++; 4982731b9a8SJean-Christophe PLAGNIOL-VILLARD *utf++ = 0; 4992731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5002731b9a8SJean-Christophe PLAGNIOL-VILLARD return retval; 5012731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5022731b9a8SJean-Christophe PLAGNIOL-VILLARD 5032731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 5042731b9a8SJean-Christophe PLAGNIOL-VILLARD * root_hub_string is used by each host controller's root hub code, 5052731b9a8SJean-Christophe PLAGNIOL-VILLARD * so that they're identified consistently throughout the system. 5062731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 5072731b9a8SJean-Christophe PLAGNIOL-VILLARD static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len) 5082731b9a8SJean-Christophe PLAGNIOL-VILLARD { 5092731b9a8SJean-Christophe PLAGNIOL-VILLARD char buf [30]; 5102731b9a8SJean-Christophe PLAGNIOL-VILLARD 5112731b9a8SJean-Christophe PLAGNIOL-VILLARD /* assert (len > (2 * (sizeof (buf) + 1))); 5122731b9a8SJean-Christophe PLAGNIOL-VILLARD assert (strlen (type) <= 8);*/ 5132731b9a8SJean-Christophe PLAGNIOL-VILLARD 5142731b9a8SJean-Christophe PLAGNIOL-VILLARD /* language ids */ 5152731b9a8SJean-Christophe PLAGNIOL-VILLARD if (id == 0) { 5162731b9a8SJean-Christophe PLAGNIOL-VILLARD *data++ = 4; *data++ = 3; /* 4 bytes data */ 5172731b9a8SJean-Christophe PLAGNIOL-VILLARD *data++ = 0; *data++ = 0; /* some language id */ 5182731b9a8SJean-Christophe PLAGNIOL-VILLARD return 4; 5192731b9a8SJean-Christophe PLAGNIOL-VILLARD 5202731b9a8SJean-Christophe PLAGNIOL-VILLARD /* serial number */ 5212731b9a8SJean-Christophe PLAGNIOL-VILLARD } else if (id == 1) { 5222731b9a8SJean-Christophe PLAGNIOL-VILLARD sprintf (buf, "%#x", serial); 5232731b9a8SJean-Christophe PLAGNIOL-VILLARD 5242731b9a8SJean-Christophe PLAGNIOL-VILLARD /* product description */ 5252731b9a8SJean-Christophe PLAGNIOL-VILLARD } else if (id == 2) { 5262731b9a8SJean-Christophe PLAGNIOL-VILLARD sprintf (buf, "USB %s Root Hub", type); 5272731b9a8SJean-Christophe PLAGNIOL-VILLARD 5282731b9a8SJean-Christophe PLAGNIOL-VILLARD /* id 3 == vendor description */ 5292731b9a8SJean-Christophe PLAGNIOL-VILLARD 5302731b9a8SJean-Christophe PLAGNIOL-VILLARD /* unsupported IDs --> "stall" */ 5312731b9a8SJean-Christophe PLAGNIOL-VILLARD } else 5322731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 5332731b9a8SJean-Christophe PLAGNIOL-VILLARD 5342731b9a8SJean-Christophe PLAGNIOL-VILLARD ascii2utf (buf, data + 2, len - 2); 5352731b9a8SJean-Christophe PLAGNIOL-VILLARD data [0] = 2 + strlen(buf) * 2; 5362731b9a8SJean-Christophe PLAGNIOL-VILLARD data [1] = 3; 5372731b9a8SJean-Christophe PLAGNIOL-VILLARD return data [0]; 5382731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5392731b9a8SJean-Christophe PLAGNIOL-VILLARD 5402731b9a8SJean-Christophe PLAGNIOL-VILLARD /* helper macro */ 5412731b9a8SJean-Christophe PLAGNIOL-VILLARD #define OK(x) len = (x); break 5422731b9a8SJean-Christophe PLAGNIOL-VILLARD 5432731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 5442731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles all USB request to the the virtual root hub 5452731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 5462731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe, 5472731b9a8SJean-Christophe PLAGNIOL-VILLARD void *data, int buf_len, struct devrequest *cmd) 5482731b9a8SJean-Christophe PLAGNIOL-VILLARD { 5492731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 data_buf[16]; 5502731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 *bufp = data_buf; 5512731b9a8SJean-Christophe PLAGNIOL-VILLARD int len = 0; 5522731b9a8SJean-Christophe PLAGNIOL-VILLARD int status = 0; 5532731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 bmRType_bReq; 554b0b20d47SWolfgang Denk __u16 wValue = le16_to_cpu (cmd->value); 555b0b20d47SWolfgang Denk __u16 wLength = le16_to_cpu (cmd->length); 556b0b20d47SWolfgang Denk #ifdef SL811_DEBUG 557b0b20d47SWolfgang Denk __u16 wIndex = le16_to_cpu (cmd->index); 558b0b20d47SWolfgang Denk #endif 5592731b9a8SJean-Christophe PLAGNIOL-VILLARD 5602731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeint(pipe)) { 5612731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "interrupt transfer unimplemented!\n"); 5622731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 5632731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5642731b9a8SJean-Christophe PLAGNIOL-VILLARD 5652731b9a8SJean-Christophe PLAGNIOL-VILLARD bmRType_bReq = cmd->requesttype | (cmd->request << 8); 5662731b9a8SJean-Christophe PLAGNIOL-VILLARD 5672731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n", 5682731b9a8SJean-Christophe PLAGNIOL-VILLARD bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength); 5692731b9a8SJean-Christophe PLAGNIOL-VILLARD 5702731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Request Destination: 5712731b9a8SJean-Christophe PLAGNIOL-VILLARD without flags: Device, 5722731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_INTERFACE: interface, 5732731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_ENDPOINT: endpoint, 5742731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_TYPE_CLASS means HUB here, 5752731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here 5762731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 5772731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (bmRType_bReq) { 5782731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS: 5792731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(1); 5802731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2); 5812731b9a8SJean-Christophe PLAGNIOL-VILLARD 5822731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_INTERFACE: 5832731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(0); 5842731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2); 5852731b9a8SJean-Christophe PLAGNIOL-VILLARD 5862731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_ENDPOINT: 5872731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(0); 5882731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2); 5892731b9a8SJean-Christophe PLAGNIOL-VILLARD 5902731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_TYPE_CLASS: 5912731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u32 *)bufp = cpu_to_le32(0); 5922731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(4); 5932731b9a8SJean-Christophe PLAGNIOL-VILLARD 5942731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS: 5952731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus); 5962731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(4); 5972731b9a8SJean-Christophe PLAGNIOL-VILLARD 5982731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT: 5992731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) { 6002731b9a8SJean-Christophe PLAGNIOL-VILLARD case 1: 6012731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6022731b9a8SJean-Christophe PLAGNIOL-VILLARD } 6032731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 6042731b9a8SJean-Christophe PLAGNIOL-VILLARD 6052731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_TYPE_CLASS: 6062731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) { 6072731b9a8SJean-Christophe PLAGNIOL-VILLARD case C_HUB_LOCAL_POWER: 6082731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6092731b9a8SJean-Christophe PLAGNIOL-VILLARD 6102731b9a8SJean-Christophe PLAGNIOL-VILLARD case C_HUB_OVER_CURRENT: 6112731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6122731b9a8SJean-Christophe PLAGNIOL-VILLARD } 6132731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 6142731b9a8SJean-Christophe PLAGNIOL-VILLARD 6152731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS: 6162731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) { 6172731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_ENABLE: 6182731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE; 6192731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6202731b9a8SJean-Christophe PLAGNIOL-VILLARD 6212731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_SUSPEND: 6222731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND; 6232731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6242731b9a8SJean-Christophe PLAGNIOL-VILLARD 6252731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_POWER: 6262731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_POWER; 6272731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6282731b9a8SJean-Christophe PLAGNIOL-VILLARD 6292731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_CONNECTION: 6302731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION; 6312731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6322731b9a8SJean-Christophe PLAGNIOL-VILLARD 6332731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_ENABLE: 6342731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE; 6352731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6362731b9a8SJean-Christophe PLAGNIOL-VILLARD 6372731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_SUSPEND: 6382731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND; 6392731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6402731b9a8SJean-Christophe PLAGNIOL-VILLARD 6412731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_OVER_CURRENT: 6422731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT; 6432731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6442731b9a8SJean-Christophe PLAGNIOL-VILLARD 6452731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_RESET: 6462731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET; 6472731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6482731b9a8SJean-Christophe PLAGNIOL-VILLARD } 6492731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 6502731b9a8SJean-Christophe PLAGNIOL-VILLARD 6512731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS: 6522731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) { 6532731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_SUSPEND: 6542731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND; 6552731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6562731b9a8SJean-Christophe PLAGNIOL-VILLARD 6572731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_RESET: 6582731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_RESET; 6592731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange = 0; 6602731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_RESET; 6612731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_RESET; 6622731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_ENABLE; 6632731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6642731b9a8SJean-Christophe PLAGNIOL-VILLARD 6652731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_POWER: 6662731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_POWER; 6672731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6682731b9a8SJean-Christophe PLAGNIOL-VILLARD 6692731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_ENABLE: 6702731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_ENABLE; 6712731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6722731b9a8SJean-Christophe PLAGNIOL-VILLARD } 6732731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 6742731b9a8SJean-Christophe PLAGNIOL-VILLARD 6752731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_ADDRESS: 6762731b9a8SJean-Christophe PLAGNIOL-VILLARD root_hub_devnum = wValue; 6772731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 6782731b9a8SJean-Christophe PLAGNIOL-VILLARD 6792731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_DESCRIPTOR: 6802731b9a8SJean-Christophe PLAGNIOL-VILLARD switch ((wValue & 0xff00) >> 8) { 6812731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_DEVICE: 6822731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_dev_des); 6832731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_dev_des; 6842731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len); 6852731b9a8SJean-Christophe PLAGNIOL-VILLARD 6862731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_CONFIG: 6872731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_config_des); 6882731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_config_des; 6892731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len); 6902731b9a8SJean-Christophe PLAGNIOL-VILLARD 6912731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_STRING: 6922731b9a8SJean-Christophe PLAGNIOL-VILLARD len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength); 6932731b9a8SJean-Christophe PLAGNIOL-VILLARD if (len > 0) { 6942731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = data; 6952731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len); 6962731b9a8SJean-Christophe PLAGNIOL-VILLARD } 6972731b9a8SJean-Christophe PLAGNIOL-VILLARD 6982731b9a8SJean-Christophe PLAGNIOL-VILLARD default: 6992731b9a8SJean-Christophe PLAGNIOL-VILLARD status = -32; 7002731b9a8SJean-Christophe PLAGNIOL-VILLARD } 7012731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 7022731b9a8SJean-Christophe PLAGNIOL-VILLARD 7032731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_DESCRIPTOR | USB_TYPE_CLASS: 7042731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_hub_des); 7052731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_hub_des; 7062731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len); 7072731b9a8SJean-Christophe PLAGNIOL-VILLARD 7082731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_CONFIGURATION: 7092731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp[0] = 0x01; 7102731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(1); 7112731b9a8SJean-Christophe PLAGNIOL-VILLARD 7122731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_CONFIGURATION: 7132731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 7142731b9a8SJean-Christophe PLAGNIOL-VILLARD 7152731b9a8SJean-Christophe PLAGNIOL-VILLARD default: 7162731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(1, "unsupported root hub command\n"); 7172731b9a8SJean-Christophe PLAGNIOL-VILLARD status = -32; 7182731b9a8SJean-Christophe PLAGNIOL-VILLARD } 7192731b9a8SJean-Christophe PLAGNIOL-VILLARD 7202731b9a8SJean-Christophe PLAGNIOL-VILLARD len = min(len, buf_len); 7212731b9a8SJean-Christophe PLAGNIOL-VILLARD if (data != bufp) 7222731b9a8SJean-Christophe PLAGNIOL-VILLARD memcpy(data, bufp, len); 7232731b9a8SJean-Christophe PLAGNIOL-VILLARD 7242731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(5, "len = %d, status = %d\n", len, status); 7252731b9a8SJean-Christophe PLAGNIOL-VILLARD 7262731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dev->status = status; 7272731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dev->act_len = len; 7282731b9a8SJean-Christophe PLAGNIOL-VILLARD 7292731b9a8SJean-Christophe PLAGNIOL-VILLARD return status == 0 ? len : status; 7302731b9a8SJean-Christophe PLAGNIOL-VILLARD } 731