[PATCH] janitor: mark __init/__exit static drivers/net/ppp_deflate
[linux-2.6/history.git] / drivers / usb / host / hc_sl811_rh.c
blobaaaa705bccdf8c8c3c13b67ce2ea6d5f19c2b7a6
2 /*-------------------------------------------------------------------------*/
3 /*-------------------------------------------------------------------------*
4 * SL811HS virtual root hub
5 *
6 * based on usb-ohci.c by R. Weissgaerber et al.
7 *-------------------------------------------------------------------------*
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *-------------------------------------------------------------------------*/
24 /* FIXME: reuse the root hub framework in usbcore, shrinking this code. */
26 #ifdef DEBUG
27 #undef DEBUG
28 #endif
29 static __u32 getPortStatusAndChange (hci_t * hci);
30 static void setPortStatus (hci_t * hci, __u16 bitPos);
31 static void setPortChange (hci_t * hci, __u16 bitPos);
32 static void clrPortStatus (hci_t * hci, __u16 bitPos);
33 static void clrPortChange (hci_t * hci, __u16 bitPos);
34 static int USBReset (hci_t * hci);
35 static int cc_to_error (int cc);
37 /*-------------------------------------------------------------------------*
38 * Virtual Root Hub
39 *-------------------------------------------------------------------------*/
41 /* Device descriptor */
42 static __u8 root_hub_dev_des[] = {
43 0x12, /* __u8 bLength; */
44 0x01, /* __u8 bDescriptorType; Device */
45 0x10, /* __u16 bcdUSB; v1.1 */
46 0x01,
47 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
48 0x00, /* __u8 bDeviceSubClass; */
49 0x00, /* __u8 bDeviceProtocol; */
50 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
51 0x00, /* __u16 idVendor; */
52 0x00,
53 0x00, /* __u16 idProduct; */
54 0x00,
55 0x00, /* __u16 bcdDevice; */
56 0x00,
57 0x00, /* __u8 iManufacturer; */
58 0x02, /* __u8 iProduct; */
59 0x01, /* __u8 iSerialNumber; */
60 0x01 /* __u8 bNumConfigurations; */
63 /* Configuration descriptor */
64 static __u8 root_hub_config_des[] = {
65 0x09, /* __u8 bLength; */
66 0x02, /* __u8 bDescriptorType; Configuration */
67 0x19, /* __u16 wTotalLength; */
68 0x00,
69 0x01, /* __u8 bNumInterfaces; */
70 0x01, /* __u8 bConfigurationValue; */
71 0x00, /* __u8 iConfiguration; */
72 0x40, /* __u8 bmAttributes;
73 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
74 4..0: resvd */
75 0x00, /* __u8 MaxPower; */
77 /* interface */
78 0x09, /* __u8 if_bLength; */
79 0x04, /* __u8 if_bDescriptorType; Interface */
80 0x00, /* __u8 if_bInterfaceNumber; */
81 0x00, /* __u8 if_bAlternateSetting; */
82 0x01, /* __u8 if_bNumEndpoints; */
83 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
84 0x00, /* __u8 if_bInterfaceSubClass; */
85 0x00, /* __u8 if_bInterfaceProtocol; */
86 0x00, /* __u8 if_iInterface; */
88 /* endpoint */
89 0x07, /* __u8 ep_bLength; */
90 0x05, /* __u8 ep_bDescriptorType; Endpoint */
91 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
92 0x03, /* __u8 ep_bmAttributes; Interrupt */
93 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
94 0x00,
95 0xff /* __u8 ep_bInterval; 255 ms */
98 /* Hub class-specific descriptor is constructed dynamically */
100 /***************************************************************************
101 * Function Name : rh_send_irq
103 * This function examine the port change in the virtual root hub.
105 * Note: This function assumes only one port exist in the root hub.
107 * Input: hci = data structure for the host controller
108 * rh_data = The pointer to port change data
109 * rh_len = length of the data in bytes
111 * Return: length of data
112 **************************************************************************/
113 static int rh_send_irq (hci_t * hci, void *rh_data, int rh_len)
115 int num_ports;
116 int i;
117 int ret;
118 int len;
119 __u8 data[8];
121 DBGFUNC ("enter rh_send_irq: \n");
123 /* Assuming the root hub has one port. This value need to change if
124 * there are more than one port for the root hub
127 num_ports = 1;
129 /* The root hub status is not implemented, it basically has two fields:
130 * -- Local Power Status
131 * -- Over Current Indicator
132 * -- Local Power Change
133 * -- Over Current Indicator
135 * Right now, It is assume the power is good and no changes
138 *(__u8 *) data = 0;
140 ret = *(__u8 *) data;
142 /* Has the port status change within the root hub: It checks for
143 * -- Port Connect Status change
144 * -- Port Enable Change
147 for (i = 0; i < num_ports; i++) {
148 *(__u8 *) (data + (i + 1) / 8) |=
149 (((getPortStatusAndChange (hci) >> 16) & (PORT_CONNECT_STAT | PORT_ENABLE_STAT)) ? 1 : 0) << ((i + 1) % 8);
150 ret += *(__u8 *) (data + (i + 1) / 8);
152 /* After the port change is read, it should be reset so the next time
153 * is it doesn't trigger a change again */
156 len = i / 8 + 1;
158 if (ret > 0) {
159 memcpy (rh_data, data, min (len, min (rh_len, (int)sizeof (data))));
160 return len;
162 return 0;
165 /***************************************************************************
166 * Function Name : rh_int_timer_do
168 * This function is called when the timer expires. It gets the the port
169 * change data and pass along to the upper protocol.
171 * Note: The virtual root hub interrupt pipe are polled by the timer
172 * every "interval" ms
174 * Input: ptr = ptr to the urb
176 * Return: none
177 **************************************************************************/
178 static void rh_int_timer_do (unsigned long ptr)
180 int len;
181 struct urb *urb = (struct urb *) ptr;
182 hci_t *hci = urb->dev->bus->hcpriv;
184 DBGFUNC ("enter rh_int_timer_do\n");
186 if (hci->rh.send) {
187 len = rh_send_irq (hci, urb->transfer_buffer,
188 urb->transfer_buffer_length);
189 if (len > 0) {
190 urb->actual_length = len;
191 if (urb_debug == 2)
192 urb_print (urb, "RET-t(rh)",
193 usb_pipeout (urb->pipe));
195 if (urb->complete) {
196 urb->complete (urb, NULL);
201 /* re-activate the timer */
202 rh_init_int_timer (urb);
205 /***************************************************************************
206 * Function Name : rh_init_int_timer
208 * This function creates a timer that act as interrupt pipe in the
209 * virtual hub.
211 * Note: The virtual root hub's interrupt pipe are polled by the timer
212 * every "interval" ms
214 * Input: urb = USB request block
216 * Return: 0
217 **************************************************************************/
218 static int rh_init_int_timer (struct urb * urb)
220 hci_t *hci = urb->dev->bus->hcpriv;
221 hci->rh.interval = urb->interval;
223 init_timer (&hci->rh.rh_int_timer);
224 hci->rh.rh_int_timer.function = rh_int_timer_do;
225 hci->rh.rh_int_timer.data = (unsigned long) urb;
226 hci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
227 add_timer (&hci->rh.rh_int_timer);
229 return 0;
232 /*-------------------------------------------------------------------------*/
234 /* for returning string descriptors in UTF-16LE */
235 static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
237 int retval;
239 for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
240 *utf++ = *ascii++ & 0x7f;
241 *utf++ = 0;
243 return retval;
246 static int root_hub_string (int id, int serial, char *type, __u8 *data, int len)
248 char buf [30];
250 // assert (len > (2 * (sizeof (buf) + 1)));
251 // assert (strlen (type) <= 8);
253 // language ids
254 if (id == 0) {
255 *data++ = 4; *data++ = 3; /* 4 bytes data */
256 *data++ = 0; *data++ = 0; /* some language id */
257 return 4;
259 // serial number
260 } else if (id == 1) {
261 sprintf (buf, "%x", serial);
263 // product description
264 } else if (id == 2) {
265 sprintf (buf, "USB %s Root Hub", type);
267 // id 3 == vendor description
269 // unsupported IDs --> "stall"
270 } else
271 return 0;
273 data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
274 data [1] = 3;
275 return data [0];
278 /*-------------------------------------------------------------------------*/
280 /* helper macro */
281 #define OK(x) len = (x); break
283 /***************************************************************************
284 * Function Name : rh_submit_urb
286 * This function handles all USB request to the the virtual root hub
288 * Input: urb = USB request block
290 * Return: 0
291 **************************************************************************/
292 static int rh_submit_urb (struct urb * urb)
294 struct usb_device *usb_dev = urb->dev;
295 hci_t *hci = usb_dev->bus->hcpriv;
296 unsigned int pipe = urb->pipe;
297 struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
298 void *data = urb->transfer_buffer;
299 int leni = urb->transfer_buffer_length;
300 int len = 0;
301 int status = TD_CC_NOERROR;
302 __u32 datab[4];
303 __u8 *data_buf = (__u8 *) datab;
305 __u16 bmRType_bReq;
306 __u16 wValue;
307 __u16 wIndex;
308 __u16 wLength;
310 DBGFUNC ("enter rh_submit_urb\n");
311 if (usb_pipeint (pipe)) {
312 hci->rh.urb = urb;
313 hci->rh.send = 1;
314 hci->rh.interval = urb->interval;
315 rh_init_int_timer (urb);
316 urb->status = cc_to_error (TD_CC_NOERROR);
318 return 0;
321 bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
322 wValue = le16_to_cpu (cmd->wValue);
323 wIndex = le16_to_cpu (cmd->wIndex);
324 wLength = le16_to_cpu (cmd->wLength);
326 DBG ("rh_submit_urb, req = %d(%x) len=%d",
327 bmRType_bReq, bmRType_bReq, wLength);
329 switch (bmRType_bReq) {
330 /* Request Destination:
331 without flags: Device,
332 RH_INTERFACE: interface,
333 RH_ENDPOINT: endpoint,
334 RH_CLASS means HUB here,
335 RH_OTHER | RH_CLASS almost ever means HUB_PORT here
338 case RH_GET_STATUS:
339 *(__u16 *) data_buf = cpu_to_le16 (1);
340 OK (2);
342 case RH_GET_STATUS | RH_INTERFACE:
343 *(__u16 *) data_buf = cpu_to_le16 (0);
344 OK (2);
346 case RH_GET_STATUS | RH_ENDPOINT:
347 *(__u16 *) data_buf = cpu_to_le16 (0);
348 OK (2);
350 case RH_GET_STATUS | RH_CLASS:
351 *(__u32 *) data_buf = cpu_to_le32 (0);
352 OK (4);
354 case RH_GET_STATUS | RH_OTHER | RH_CLASS:
355 *(__u32 *) data_buf =
356 cpu_to_le32 (getPortStatusAndChange (hci));
357 OK (4);
359 case RH_CLEAR_FEATURE | RH_ENDPOINT:
360 switch (wValue) {
361 case (RH_ENDPOINT_STALL):
362 OK (0);
364 break;
366 case RH_CLEAR_FEATURE | RH_CLASS:
367 switch (wValue) {
368 case RH_C_HUB_LOCAL_POWER:
369 OK (0);
371 case (RH_C_HUB_OVER_CURRENT):
372 /* Over Current Not Implemented */
373 OK (0);
375 break;
377 case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
378 switch (wValue) {
379 case (RH_PORT_ENABLE):
380 clrPortStatus (hci, PORT_ENABLE_STAT);
381 OK (0);
383 case (RH_PORT_SUSPEND):
384 clrPortStatus (hci, PORT_SUSPEND_STAT);
385 OK (0);
387 case (RH_PORT_POWER):
388 clrPortStatus (hci, PORT_POWER_STAT);
389 OK (0);
391 case (RH_C_PORT_CONNECTION):
392 clrPortChange (hci, PORT_CONNECT_STAT);
393 OK (0);
395 case (RH_C_PORT_ENABLE):
396 clrPortChange (hci, PORT_ENABLE_STAT);
397 OK (0);
399 case (RH_C_PORT_SUSPEND):
400 clrPortChange (hci, PORT_SUSPEND_STAT);
401 OK (0);
403 case (RH_C_PORT_OVER_CURRENT):
404 clrPortChange (hci, PORT_OVER_CURRENT_STAT);
405 OK (0);
407 case (RH_C_PORT_RESET):
408 clrPortChange (hci, PORT_RESET_STAT);
409 OK (0);
411 break;
413 case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
414 switch (wValue) {
415 case (RH_PORT_SUSPEND):
416 setPortStatus (hci, PORT_SUSPEND_STAT);
417 OK (0);
419 case (RH_PORT_RESET):
420 setPortStatus (hci, PORT_RESET_STAT);
421 // USBReset(hci);
422 clrPortChange (hci,
423 PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE
424 | PORT_SUSPEND_CHANGE |
425 PORT_OVER_CURRENT_CHANGE);
426 setPortChange (hci, PORT_RESET_CHANGE);
427 clrPortStatus (hci, PORT_RESET_STAT);
428 setPortStatus (hci, PORT_ENABLE_STAT);
430 OK (0);
432 case (RH_PORT_POWER):
433 setPortStatus (hci, PORT_POWER_STAT);
434 OK (0);
436 case (RH_PORT_ENABLE):
437 setPortStatus (hci, PORT_ENABLE_STAT);
438 OK (0);
440 break;
442 case RH_SET_ADDRESS:
443 hci->rh.devnum = wValue;
444 OK (0);
446 case RH_GET_DESCRIPTOR:
447 DBGVERBOSE ("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue);
448 switch ((wValue & 0xff00) >> 8) {
449 case (0x01): /* device descriptor */
450 len = min (leni, min ((__u16)sizeof (root_hub_dev_des), wLength));
451 data_buf = root_hub_dev_des;
452 OK (len);
454 case (0x02): /* configuration descriptor */
455 len = min (leni, min ((__u16)sizeof (root_hub_config_des), wLength));
456 data_buf = root_hub_config_des;
457 OK (len);
459 case (0x03): /* string descriptors */
460 len = root_hub_string (wValue & 0xff, (int) (long) 0,
461 "SL811HS", data, wLength);
462 if (len > 0) {
463 data_buf = data;
464 OK (min (leni, len));
467 default:
468 status = SL11H_STATMASK_STALL;
470 break;
472 case RH_GET_DESCRIPTOR | RH_CLASS:
473 data_buf[0] = 9; // min length;
474 data_buf[1] = 0x29;
475 data_buf[2] = 1; // # of downstream port
476 data_buf[3] = 0;
477 datab[1] = 0;
478 data_buf[5] = 50; // 100 ms for port reset
479 data_buf[7] = 0xfc; // which port is attachable
480 if (data_buf[2] < 7) {
481 data_buf[8] = 0xff;
482 } else {
485 len = min (leni, min ((__u16)data_buf[0], wLength));
486 OK (len);
488 case RH_GET_CONFIGURATION:
489 *(__u8 *) data_buf = 0x01;
490 OK (1);
492 case RH_SET_CONFIGURATION:
493 OK (0);
495 default:
496 DBGERR ("unsupported root hub command");
497 status = SL11H_STATMASK_STALL;
500 len = min (len, leni);
501 if (data != data_buf)
502 memcpy (data, data_buf, len);
503 urb->actual_length = len;
504 urb->status = cc_to_error (status);
506 urb->hcpriv = NULL;
507 urb->dev = NULL;
508 if (urb->complete) {
509 urb->complete (urb, NULL);
512 return 0;
515 /***************************************************************************
516 * Function Name : rh_unlink_urb
518 * This function unlinks the URB
520 * Input: urb = USB request block
522 * Return: 0
523 **************************************************************************/
524 static int rh_unlink_urb (struct urb * urb)
526 hci_t *hci = urb->dev->bus->hcpriv;
528 DBGFUNC ("enter rh_unlink_urb\n");
529 if (hci->rh.urb == urb) {
530 hci->rh.send = 0;
531 del_timer (&hci->rh.rh_int_timer);
532 hci->rh.urb = NULL;
534 urb->hcpriv = NULL;
535 usb_put_dev (urb->dev);
536 urb->dev = NULL;
537 if (urb->transfer_flags & URB_ASYNC_UNLINK) {
538 urb->status = -ECONNRESET;
539 if (urb->complete) {
540 urb->complete (urb, NULL);
542 } else
543 urb->status = -ENOENT;
545 return 0;
548 /***************************************************************************
549 * Function Name : rh_connect_rh
551 * This function connect the virtual root hub to the USB stack
553 * Input: urb = USB request block
555 * Return: 0
556 **************************************************************************/
557 static int rh_connect_rh (hci_t * hci)
559 struct usb_device *usb_dev;
560 int retval;
562 hci->rh.devnum = 0;
563 usb_dev = usb_alloc_dev (NULL, hci->bus, 0);
564 if (!usb_dev)
565 return -ENOMEM;
567 usb_dev->devnum = 1;
568 usb_dev->bus->devnum_next = usb_dev->devnum + 1;
569 set_bit (usb_dev->devnum, usb_dev->bus->devmap.devicemap);
571 down (&usb_bus_list_lock);
572 hci->bus->root_hub = usb_dev;
573 retval = usb_new_device (usb_dev);
574 if (retval != 0)
575 hci->bus->root_hub = NULL;
576 up (&usb_bus_list_lock);
577 if (retval != 0) {
578 usb_put_dev (usb_dev);
579 return -ENODEV;
582 return 0;