|
|
1.1 root 1: // Code for handling standard USB hubs.
2: //
3: // Copyright (C) 2010 Kevin O'Connor <[email protected]>
4: //
5: // This file may be distributed under the terms of the GNU LGPLv3 license.
6:
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
11:
12: static int
13: get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc)
14: {
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;
19: req.wIndex = 0;
20: req.wLength = sizeof(*desc);
21: return send_default_control(pipe, &req, desc);
22: }
23:
24: static int
25: set_port_feature(struct usbhub_s *hub, int port, int feature)
26: {
27: struct usb_ctrlrequest req;
28: req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
29: req.bRequest = USB_REQ_SET_FEATURE;
30: req.wValue = feature;
31: req.wIndex = port + 1;
32: req.wLength = 0;
33: mutex_lock(&hub->lock);
34: int ret = send_default_control(hub->pipe, &req, NULL);
35: mutex_unlock(&hub->lock);
36: return ret;
37: }
38:
39: static int
40: clear_port_feature(struct usbhub_s *hub, int port, int feature)
41: {
42: struct usb_ctrlrequest req;
43: req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
44: req.bRequest = USB_REQ_CLEAR_FEATURE;
45: req.wValue = feature;
46: req.wIndex = port + 1;
47: req.wLength = 0;
48: mutex_lock(&hub->lock);
49: int ret = send_default_control(hub->pipe, &req, NULL);
50: mutex_unlock(&hub->lock);
51: return ret;
52: }
53:
54: static int
55: get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts)
56: {
57: struct usb_ctrlrequest req;
58: req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
59: req.bRequest = USB_REQ_GET_STATUS;
60: req.wValue = 0;
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);
66: return ret;
67: }
68:
69: // Check if device attached to port
70: static int
71: usb_hub_detect(struct usbhub_s *hub, u32 port)
72: {
73: // Turn on power to port.
74: int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER);
75: if (ret)
76: goto fail;
77:
78: // Wait for port power to stabilize.
79: msleep(hub->powerwait);
80:
81: // Check periodically for a device connect.
82: struct usb_port_status sts;
83: u64 end = calc_future_tsc(USB_TIME_SIGATT);
84: for (;;) {
85: ret = get_port_status(hub, port, &sts);
86: if (ret)
87: goto fail;
88: if (sts.wPortStatus & USB_PORT_STAT_CONNECTION)
89: // Device connected.
90: break;
91: if (check_tsc(end))
92: // No device found.
93: return -1;
94: msleep(5);
95: }
96:
97: // XXX - wait USB_TIME_ATTDB time?
98:
99: return 0;
100:
101: fail:
102: dprintf(1, "Failure on hub port %d detect\n", port);
103: return -1;
104: }
105:
106: // Disable port
107: static void
108: usb_hub_disconnect(struct usbhub_s *hub, u32 port)
109: {
110: int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE);
111: if (ret)
112: dprintf(1, "Failure on hub port %d disconnect\n", port);
113: }
114:
115: // Reset device on port
116: static int
117: usb_hub_reset(struct usbhub_s *hub, u32 port)
118: {
119: int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET);
120: if (ret)
121: goto fail;
122:
123: // Wait for reset to complete.
124: struct usb_port_status sts;
125: u64 end = calc_future_tsc(USB_TIME_DRST * 2);
126: for (;;) {
127: ret = get_port_status(hub, port, &sts);
128: if (ret)
129: goto fail;
130: if (!(sts.wPortStatus & USB_PORT_STAT_RESET))
131: break;
132: if (check_tsc(end)) {
133: warn_timeout();
134: goto fail;
135: }
136: msleep(5);
137: }
138:
139: // Reset complete.
140: if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
141: // Device no longer present
142: return -1;
143:
144: return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK)
145: >> USB_PORT_STAT_SPEED_SHIFT);
146:
147: fail:
148: dprintf(1, "Failure on hub port %d reset\n", port);
149: usb_hub_disconnect(hub, port);
150: return -1;
151: }
152:
153: static struct usbhub_op_s HubOp = {
154: .detect = usb_hub_detect,
155: .reset = usb_hub_reset,
156: .disconnect = usb_hub_disconnect,
157: };
158:
159: // Configure a usb hub and then find devices connected to it.
160: int
161: usb_hub_init(struct usb_pipe *pipe)
162: {
163: ASSERT32FLAT();
164: if (!CONFIG_USB_HUB)
165: return -1;
166:
167: struct usb_hub_descriptor desc;
168: int ret = get_hub_desc(pipe, &desc);
169: if (ret)
170: return ret;
171:
172: struct usbhub_s hub;
173: memset(&hub, 0, sizeof(hub));
174: hub.pipe = pipe;
175: hub.cntl = pipe->cntl;
176: hub.powerwait = desc.bPwrOn2PwrGood * 2;
177: hub.portcount = desc.bNbrPorts;
178: hub.op = &HubOp;
179: usb_enumerate(&hub);
180:
181: dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount);
182: if (hub.devcount)
183: return 0;
184: return -1;
185: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.