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