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