1 // Code for handling standard USB hubs.
3 // Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
7 #include "util.h" // dprintf
8 #include "config.h" // CONFIG_USB_HUB
9 #include "usb-hub.h" // struct usb_hub_descriptor
10 #include "usb.h" // struct usb_s
13 get_hub_desc(struct usb_hub_descriptor *desc, u32 endp)
15 struct usb_ctrlrequest req;
16 req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE;
17 req.bRequest = USB_REQ_GET_DESCRIPTOR;
18 req.wValue = USB_DT_HUB<<8;
20 req.wLength = sizeof(*desc);
21 return send_default_control(endp, &req, desc);
25 set_port_feature(int port, int feature, u32 endp)
27 struct usb_ctrlrequest req;
28 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
29 req.bRequest = USB_REQ_SET_FEATURE;
33 return send_default_control(endp, &req, NULL);
37 clear_port_feature(int port, int feature, u32 endp)
39 struct usb_ctrlrequest req;
40 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
41 req.bRequest = USB_REQ_CLEAR_FEATURE;
45 return send_default_control(endp, &req, NULL);
49 get_port_status(int port, struct usb_port_status *sts, u32 endp)
51 struct usb_ctrlrequest req;
52 req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
53 req.bRequest = USB_REQ_GET_STATUS;
56 req.wLength = sizeof(*sts);
57 return send_default_control(endp, &req, sts);
60 // Configure a usb hub and then find devices connected to it.
62 usb_hub_init(u32 endp)
67 struct usb_hub_descriptor desc;
68 int ret = get_hub_desc(&desc, endp);
72 // Turn on power to all ports.
74 for (i=1; i<=desc.bNbrPorts; i++) {
75 ret = set_port_feature(i, USB_PORT_FEAT_POWER, endp);
80 // Wait for port detection.
81 msleep(desc.bPwrOn2PwrGood * 2 + USB_TIME_SIGATT);
82 // XXX - should poll for ports becoming active sooner and then
83 // possibly wait USB_TIME_ATTDB.
85 // Detect down stream devices.
86 struct usb_s *cntl = endp2cntl(endp);
88 for (i=1; i<=desc.bNbrPorts; i++) {
89 struct usb_port_status sts;
90 ret = get_port_status(i, &sts, endp);
93 if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
94 // XXX - power down port?
98 ret = set_port_feature(i, USB_PORT_FEAT_RESET, endp);
102 // Wait for reset to complete.
103 u64 end = calc_future_tsc(USB_TIME_DRST * 2);
105 ret = get_port_status(i, &sts, endp);
108 if (!(sts.wPortStatus & USB_PORT_STAT_RESET))
110 if (check_time(end)) {
117 if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
118 // Device no longer present. XXX - power down port?
121 // XXX - should try to parallelize configuration.
122 int count = configure_usb_device(
123 cntl, !!(sts.wPortStatus & USB_PORT_STAT_LOW_SPEED));
126 ret = clear_port_feature(i, USB_PORT_FEAT_ENABLE, endp);
136 dprintf(1, "Failure on hub setup\n");