4 * This is horrible, it knows about the UHCI driver
5 * internals, but it's just meant as a rough example,
6 * let's do the virtualization later when this works.
8 * (C) Copyright 1999 Linus Torvalds
9 * (C) Copyright 1999 Johannes Erdfelt
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/list.h>
15 #include <linux/malloc.h>
16 #include <linux/smp_lock.h>
18 #include <asm/spinlock.h>
24 extern struct usb_operations uhci_device_operations
;
27 static DECLARE_WAIT_QUEUE_HEAD(usb_hub_wait
);
28 static spinlock_t hub_event_lock
= SPIN_LOCK_UNLOCKED
;
30 /* List of hubs needing servicing */
31 static struct list_head hub_event_list
;
34 static int khubd_pid
= 0;
37 * A irq handler returns non-zero to indicate to
38 * the low-level driver that it wants to be re-activated,
39 * or zero to say "I'm done".
41 static int hub_irq(int status
, void *__buffer
, void *dev_id
)
43 struct usb_hub
*hub
= dev_id
;
46 if (waitqueue_active(&usb_hub_wait
)) {
47 /* Add the hub to the event queue */
48 spin_lock_irqsave(&hub_event_lock
, flags
);
49 if (hub
->event_list
.next
== &hub
->event_list
) {
50 list_add(&hub
->event_list
, &hub_event_list
);
52 wake_up(&usb_hub_wait
);
54 spin_unlock_irqrestore(&hub_event_lock
, flags
);
60 static void usb_hub_configure(struct usb_hub
*hub
)
62 struct usb_device
*dev
= hub
->dev
;
63 unsigned char hubdescriptor
[8], buf
[4];
66 usb_set_configuration(dev
, dev
->config
[0].bConfigurationValue
);
68 if (usb_get_hub_descriptor(dev
, hubdescriptor
, 8))
71 hub
->nports
= dev
->maxchild
= hubdescriptor
[2];
72 printk("hub: %d-port%s detected\n", hub
->nports
,
73 (hub
->nports
== 1) ? "" : "s");
75 charac
= (hubdescriptor
[4] << 8) + hubdescriptor
[3];
76 switch (charac
& HUB_CHAR_LPSM
) {
78 printk("hub: ganged power switching\n");
81 printk("hub: individual port power switching\n");
85 printk("hub: unknown reserved power switching mode\n");
89 if (charac
& HUB_CHAR_COMPOUND
)
90 printk("hub: part of a compound device\n");
92 printk("hub: standalone hub\n");
94 switch (charac
& HUB_CHAR_OCPM
) {
96 printk("hub: global over current protection\n");
99 printk("hub: individual port over current protection\n");
103 printk("hub: no over current protection\n");
107 printk("hub: power on to power good time: %dms\n",
108 hubdescriptor
[5] * 2);
110 printk("hub: hub controller current requirement: %dmA\n",
113 for (i
= 0; i
< dev
->maxchild
; i
++)
114 printk("hub: port %d is%s removable\n", i
+ 1,
115 hubdescriptor
[7 + ((i
+ 1)/8)] & (1 << ((i
+ 1) % 8))
118 if (usb_get_hub_status(dev
, buf
))
121 printk("hub: local power source is %s\n",
122 (buf
[0] & 1) ? "lost (inactive)" : "good");
124 printk("hub: %sover current condition exists\n",
125 (buf
[0] & 2) ? "" : "no ");
128 for (i
= 0; i
< hub
->nports
; i
++) {
129 int portstat
, portchange
;
130 unsigned char portstatus
[4];
132 if (usb_get_port_status(dev
, i
+ 1, portstatus
))
134 portstat
= (portstatus
[1] << 8) + portstatus
[0];
135 portchange
= (portstatus
[3] << 8) + portstatus
[2];
137 printk("hub: port %d status\n", i
+ 1);
138 printk("hub: %sdevice present\n", (portstat
& 1) ? "" : "no ");
139 printk("hub: %s\n", (portstat
& 2) ? "enabled" : "disabled");
140 printk("hub: %ssuspended\n", (portstat
& 4) ? "" : "not ");
141 printk("hub: %sover current\n", (portstat
& 8) ? "" : "not ");
142 printk("hub: has %spower\n", (portstat
& 0x100) ? "" : "no ");
143 printk("hub: %s speed\n", (portstat
& 0x200) ? "low" : "full");
147 /* Enable power to the ports */
148 printk("enabling power on all ports\n");
149 for (i
= 0; i
< hub
->nports
; i
++)
150 usb_set_port_feature(dev
, i
+ 1, USB_PORT_FEAT_POWER
);
153 static int hub_probe(struct usb_device
*dev
)
155 struct usb_interface_descriptor
*interface
;
156 struct usb_endpoint_descriptor
*endpoint
;
159 /* We don't handle multi-config hubs */
160 if (dev
->descriptor
.bNumConfigurations
!= 1)
163 /* We don't handle multi-interface hubs */
164 if (dev
->config
[0].bNumInterfaces
!= 1)
167 interface
= &dev
->config
[0].interface
[0];
170 if (interface
->bInterfaceClass
!= 9)
172 if ((interface
->bInterfaceSubClass
!= 0) &&
173 (interface
->bInterfaceSubClass
!= 1))
176 /* Multiple endpoints? What kind of mutant ninja-hub is this? */
177 if (interface
->bNumEndpoints
!= 1)
180 endpoint
= &interface
->endpoint
[0];
182 /* Output endpoint? Curiousier and curiousier.. */
183 if (!(endpoint
->bEndpointAddress
& 0x80))
186 /* If it's not an interrupt endpoint, we'd better punt! */
187 if ((endpoint
->bmAttributes
& 3) != 3)
191 printk("USB hub found\n");
193 if ((hub
= kmalloc(sizeof(*hub
), GFP_KERNEL
)) == NULL
) {
194 printk("couldn't kmalloc hub struct\n");
198 memset(hub
, 0, sizeof(*hub
));
202 INIT_LIST_HEAD(&hub
->event_list
);
205 usb_hub_configure(hub
);
207 usb_request_irq(dev
, usb_rcvctrlpipe(dev
, endpoint
->bEndpointAddress
), hub_irq
, endpoint
->bInterval
, hub
);
210 wake_up(&usb_hub_wait
);
215 static void hub_disconnect(struct usb_device
*dev
)
217 struct usb_hub
*hub
= dev
->private;
220 spin_lock_irqsave(&hub_event_lock
, flags
);
222 /* Delete it and then reset it */
223 list_del(&hub
->event_list
);
224 INIT_LIST_HEAD(&hub
->event_list
);
226 spin_unlock_irqrestore(&hub_event_lock
, flags
);
228 /* Free the memory */
232 static void usb_hub_port_connect_change(struct usb_device
*hub
, int port
)
234 struct usb_device
*usb
;
235 unsigned char buf
[4];
236 unsigned short portstatus
, portchange
;
238 usb_disconnect(&hub
->children
[port
]);
240 usb_set_port_feature(hub
, port
+ 1, USB_PORT_FEAT_RESET
);
242 wait_ms(50); /* FIXME: This is from the *BSD stack, thanks! :) */
244 if (usb_get_port_status(hub
, port
+ 1, buf
)) {
245 printk("get_port_status failed\n");
249 portstatus
= *((unsigned short *)buf
+ 0);
250 portchange
= *((unsigned short *)buf
+ 1);
252 if ((!(portstatus
& USB_PORT_STAT_CONNECTION
)) &&
253 (!(portstatus
& USB_PORT_STAT_ENABLE
))) {
254 /* We're done now, we already disconnected the device */
255 /* printk("not connected/enabled\n"); */
259 usb
= hub
->bus
->op
->allocate(hub
);
261 printk("couldn't allocate usb_device\n");
267 usb
->slow
= (portstatus
& USB_PORT_STAT_LOW_SPEED
) ? 1 : 0;
269 hub
->children
[port
] = usb
;
274 static void usb_hub_events(void)
277 unsigned char buf
[4];
278 unsigned short portstatus
, portchange
;
280 struct list_head
*next
, *tmp
, *head
= &hub_event_list
;
281 struct usb_device
*dev
;
284 spin_lock_irqsave(&hub_event_lock
, flags
);
287 while (tmp
!= head
) {
288 hub
= list_entry(tmp
, struct usb_hub
, event_list
);
296 for (i
= 0; i
< hub
->nports
; i
++) {
297 if (usb_get_port_status(dev
, i
+ 1, buf
)) {
298 printk("get_port_status failed\n");
302 portstatus
= *((unsigned short *)buf
+ 0);
303 portchange
= *((unsigned short *)buf
+ 1);
305 if (portchange
& USB_PORT_STAT_C_CONNECTION
) {
306 printk("hub: port %d connection change\n", i
+ 1);
308 usb_clear_port_feature(dev
, i
+ 1,
309 USB_PORT_FEAT_C_CONNECTION
);
311 usb_hub_port_connect_change(dev
, i
);
314 if (portchange
& USB_PORT_STAT_C_ENABLE
) {
315 printk("hub: port %d enable change\n", i
+ 1);
316 usb_clear_port_feature(dev
, i
+ 1,
317 USB_PORT_FEAT_C_ENABLE
);
320 if (portchange
& USB_PORT_STAT_C_SUSPEND
)
321 printk("hub: port %d suspend change\n", i
+ 1);
323 if (portchange
& USB_PORT_STAT_C_OVERCURRENT
)
324 printk("hub: port %d over-current change\n", i
+ 1);
326 if (portchange
& USB_PORT_STAT_C_RESET
) {
327 printk("hub: port %d reset change\n", i
+ 1);
328 usb_clear_port_feature(dev
, i
+ 1,
329 USB_PORT_FEAT_C_RESET
);
336 if (usb_get_port_status(dev
, i
+ 1, buf
))
339 portstatus
= (buf
[1] << 8) + buf
[0];
340 portchange
= (buf
[3] << 8) + buf
[2];
342 printk("hub: port %d status\n", i
+ 1);
343 printk("hub: %sdevice present\n", (portstatus
& 1) ? "" : "no ");
344 printk("hub: %s\n", (portstatus
& 2) ? "enabled" : "disabled");
345 printk("hub: %ssuspended\n", (portstatus
& 4) ? "" : "not ");
346 printk("hub: %sover current\n", (portstatus
& 8) ? "" : "not ");
347 printk("hub: has %spower\n", (portstatus
& 0x100) ? "" : "no ");
348 printk("hub: %s speed\n", (portstatus
& 0x200) ? "low" : "full");
357 spin_unlock_irqrestore(&hub_event_lock
, flags
);
360 static int usb_hub_thread(void *__hub
)
365 * This thread doesn't need any user-level access,
366 * so get rid of all our resources
368 printk("usb_hub_thread at %p\n", &usb_hub_thread
);
373 /* Setup a nice name */
374 strcpy(current
->comm
, "khubd");
376 /* Send me a signal to get me die (for debugging) */
378 interruptible_sleep_on(&usb_hub_wait
);
380 } while (!signal_pending(current
));
382 printk("usb_hub_thread exiting\n");
387 static struct usb_driver hub_driver
= {
395 * This should be a separate module.
401 INIT_LIST_HEAD(&hub_event_list
);
403 usb_register(&hub_driver
);
404 pid
= kernel_thread(usb_hub_thread
, NULL
, CLONE_FS
| CLONE_FILES
| CLONE_SIGHAND
);
410 /* Fall through if kernel_thread failed */
411 usb_deregister(&hub_driver
);
416 void hub_cleanup(void)
419 kill_proc(khubd_pid
, SIGINT
, 1);
421 usb_deregister(&hub_driver
);