1*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 2*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2004 3*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 5*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * This code is based on linux driver for sl811hs chip, source at 6*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * drivers/usb/host/sl811.c: 7*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 8*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * SL811 Host Controller Interface driver for USB. 9*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 10*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Copyright (c) 2003/06, Courage Co., Ltd. 11*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 12*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Based on: 13*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap, 14*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, 15*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Adam Richter, Gregory P. Smith; 16*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com> 17*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn> 18*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 19*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * See file CREDITS for list of people who contributed to this 20*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * project. 21*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 22*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 23*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 24*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 25*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 26*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 27*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 28*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 29*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 31*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 32*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 33*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 34*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 35*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 36*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 37*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 38*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 39*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <mpc8xx.h> 40*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <usb.h> 41*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #include "sl811.h" 42*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 43*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #include "../../../board/kup/common/kup.h" 44*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 45*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #ifdef __PPC__ 46*2731b9a8SJean-Christophe PLAGNIOL-VILLARD # define EIEIO __asm__ volatile ("eieio") 47*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #else 48*2731b9a8SJean-Christophe PLAGNIOL-VILLARD # define EIEIO /* nothing */ 49*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif 50*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 51*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #define SL811_ADR (0x50000000) 52*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #define SL811_DAT (0x50000001) 53*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 54*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);}) 55*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 56*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #ifdef SL811_DEBUG 57*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int debug = 9; 58*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif 59*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 60*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int root_hub_devnum = 0; 61*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static struct usb_port_status rh_status = { 0 };/* root hub port status */ 62*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 63*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe, 64*2731b9a8SJean-Christophe PLAGNIOL-VILLARD void *data, int buf_len, struct devrequest *cmd); 65*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 66*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static void sl811_write (__u8 index, __u8 data) 67*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 68*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = index; 69*2731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 70*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_DAT) = data; 71*2731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 72*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 73*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 74*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_read (__u8 index) 75*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 76*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 data; 77*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 78*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = index; 79*2731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 80*2731b9a8SJean-Christophe PLAGNIOL-VILLARD data = *(volatile unsigned char *) (SL811_DAT); 81*2731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 82*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return (data); 83*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 84*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 85*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 86*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Read consecutive bytes of data from the SL811H/SL11H buffer 87*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 88*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size) 89*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 90*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = offset; 91*2731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 92*2731b9a8SJean-Christophe PLAGNIOL-VILLARD while (size--) { 93*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *buf++ = *(volatile unsigned char *) (SL811_DAT); 94*2731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 95*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 96*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 97*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 98*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 99*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Write consecutive bytes of data to the SL811H/SL11H buffer 100*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 101*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size) 102*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 103*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_ADR) = offset; 104*2731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 105*2731b9a8SJean-Christophe PLAGNIOL-VILLARD while (size--) { 106*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(volatile unsigned char *) (SL811_DAT) = *buf++; 107*2731b9a8SJean-Christophe PLAGNIOL-VILLARD EIEIO; 108*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 109*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 110*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 111*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int usb_init_kup4x (void) 112*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 113*2731b9a8SJean-Christophe PLAGNIOL-VILLARD volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; 114*2731b9a8SJean-Christophe PLAGNIOL-VILLARD volatile memctl8xx_t *memctl = &immap->im_memctl; 115*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int i; 116*2731b9a8SJean-Christophe PLAGNIOL-VILLARD unsigned char tmp; 117*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 118*2731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl = &immap->im_memctl; 119*2731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl->memc_or7 = 0xFFFF8726; 120*2731b9a8SJean-Christophe PLAGNIOL-VILLARD memctl->memc_br7 = 0x50000401; /* start at 0x50000000 */ 121*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* BP 14 low = USB ON */ 122*2731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC); 123*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* PB 14 nomal port */ 124*2731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC); 125*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* output */ 126*2731b9a8SJean-Christophe PLAGNIOL-VILLARD immap->im_cpm.cp_pbdir |= (BP_USB_VCC); 127*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 128*2731b9a8SJean-Christophe PLAGNIOL-VILLARD puts ("USB: "); 129*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 130*2731b9a8SJean-Christophe PLAGNIOL-VILLARD for (i = 0x10; i < 0xff; i++) { 131*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(i, i); 132*2731b9a8SJean-Christophe PLAGNIOL-VILLARD tmp = (sl811_read(i)); 133*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (tmp != i) { 134*2731b9a8SJean-Christophe PLAGNIOL-VILLARD printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp); 135*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return (-1); 136*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 137*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 138*2731b9a8SJean-Christophe PLAGNIOL-VILLARD printf ("SL811 ready\n"); 139*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return (0); 140*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 141*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 142*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 143*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function resets SL811HS controller and detects the speed of 144*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * the connecting device 145*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * 146*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * Return: 0 = no device attached; 1 = USB device attached 147*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 148*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_hc_reset(void) 149*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 150*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int status ; 151*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 152*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI); 153*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET); 154*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 155*2731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20); 156*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 157*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Disable hardware SOF generation, clear all irq status. */ 158*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, 0); 159*2731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2); 160*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 161*2731b9a8SJean-Christophe PLAGNIOL-VILLARD status = sl811_read(SL811_INTRSTS); 162*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 163*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_INTR_NOTPRESENT) { 164*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Device is not present */ 165*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "Device not present\n"); 166*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE); 167*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION; 168*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTR, SL811_INTR_INSRMV); 169*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 170*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 171*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 172*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Send SOF to address 0, endpoint 0. */ 173*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_LEN_B, 0); 174*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0)); 175*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_B, 0x00); 176*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_SOFLOW, SL811_12M_LOW); 177*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 178*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_INTR_SPEED_FULL) { 179*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* full speed device connect directly to root hub */ 180*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG (0, "Full speed Device attached\n"); 181*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 182*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET); 183*2731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20); 184*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI); 185*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_SOF); 186*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 187*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start the SOF or EOP */ 188*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM); 189*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION; 190*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED; 191*2731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2); 192*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 193*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 194*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* slow speed device connect directly to root-hub */ 195*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "Low speed Device attached\n"); 196*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 197*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_RESET); 198*2731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(20); 199*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI); 200*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF); 201*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 202*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start the SOF or EOP */ 203*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM); 204*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED; 205*2731b9a8SJean-Christophe PLAGNIOL-VILLARD mdelay(2); 206*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 207*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 208*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 209*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION; 210*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A); 211*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 212*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1; 213*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 214*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 215*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int usb_lowlevel_init(void) 216*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 217*2731b9a8SJean-Christophe PLAGNIOL-VILLARD root_hub_devnum = 0; 218*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_hc_reset(); 219*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 220*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 221*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 222*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int usb_lowlevel_stop(void) 223*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 224*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_hc_reset(); 225*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 226*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 227*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 228*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int calc_needed_buswidth(int bytes, int need_preamble) 229*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 230*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048; 231*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 232*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 233*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len) 234*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 235*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE; 236*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 status = 0; 237*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int err = 0, time_start = get_timer(0); 238*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) && 239*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_pipeslow(pipe); 240*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 241*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (len > 239) 242*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 243*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 244*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeout(pipe)) 245*2731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_DIR_OUT; 246*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) 247*2731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_TOGGLE_1; 248*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (need_preamble) 249*2731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_PREAMBLE; 250*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 251*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 252*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 253*2731b9a8SJean-Christophe PLAGNIOL-VILLARD while (err < 3) { 254*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_ADDR_A, 0x10); 255*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_LEN_A, len); 256*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeout(pipe) && len) 257*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write_buf(0x10, buffer, len); 258*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 259*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) && 260*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble)) 261*2731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl |= SL811_USB_CTRL_SOF; 262*2731b9a8SJean-Christophe PLAGNIOL-VILLARD else 263*2731b9a8SJean-Christophe PLAGNIOL-VILLARD ctrl &= ~SL811_USB_CTRL_SOF; 264*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 265*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_CTRL_A, ctrl); 266*2731b9a8SJean-Christophe PLAGNIOL-VILLARD while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) { 267*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (5*CONFIG_SYS_HZ < get_timer(time_start)) { 268*2731b9a8SJean-Christophe PLAGNIOL-VILLARD printf("USB transmit timed out\n"); 269*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return -USB_ST_CRC_ERR; 270*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 271*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 272*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 273*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_INTRSTS, 0xff); 274*2731b9a8SJean-Christophe PLAGNIOL-VILLARD status = sl811_read(SL811_STS_A); 275*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 276*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_ACK) { 277*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int remainder = sl811_read(SL811_CNT_A); 278*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (remainder) { 279*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "usb transfer remainder = %d\n", remainder); 280*2731b9a8SJean-Christophe PLAGNIOL-VILLARD len -= remainder; 281*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 282*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipein(pipe) && len) 283*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_read_buf(0x10, buffer, len); 284*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return len; 285*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 286*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 287*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK) 288*2731b9a8SJean-Christophe PLAGNIOL-VILLARD continue; 289*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 290*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "usb transfer error %#x\n", (int)status); 291*2731b9a8SJean-Christophe PLAGNIOL-VILLARD err++; 292*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 293*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 294*2731b9a8SJean-Christophe PLAGNIOL-VILLARD err = 0; 295*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 296*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_ERROR) 297*2731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_BUF_ERR; 298*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_TIMEOUT) 299*2731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_CRC_ERR; 300*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (status & SL811_USB_STS_STALL) 301*2731b9a8SJean-Christophe PLAGNIOL-VILLARD err |= USB_ST_STALLED; 302*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 303*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return -err; 304*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 305*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 306*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 307*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int len) 308*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 309*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_out = usb_pipeout(pipe); 310*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe); 311*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int max = usb_maxpacket(dev, pipe); 312*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int done = 0; 313*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 314*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n", 315*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out); 316*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 317*2731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 318*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 319*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_A, usb_pipedevice(pipe)); 320*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep)); 321*2731b9a8SJean-Christophe PLAGNIOL-VILLARD while (done < len) { 322*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done, 323*2731b9a8SJean-Christophe PLAGNIOL-VILLARD max > len - done ? len - done : max); 324*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (res < 0) { 325*2731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -res; 326*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return res; 327*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 328*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 329*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!dir_out && res < max) /* short packet */ 330*2731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 331*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 332*2731b9a8SJean-Christophe PLAGNIOL-VILLARD done += res; 333*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dotoggle(dev, ep, dir_out); 334*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 335*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 336*2731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = done; 337*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 338*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 339*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 340*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 341*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 342*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int len,struct devrequest *setup) 343*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 344*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int done = 0; 345*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe); 346*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe); 347*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 348*2731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 349*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 350*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (devnum == root_hub_devnum) 351*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return sl811_rh_submit_urb(dev, pipe, buffer, len, setup); 352*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 353*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n", 354*2731b9a8SJean-Christophe PLAGNIOL-VILLARD devnum, ep, buffer, len, (int)setup->requesttype, 355*2731b9a8SJean-Christophe PLAGNIOL-VILLARD (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64); 356*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 357*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_DEV_A, devnum); 358*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep)); 359*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* setup phase */ 360*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, 1, 0); 361*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep), 362*2731b9a8SJean-Christophe PLAGNIOL-VILLARD (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) { 363*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_in = usb_pipein(pipe); 364*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int max = usb_maxpacket(dev, pipe); 365*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 366*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* data phase */ 367*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, 368*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep)); 369*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, usb_pipeout(pipe), 1); 370*2731b9a8SJean-Christophe PLAGNIOL-VILLARD while (done < len) { 371*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done, 372*2731b9a8SJean-Christophe PLAGNIOL-VILLARD max > len - done ? len - done : max); 373*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (res < 0) { 374*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "status data failed!\n"); 375*2731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -res; 376*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 377*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 378*2731b9a8SJean-Christophe PLAGNIOL-VILLARD done += res; 379*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dotoggle(dev, ep, usb_pipeout(pipe)); 380*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_in && res < max) /* short packet */ 381*2731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 382*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 383*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 384*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* status phase */ 385*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sl811_write(SL811_PIDEP_A, 386*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep)); 387*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, !usb_pipeout(pipe), 1); 388*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (sl811_send_packet(dev, 389*2731b9a8SJean-Christophe PLAGNIOL-VILLARD !dir_in ? usb_rcvctrlpipe(dev, ep) : 390*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_sndctrlpipe(dev, ep), 391*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0, 0) < 0) { 392*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "status phase failed!\n"); 393*2731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -1; 394*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 395*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 396*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "setup phase failed!\n"); 397*2731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = -1; 398*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 399*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 400*2731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = done; 401*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 402*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return done; 403*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 404*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 405*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, 406*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int len, int interval) 407*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 408*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe, 409*2731b9a8SJean-Christophe PLAGNIOL-VILLARD buffer, len, interval); 410*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 411*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 412*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 413*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 414*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * SL811 Virtual Root Hub 415*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 416*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 417*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Device descriptor */ 418*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_dev_des[] = 419*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 420*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x12, /* __u8 bLength; */ 421*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bDescriptorType; Device */ 422*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x10, /* __u16 bcdUSB; v1.1 */ 423*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, 424*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 425*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bDeviceSubClass; */ 426*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bDeviceProtocol; */ 427*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 428*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 idVendor; */ 429*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 430*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 idProduct; */ 431*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 432*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 bcdDevice; */ 433*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 434*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 iManufacturer; */ 435*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x02, /* __u8 iProduct; */ 436*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 iSerialNumber; */ 437*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01 /* __u8 bNumConfigurations; */ 438*2731b9a8SJean-Christophe PLAGNIOL-VILLARD }; 439*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 440*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Configuration descriptor */ 441*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_config_des[] = 442*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 443*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bLength; */ 444*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x02, /* __u8 bDescriptorType; Configuration */ 445*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x19, /* __u16 wTotalLength; */ 446*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 447*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bNumInterfaces; */ 448*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bConfigurationValue; */ 449*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 iConfiguration; */ 450*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x40, /* __u8 bmAttributes; 451*2731b9a8SJean-Christophe PLAGNIOL-VILLARD Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 452*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 4..0: resvd */ 453*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 MaxPower; */ 454*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 455*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* interface */ 456*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 if_bLength; */ 457*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x04, /* __u8 if_bDescriptorType; Interface */ 458*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceNumber; */ 459*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bAlternateSetting; */ 460*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 if_bNumEndpoints; */ 461*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ 462*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceSubClass; */ 463*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_bInterfaceProtocol; */ 464*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 if_iInterface; */ 465*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 466*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* endpoint */ 467*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x07, /* __u8 ep_bLength; */ 468*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 469*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 470*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x03, /* __u8 ep_bmAttributes; Interrupt */ 471*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x08, /* __u16 ep_wMaxPacketSize; */ 472*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 473*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xff /* __u8 ep_bInterval; 255 ms */ 474*2731b9a8SJean-Christophe PLAGNIOL-VILLARD }; 475*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 476*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* root hub class descriptor*/ 477*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static __u8 sl811_rh_hub_des[] = 478*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 479*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x09, /* __u8 bLength; */ 480*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x29, /* __u8 bDescriptorType; Hub-descriptor */ 481*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x01, /* __u8 bNbrPorts; */ 482*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u16 wHubCharacteristics; */ 483*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, 484*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x50, /* __u8 bPwrOn2pwrGood; 2ms */ 485*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0x00, /* __u8 bHubContrCurrent; 0 mA */ 486*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */ 487*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ 488*2731b9a8SJean-Christophe PLAGNIOL-VILLARD }; 489*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 490*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 491*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * helper routine for returning string descriptors in UTF-16LE 492*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * input can actually be ISO-8859-1; ASCII is its 7-bit subset 493*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 494*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ascii2utf (char *s, u8 *utf, int utfmax) 495*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 496*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int retval; 497*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 498*2731b9a8SJean-Christophe PLAGNIOL-VILLARD for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { 499*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *utf++ = *s++; 500*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *utf++ = 0; 501*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 502*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return retval; 503*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 504*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 505*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 506*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * root_hub_string is used by each host controller's root hub code, 507*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * so that they're identified consistently throughout the system. 508*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 509*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len) 510*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 511*2731b9a8SJean-Christophe PLAGNIOL-VILLARD char buf [30]; 512*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 513*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* assert (len > (2 * (sizeof (buf) + 1))); 514*2731b9a8SJean-Christophe PLAGNIOL-VILLARD assert (strlen (type) <= 8);*/ 515*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 516*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* language ids */ 517*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (id == 0) { 518*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *data++ = 4; *data++ = 3; /* 4 bytes data */ 519*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *data++ = 0; *data++ = 0; /* some language id */ 520*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 4; 521*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 522*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* serial number */ 523*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } else if (id == 1) { 524*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sprintf (buf, "%#x", serial); 525*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 526*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* product description */ 527*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } else if (id == 2) { 528*2731b9a8SJean-Christophe PLAGNIOL-VILLARD sprintf (buf, "USB %s Root Hub", type); 529*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 530*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* id 3 == vendor description */ 531*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 532*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* unsupported IDs --> "stall" */ 533*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } else 534*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 535*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 536*2731b9a8SJean-Christophe PLAGNIOL-VILLARD ascii2utf (buf, data + 2, len - 2); 537*2731b9a8SJean-Christophe PLAGNIOL-VILLARD data [0] = 2 + strlen(buf) * 2; 538*2731b9a8SJean-Christophe PLAGNIOL-VILLARD data [1] = 3; 539*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return data [0]; 540*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 541*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 542*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* helper macro */ 543*2731b9a8SJean-Christophe PLAGNIOL-VILLARD #define OK(x) len = (x); break 544*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 545*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 546*2731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles all USB request to the the virtual root hub 547*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 548*2731b9a8SJean-Christophe PLAGNIOL-VILLARD static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe, 549*2731b9a8SJean-Christophe PLAGNIOL-VILLARD void *data, int buf_len, struct devrequest *cmd) 550*2731b9a8SJean-Christophe PLAGNIOL-VILLARD { 551*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 data_buf[16]; 552*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 *bufp = data_buf; 553*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int len = 0; 554*2731b9a8SJean-Christophe PLAGNIOL-VILLARD int status = 0; 555*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 556*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 bmRType_bReq; 557*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 wValue; 558*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 wIndex; 559*2731b9a8SJean-Christophe PLAGNIOL-VILLARD __u16 wLength; 560*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 561*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (usb_pipeint(pipe)) { 562*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(0, "interrupt transfer unimplemented!\n"); 563*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 564*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 565*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 566*2731b9a8SJean-Christophe PLAGNIOL-VILLARD bmRType_bReq = cmd->requesttype | (cmd->request << 8); 567*2731b9a8SJean-Christophe PLAGNIOL-VILLARD wValue = le16_to_cpu (cmd->value); 568*2731b9a8SJean-Christophe PLAGNIOL-VILLARD wIndex = le16_to_cpu (cmd->index); 569*2731b9a8SJean-Christophe PLAGNIOL-VILLARD wLength = le16_to_cpu (cmd->length); 570*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 571*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n", 572*2731b9a8SJean-Christophe PLAGNIOL-VILLARD bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength); 573*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 574*2731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Request Destination: 575*2731b9a8SJean-Christophe PLAGNIOL-VILLARD without flags: Device, 576*2731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_INTERFACE: interface, 577*2731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_ENDPOINT: endpoint, 578*2731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_TYPE_CLASS means HUB here, 579*2731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here 580*2731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 581*2731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (bmRType_bReq) { 582*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS: 583*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(1); 584*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2); 585*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 586*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_INTERFACE: 587*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(0); 588*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2); 589*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 590*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_ENDPOINT: 591*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u16 *)bufp = cpu_to_le16(0); 592*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(2); 593*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 594*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_TYPE_CLASS: 595*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u32 *)bufp = cpu_to_le32(0); 596*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(4); 597*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 598*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS: 599*2731b9a8SJean-Christophe PLAGNIOL-VILLARD *(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus); 600*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(4); 601*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 602*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT: 603*2731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) { 604*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case 1: 605*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 606*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 607*2731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 608*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 609*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_TYPE_CLASS: 610*2731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) { 611*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case C_HUB_LOCAL_POWER: 612*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 613*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 614*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case C_HUB_OVER_CURRENT: 615*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 616*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 617*2731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 618*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 619*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS: 620*2731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) { 621*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_ENABLE: 622*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE; 623*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 624*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 625*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_SUSPEND: 626*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND; 627*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 628*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 629*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_POWER: 630*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_POWER; 631*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 632*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 633*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_CONNECTION: 634*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION; 635*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 636*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 637*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_ENABLE: 638*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE; 639*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 640*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 641*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_SUSPEND: 642*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND; 643*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 644*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 645*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_OVER_CURRENT: 646*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT; 647*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 648*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 649*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_C_RESET: 650*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET; 651*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 652*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 653*2731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 654*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 655*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS: 656*2731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (wValue) { 657*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_SUSPEND: 658*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND; 659*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 660*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 661*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_RESET: 662*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_RESET; 663*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange = 0; 664*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortChange |= USB_PORT_STAT_C_RESET; 665*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus &= ~USB_PORT_STAT_RESET; 666*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_ENABLE; 667*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 668*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 669*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_POWER: 670*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_POWER; 671*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 672*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 673*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_PORT_FEAT_ENABLE: 674*2731b9a8SJean-Christophe PLAGNIOL-VILLARD rh_status.wPortStatus |= USB_PORT_STAT_ENABLE; 675*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 676*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 677*2731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 678*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 679*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_ADDRESS: 680*2731b9a8SJean-Christophe PLAGNIOL-VILLARD root_hub_devnum = wValue; 681*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 682*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 683*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_DESCRIPTOR: 684*2731b9a8SJean-Christophe PLAGNIOL-VILLARD switch ((wValue & 0xff00) >> 8) { 685*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_DEVICE: 686*2731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_dev_des); 687*2731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_dev_des; 688*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len); 689*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 690*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_CONFIG: 691*2731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_config_des); 692*2731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_config_des; 693*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len); 694*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 695*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DT_STRING: 696*2731b9a8SJean-Christophe PLAGNIOL-VILLARD len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength); 697*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (len > 0) { 698*2731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = data; 699*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len); 700*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 701*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 702*2731b9a8SJean-Christophe PLAGNIOL-VILLARD default: 703*2731b9a8SJean-Christophe PLAGNIOL-VILLARD status = -32; 704*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 705*2731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 706*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 707*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_DESCRIPTOR | USB_TYPE_CLASS: 708*2731b9a8SJean-Christophe PLAGNIOL-VILLARD len = sizeof(sl811_rh_hub_des); 709*2731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp = sl811_rh_hub_des; 710*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(len); 711*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 712*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_GET_CONFIGURATION: 713*2731b9a8SJean-Christophe PLAGNIOL-VILLARD bufp[0] = 0x01; 714*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(1); 715*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 716*2731b9a8SJean-Christophe PLAGNIOL-VILLARD case RH_SET_CONFIGURATION: 717*2731b9a8SJean-Christophe PLAGNIOL-VILLARD OK(0); 718*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 719*2731b9a8SJean-Christophe PLAGNIOL-VILLARD default: 720*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(1, "unsupported root hub command\n"); 721*2731b9a8SJean-Christophe PLAGNIOL-VILLARD status = -32; 722*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 723*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 724*2731b9a8SJean-Christophe PLAGNIOL-VILLARD len = min(len, buf_len); 725*2731b9a8SJean-Christophe PLAGNIOL-VILLARD if (data != bufp) 726*2731b9a8SJean-Christophe PLAGNIOL-VILLARD memcpy(data, bufp, len); 727*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 728*2731b9a8SJean-Christophe PLAGNIOL-VILLARD PDEBUG(5, "len = %d, status = %d\n", len, status); 729*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 730*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dev->status = status; 731*2731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_dev->act_len = len; 732*2731b9a8SJean-Christophe PLAGNIOL-VILLARD 733*2731b9a8SJean-Christophe PLAGNIOL-VILLARD return status == 0 ? len : status; 734*2731b9a8SJean-Christophe PLAGNIOL-VILLARD } 735