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