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