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_pipe *pipe, struct usb_hub_descriptor *desc)
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(pipe, &req, desc);
25 set_port_feature(struct usbhub_s *hub, int port, int feature)
27 struct usb_ctrlrequest req;
28 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
29 req.bRequest = USB_REQ_SET_FEATURE;
31 req.wIndex = port + 1;
33 mutex_lock(&hub->lock);
34 int ret = send_default_control(hub->pipe, &req, NULL);
35 mutex_unlock(&hub->lock);
40 clear_port_feature(struct usbhub_s *hub, int port, int feature)
42 struct usb_ctrlrequest req;
43 req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
44 req.bRequest = USB_REQ_CLEAR_FEATURE;
46 req.wIndex = port + 1;
48 mutex_lock(&hub->lock);
49 int ret = send_default_control(hub->pipe, &req, NULL);
50 mutex_unlock(&hub->lock);
55 get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts)
57 struct usb_ctrlrequest req;
58 req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
59 req.bRequest = USB_REQ_GET_STATUS;
61 req.wIndex = port + 1;
62 req.wLength = sizeof(*sts);
63 mutex_lock(&hub->lock);
64 int ret = send_default_control(hub->pipe, &req, sts);
65 mutex_unlock(&hub->lock);
69 // Check if device attached to port
71 usb_hub_detect(struct usbhub_s *hub, u32 port)
73 // Turn on power to port.
74 int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER);
78 // Wait for port power to stabilize.
79 msleep(hub->powerwait);
81 // Check periodically for a device connect.
82 struct usb_port_status sts;
83 u64 end = calc_future_tsc(USB_TIME_SIGATT);
85 ret = get_port_status(hub, port, &sts);
88 if (sts.wPortStatus & USB_PORT_STAT_CONNECTION)
97 // XXX - wait USB_TIME_ATTDB time?
102 dprintf(1, "Failure on hub port %d detect\n", port);
108 usb_hub_disconnect(struct usbhub_s *hub, u32 port)
110 int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE);
112 dprintf(1, "Failure on hub port %d disconnect\n", port);
115 // Reset device on port
117 usb_hub_reset(struct usbhub_s *hub, u32 port)
119 int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET);
123 // Wait for reset to complete.
124 struct usb_port_status sts;
125 u64 end = calc_future_tsc(USB_TIME_DRST * 2);
127 ret = get_port_status(hub, port, &sts);
130 if (!(sts.wPortStatus & USB_PORT_STAT_RESET))
132 if (check_tsc(end)) {
140 if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
141 // Device no longer present
144 return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK)
145 >> USB_PORT_STAT_SPEED_SHIFT);
148 dprintf(1, "Failure on hub port %d reset\n", port);
149 usb_hub_disconnect(hub, port);
153 static struct usbhub_op_s HubOp = {
154 .detect = usb_hub_detect,
155 .reset = usb_hub_reset,
156 .disconnect = usb_hub_disconnect,
159 // Configure a usb hub and then find devices connected to it.
161 usb_hub_init(struct usb_pipe *pipe)
167 struct usb_hub_descriptor desc;
168 int ret = get_hub_desc(pipe, &desc);
173 memset(&hub, 0, sizeof(hub));
175 hub.cntl = pipe->cntl;
176 hub.powerwait = desc.bPwrOn2PwrGood * 2;
177 hub.portcount = desc.bNbrPorts;
181 dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount);