usbroothub.c revision 1.1.2.6 1 1.1.2.6 skrll /* $NetBSD: usbroothub.c,v 1.1.2.6 2015/03/19 17:26:43 skrll Exp $ */
2 1.1.2.1 skrll
3 1.1.2.2 skrll /*-
4 1.1.2.2 skrll * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
5 1.1.2.2 skrll * All rights reserved.
6 1.1.2.2 skrll *
7 1.1.2.2 skrll * This code is derived from software contributed to The NetBSD Foundation
8 1.1.2.2 skrll * by Lennart Augustsson (lennart (at) augustsson.net) at
9 1.1.2.2 skrll * Carlstedt Research & Technology, Jared D. McNeill (jmcneill (at) invisible.ca),
10 1.1.2.2 skrll * Matthew R. Green (mrg (at) eterna.com.au) and Nick Hudson.
11 1.1.2.2 skrll *
12 1.1.2.2 skrll * Redistribution and use in source and binary forms, with or without
13 1.1.2.2 skrll * modification, are permitted provided that the following conditions
14 1.1.2.2 skrll * are met:
15 1.1.2.2 skrll * 1. Redistributions of source code must retain the above copyright
16 1.1.2.2 skrll * notice, this list of conditions and the following disclaimer.
17 1.1.2.2 skrll * 2. Redistributions in binary form must reproduce the above copyright
18 1.1.2.2 skrll * notice, this list of conditions and the following disclaimer in the
19 1.1.2.2 skrll * documentation and/or other materials provided with the distribution.
20 1.1.2.2 skrll *
21 1.1.2.2 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 1.1.2.2 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 1.1.2.2 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 1.1.2.2 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 1.1.2.2 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 1.1.2.2 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 1.1.2.2 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 1.1.2.2 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 1.1.2.2 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 1.1.2.2 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 1.1.2.2 skrll * POSSIBILITY OF SUCH DAMAGE.
32 1.1.2.2 skrll */
33 1.1.2.3 skrll
34 1.1.2.1 skrll /*
35 1.1.2.1 skrll * Copyright (c) 2008
36 1.1.2.1 skrll * Matthias Drochner. All rights reserved.
37 1.1.2.1 skrll *
38 1.1.2.1 skrll * Redistribution and use in source and binary forms, with or without
39 1.1.2.1 skrll * modification, are permitted provided that the following conditions
40 1.1.2.1 skrll * are met:
41 1.1.2.1 skrll * 1. Redistributions of source code must retain the above copyright
42 1.1.2.1 skrll * notice, this list of conditions and the following disclaimer.
43 1.1.2.1 skrll * 2. Redistributions in binary form must reproduce the above copyright
44 1.1.2.1 skrll * notice, this list of conditions and the following disclaimer in the
45 1.1.2.1 skrll * documentation and/or other materials provided with the distribution.
46 1.1.2.1 skrll *
47 1.1.2.1 skrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 1.1.2.1 skrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 1.1.2.1 skrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 1.1.2.1 skrll * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 1.1.2.1 skrll * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 1.1.2.1 skrll * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 1.1.2.1 skrll * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 1.1.2.1 skrll * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 1.1.2.1 skrll * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 1.1.2.1 skrll * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 1.1.2.1 skrll *
58 1.1.2.1 skrll */
59 1.1.2.1 skrll
60 1.1.2.1 skrll #include <dev/usb/usb.h>
61 1.1.2.2 skrll #include <dev/usb/usbdi.h>
62 1.1.2.2 skrll #include <dev/usb/usbdivar.h>
63 1.1.2.1 skrll #include <dev/usb/usbroothub.h>
64 1.1.2.5 skrll #include <dev/usb/usbhist.h>
65 1.1.2.1 skrll
66 1.1.2.2 skrll extern int usbdebug;
67 1.1.2.2 skrll
68 1.1.2.1 skrll /* helper functions for USB root hub emulation */
69 1.1.2.1 skrll
70 1.1.2.6 skrll static usbd_status roothub_ctrl_transfer(struct usbd_xfer *);
71 1.1.2.6 skrll static usbd_status roothub_ctrl_start(struct usbd_xfer *);
72 1.1.2.6 skrll static void roothub_ctrl_abort(struct usbd_xfer *);
73 1.1.2.6 skrll static void roothub_ctrl_close(struct usbd_pipe *);
74 1.1.2.6 skrll static void roothub_ctrl_done(struct usbd_xfer *);
75 1.1.2.6 skrll static void roothub_noop(struct usbd_pipe *pipe);
76 1.1.2.2 skrll
77 1.1.2.2 skrll const struct usbd_pipe_methods roothub_ctrl_methods = {
78 1.1.2.2 skrll .upm_transfer = roothub_ctrl_transfer,
79 1.1.2.2 skrll .upm_start = roothub_ctrl_start,
80 1.1.2.2 skrll .upm_abort = roothub_ctrl_abort,
81 1.1.2.2 skrll .upm_close = roothub_ctrl_close,
82 1.1.2.2 skrll .upm_cleartoggle = roothub_noop,
83 1.1.2.2 skrll .upm_done = roothub_ctrl_done,
84 1.1.2.2 skrll };
85 1.1.2.2 skrll
86 1.1.2.1 skrll int
87 1.1.2.1 skrll usb_makestrdesc(usb_string_descriptor_t *p, int l, const char *s)
88 1.1.2.1 skrll {
89 1.1.2.1 skrll int i;
90 1.1.2.1 skrll
91 1.1.2.1 skrll if (l == 0)
92 1.1.2.3 skrll return 0;
93 1.1.2.1 skrll p->bLength = 2 * strlen(s) + 2;
94 1.1.2.1 skrll if (l == 1)
95 1.1.2.3 skrll return 1;
96 1.1.2.1 skrll p->bDescriptorType = UDESC_STRING;
97 1.1.2.1 skrll l -= 2;
98 1.1.2.1 skrll /* poor man's utf-16le conversion */
99 1.1.2.1 skrll for (i = 0; s[i] && l > 1; i++, l -= 2)
100 1.1.2.1 skrll USETW2(p->bString[i], 0, s[i]);
101 1.1.2.3 skrll return 2 * i + 2;
102 1.1.2.1 skrll }
103 1.1.2.1 skrll
104 1.1.2.1 skrll int
105 1.1.2.1 skrll usb_makelangtbl(usb_string_descriptor_t *p, int l)
106 1.1.2.1 skrll {
107 1.1.2.1 skrll
108 1.1.2.1 skrll if (l == 0)
109 1.1.2.3 skrll return 0;
110 1.1.2.1 skrll p->bLength = 4;
111 1.1.2.1 skrll if (l == 1)
112 1.1.2.3 skrll return 1;
113 1.1.2.1 skrll p->bDescriptorType = UDESC_STRING;
114 1.1.2.2 skrll if (l < 4)
115 1.1.2.3 skrll return 2;
116 1.1.2.1 skrll USETW(p->bString[0], 0x0409); /* english/US */
117 1.1.2.3 skrll return 4;
118 1.1.2.1 skrll }
119 1.1.2.2 skrll
120 1.1.2.2 skrll /*
121 1.1.2.2 skrll * Data structures and routines to emulate the root hub.
122 1.1.2.2 skrll */
123 1.1.2.2 skrll static const usb_device_descriptor_t usbroothub_devd1 = {
124 1.1.2.2 skrll .bLength = sizeof(usb_device_descriptor_t),
125 1.1.2.2 skrll .bDescriptorType = UDESC_DEVICE,
126 1.1.2.2 skrll .bcdUSB = {0x00, 0x01},
127 1.1.2.2 skrll .bDeviceClass = UDCLASS_HUB,
128 1.1.2.2 skrll .bDeviceSubClass = UDSUBCLASS_HUB,
129 1.1.2.2 skrll .bDeviceProtocol = UDPROTO_FSHUB,
130 1.1.2.2 skrll .bMaxPacketSize = 64,
131 1.1.2.2 skrll .idVendor = {0},
132 1.1.2.2 skrll .idProduct = {0},
133 1.1.2.2 skrll .bcdDevice = {0x00, 0x01},
134 1.1.2.2 skrll .iManufacturer = 1,
135 1.1.2.2 skrll .iProduct = 2,
136 1.1.2.2 skrll .iSerialNumber = 0,
137 1.1.2.2 skrll .bNumConfigurations = 1
138 1.1.2.2 skrll };
139 1.1.2.2 skrll
140 1.1.2.2 skrll static const struct usb_roothub_descriptors usbroothub_confd1 = {
141 1.1.2.2 skrll .urh_confd = {
142 1.1.2.2 skrll .bLength = USB_CONFIG_DESCRIPTOR_SIZE,
143 1.1.2.2 skrll .bDescriptorType = UDESC_CONFIG,
144 1.1.2.2 skrll .wTotalLength = USETWD(sizeof(usbroothub_confd1)),
145 1.1.2.2 skrll .bNumInterface = 1,
146 1.1.2.2 skrll .bConfigurationValue = 1,
147 1.1.2.2 skrll .iConfiguration = 0,
148 1.1.2.2 skrll .bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
149 1.1.2.2 skrll .bMaxPower = 0,
150 1.1.2.2 skrll },
151 1.1.2.2 skrll .urh_ifcd = {
152 1.1.2.2 skrll .bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
153 1.1.2.2 skrll .bDescriptorType = UDESC_INTERFACE,
154 1.1.2.2 skrll .bInterfaceNumber = 0,
155 1.1.2.2 skrll .bAlternateSetting = 0,
156 1.1.2.2 skrll .bNumEndpoints = 1,
157 1.1.2.2 skrll .bInterfaceClass = UICLASS_HUB,
158 1.1.2.2 skrll .bInterfaceSubClass = UISUBCLASS_HUB,
159 1.1.2.2 skrll .bInterfaceProtocol = UIPROTO_FSHUB,
160 1.1.2.2 skrll .iInterface = 0
161 1.1.2.2 skrll },
162 1.1.2.2 skrll .urh_endpd = {
163 1.1.2.2 skrll .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
164 1.1.2.2 skrll .bDescriptorType = UDESC_ENDPOINT,
165 1.1.2.2 skrll .bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
166 1.1.2.2 skrll .bmAttributes = UE_INTERRUPT,
167 1.1.2.2 skrll .wMaxPacketSize = USETWD(8), /* max packet */
168 1.1.2.2 skrll .bInterval = 255,
169 1.1.2.2 skrll },
170 1.1.2.2 skrll };
171 1.1.2.2 skrll
172 1.1.2.2 skrll static const usb_device_descriptor_t usbroothub_devd2 = {
173 1.1.2.2 skrll .bLength = sizeof(usb_device_descriptor_t),
174 1.1.2.2 skrll .bDescriptorType = UDESC_DEVICE,
175 1.1.2.2 skrll .bcdUSB = {0x00, 0x02},
176 1.1.2.2 skrll .bDeviceClass = UDCLASS_HUB,
177 1.1.2.2 skrll .bDeviceSubClass = UDSUBCLASS_HUB,
178 1.1.2.2 skrll .bDeviceProtocol = UDPROTO_HSHUBSTT,
179 1.1.2.2 skrll .bMaxPacketSize = 64,
180 1.1.2.2 skrll .idVendor = {0},
181 1.1.2.2 skrll .idProduct = {0},
182 1.1.2.2 skrll .bcdDevice = {0x00, 0x01},
183 1.1.2.2 skrll .iManufacturer = 1,
184 1.1.2.2 skrll .iProduct = 2,
185 1.1.2.2 skrll .iSerialNumber = 0,
186 1.1.2.2 skrll .bNumConfigurations = 1
187 1.1.2.2 skrll };
188 1.1.2.2 skrll
189 1.1.2.2 skrll static const usb_device_qualifier_t usbroothub_odevd2 = {
190 1.1.2.2 skrll .bLength = USB_DEVICE_QUALIFIER_SIZE,
191 1.1.2.2 skrll .bDescriptorType = UDESC_DEVICE_QUALIFIER,
192 1.1.2.2 skrll .bcdUSB = {0x00, 0x02},
193 1.1.2.2 skrll .bDeviceClass = UDCLASS_HUB,
194 1.1.2.2 skrll .bDeviceSubClass = UDSUBCLASS_HUB,
195 1.1.2.2 skrll .bDeviceProtocol = UDPROTO_FSHUB,
196 1.1.2.2 skrll .bMaxPacketSize0 = 64,
197 1.1.2.2 skrll .bNumConfigurations = 1,
198 1.1.2.2 skrll };
199 1.1.2.2 skrll
200 1.1.2.2 skrll static const struct usb_roothub_descriptors usbroothub_confd2 = {
201 1.1.2.2 skrll .urh_confd = {
202 1.1.2.2 skrll .bLength = USB_CONFIG_DESCRIPTOR_SIZE,
203 1.1.2.2 skrll .bDescriptorType = UDESC_CONFIG,
204 1.1.2.2 skrll .wTotalLength = USETWD(sizeof(usbroothub_confd2)),
205 1.1.2.2 skrll .bNumInterface = 1,
206 1.1.2.2 skrll .bConfigurationValue = 1,
207 1.1.2.2 skrll .iConfiguration = 0,
208 1.1.2.2 skrll .bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
209 1.1.2.2 skrll .bMaxPower = 0,
210 1.1.2.2 skrll },
211 1.1.2.2 skrll .urh_ifcd = {
212 1.1.2.2 skrll .bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
213 1.1.2.2 skrll .bDescriptorType = UDESC_INTERFACE,
214 1.1.2.2 skrll .bInterfaceNumber = 0,
215 1.1.2.2 skrll .bAlternateSetting = 0,
216 1.1.2.2 skrll .bNumEndpoints = 1,
217 1.1.2.2 skrll .bInterfaceClass = UICLASS_HUB,
218 1.1.2.2 skrll .bInterfaceSubClass = UISUBCLASS_HUB,
219 1.1.2.2 skrll .bInterfaceProtocol = UIPROTO_HSHUBSTT,
220 1.1.2.2 skrll .iInterface = 0
221 1.1.2.2 skrll },
222 1.1.2.2 skrll .urh_endpd = {
223 1.1.2.2 skrll .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
224 1.1.2.2 skrll .bDescriptorType = UDESC_ENDPOINT,
225 1.1.2.2 skrll .bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
226 1.1.2.2 skrll .bmAttributes = UE_INTERRUPT,
227 1.1.2.2 skrll .wMaxPacketSize = USETWD(8), /* max packet */
228 1.1.2.2 skrll .bInterval = 12,
229 1.1.2.2 skrll },
230 1.1.2.2 skrll };
231 1.1.2.2 skrll
232 1.1.2.2 skrll static const usb_hub_descriptor_t usbroothub_hubd = {
233 1.1.2.2 skrll .bDescLength = USB_HUB_DESCRIPTOR_SIZE,
234 1.1.2.2 skrll .bDescriptorType = UDESC_HUB,
235 1.1.2.2 skrll .bNbrPorts = 1,
236 1.1.2.2 skrll .wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL),
237 1.1.2.2 skrll .bPwrOn2PwrGood = 50,
238 1.1.2.2 skrll .bHubContrCurrent = 0,
239 1.1.2.2 skrll .DeviceRemovable = {0}, /* port is removable */
240 1.1.2.2 skrll };
241 1.1.2.3 skrll
242 1.1.2.2 skrll /*
243 1.1.2.2 skrll * Simulate a hardware hub by handling all the necessary requests.
244 1.1.2.2 skrll */
245 1.1.2.2 skrll usbd_status
246 1.1.2.6 skrll roothub_ctrl_transfer(struct usbd_xfer *xfer)
247 1.1.2.2 skrll {
248 1.1.2.6 skrll struct usbd_pipe *pipe = xfer->ux_pipe;
249 1.1.2.2 skrll struct usbd_bus *bus = pipe->up_dev->ud_bus;
250 1.1.2.2 skrll usbd_status err;
251 1.1.2.2 skrll
252 1.1.2.2 skrll /* Insert last in queue. */
253 1.1.2.2 skrll mutex_enter(bus->ub_lock);
254 1.1.2.2 skrll err = usb_insert_transfer(xfer);
255 1.1.2.2 skrll mutex_exit(bus->ub_lock);
256 1.1.2.2 skrll if (err)
257 1.1.2.3 skrll return err;
258 1.1.2.2 skrll
259 1.1.2.2 skrll /* Pipe isn't running, start first */
260 1.1.2.2 skrll return roothub_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
261 1.1.2.2 skrll }
262 1.1.2.2 skrll
263 1.1.2.2 skrll static usbd_status
264 1.1.2.6 skrll roothub_ctrl_start(struct usbd_xfer *xfer)
265 1.1.2.2 skrll {
266 1.1.2.6 skrll struct usbd_pipe *pipe = xfer->ux_pipe;
267 1.1.2.2 skrll struct usbd_bus *bus = pipe->up_dev->ud_bus;
268 1.1.2.2 skrll usb_device_request_t *req;
269 1.1.2.2 skrll usbd_status err = USBD_IOERROR; /* XXX STALL? */
270 1.1.2.2 skrll uint16_t len, value;
271 1.1.2.2 skrll int buflen, actlen;
272 1.1.2.2 skrll void *buf;
273 1.1.2.2 skrll
274 1.1.2.5 skrll USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
275 1.1.2.5 skrll
276 1.1.2.2 skrll KASSERT(xfer->ux_rqflags & URQ_REQUEST);
277 1.1.2.2 skrll req = &xfer->ux_request;
278 1.1.2.2 skrll
279 1.1.2.5 skrll USBHIST_LOG(usbdebug, "type=%#2x request=%#2x", req->bmRequestType,
280 1.1.2.5 skrll req->bRequest, 0, 0);
281 1.1.2.2 skrll
282 1.1.2.2 skrll len = UGETW(req->wLength);
283 1.1.2.2 skrll value = UGETW(req->wValue);
284 1.1.2.2 skrll
285 1.1.2.2 skrll buf = len ? usbd_get_buffer(xfer) : NULL;
286 1.1.2.2 skrll buflen = 0;
287 1.1.2.2 skrll
288 1.1.2.2 skrll #define C(x,y) ((x) | ((y) << 8))
289 1.1.2.2 skrll switch (C(req->bRequest, req->bmRequestType)) {
290 1.1.2.2 skrll case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
291 1.1.2.2 skrll case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
292 1.1.2.2 skrll case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
293 1.1.2.2 skrll /*
294 1.1.2.2 skrll * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
295 1.1.2.2 skrll * for the integrated root hub.
296 1.1.2.2 skrll */
297 1.1.2.2 skrll break;
298 1.1.2.2 skrll case C(UR_GET_CONFIG, UT_READ_DEVICE):
299 1.1.2.2 skrll if (len > 0) {
300 1.1.2.2 skrll uint8_t *out = buf;
301 1.1.2.2 skrll
302 1.1.2.2 skrll *out = bus->ub_rhconf;
303 1.1.2.2 skrll buflen = sizeof(*out);
304 1.1.2.2 skrll }
305 1.1.2.2 skrll break;
306 1.1.2.2 skrll case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
307 1.1.2.5 skrll USBHIST_LOG(usbdebug, "wValue=%#4x", value, 0, 0, 0);
308 1.1.2.2 skrll
309 1.1.2.2 skrll if (len == 0)
310 1.1.2.2 skrll break;
311 1.1.2.2 skrll switch (value) {
312 1.1.2.2 skrll case C(0, UDESC_DEVICE):
313 1.1.2.2 skrll if (bus->ub_revision == USBREV_2_0) {
314 1.1.2.2 skrll buflen = min(len, sizeof(usbroothub_devd2));
315 1.1.2.2 skrll memcpy(buf, &usbroothub_devd2, buflen);
316 1.1.2.2 skrll } else {
317 1.1.2.2 skrll buflen = min(len, sizeof(usbroothub_devd1));
318 1.1.2.2 skrll memcpy(buf, &usbroothub_devd1, buflen);
319 1.1.2.2 skrll }
320 1.1.2.2 skrll break;
321 1.1.2.2 skrll case C(0, UDESC_CONFIG):
322 1.1.2.2 skrll if (bus->ub_revision == USBREV_2_0) {
323 1.1.2.2 skrll buflen = min(len, sizeof(usbroothub_confd2));
324 1.1.2.2 skrll memcpy(buf, &usbroothub_confd2, buflen);
325 1.1.2.2 skrll } else {
326 1.1.2.2 skrll buflen = min(len, sizeof(usbroothub_confd1));
327 1.1.2.2 skrll memcpy(buf, &usbroothub_confd1, buflen);
328 1.1.2.2 skrll }
329 1.1.2.2 skrll break;
330 1.1.2.2 skrll case C(0, UDESC_DEVICE_QUALIFIER):
331 1.1.2.2 skrll if (bus->ub_revision == USBREV_2_0) {
332 1.1.2.2 skrll /*
333 1.1.2.2 skrll * We can't really operate at another speed,
334 1.1.2.2 skrll * but the spec says we need this descriptor.
335 1.1.2.2 skrll */
336 1.1.2.2 skrll buflen = min(len, sizeof(usbroothub_odevd2));
337 1.1.2.2 skrll memcpy(buf, &usbroothub_odevd2, buflen);
338 1.1.2.2 skrll } else
339 1.1.2.2 skrll goto fail;
340 1.1.2.2 skrll break;
341 1.1.2.2 skrll case C(0, UDESC_OTHER_SPEED_CONFIGURATION):
342 1.1.2.2 skrll if (bus->ub_revision == USBREV_2_0) {
343 1.1.2.2 skrll struct usb_roothub_descriptors confd;
344 1.1.2.2 skrll
345 1.1.2.2 skrll /*
346 1.1.2.2 skrll * We can't really operate at another speed,
347 1.1.2.2 skrll * but the spec says we need this descriptor.
348 1.1.2.2 skrll */
349 1.1.2.2 skrll buflen = min(len, sizeof(usbroothub_confd2));
350 1.1.2.2 skrll memcpy(&confd, &usbroothub_confd2, buflen);
351 1.1.2.2 skrll confd.urh_confd.bDescriptorType =
352 1.1.2.2 skrll UDESC_OTHER_SPEED_CONFIGURATION;
353 1.1.2.2 skrll memcpy(buf, &confd, buflen);
354 1.1.2.3 skrll } else
355 1.1.2.2 skrll goto fail;
356 1.1.2.2 skrll break;
357 1.1.2.2 skrll #define sd ((usb_string_descriptor_t *)buf)
358 1.1.2.2 skrll case C(0, UDESC_STRING):
359 1.1.2.2 skrll /* Language table */
360 1.1.2.2 skrll buflen = usb_makelangtbl(sd, len);
361 1.1.2.2 skrll break;
362 1.1.2.2 skrll case C(1, UDESC_STRING):
363 1.1.2.2 skrll /* Vendor */
364 1.1.2.2 skrll buflen = usb_makestrdesc(sd, len, "NetBSD");
365 1.1.2.2 skrll break;
366 1.1.2.2 skrll case C(2, UDESC_STRING):
367 1.1.2.2 skrll /* Product */
368 1.1.2.2 skrll buflen = usb_makestrdesc(sd, len, "Root hub");
369 1.1.2.2 skrll break;
370 1.1.2.2 skrll #undef sd
371 1.1.2.2 skrll default:
372 1.1.2.2 skrll /* Default to error */
373 1.1.2.2 skrll buflen = -1;
374 1.1.2.2 skrll }
375 1.1.2.2 skrll break;
376 1.1.2.2 skrll case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
377 1.1.2.2 skrll buflen = min(len, sizeof(usbroothub_hubd));
378 1.1.2.2 skrll memcpy(buf, &usbroothub_hubd, buflen);
379 1.1.2.2 skrll break;
380 1.1.2.2 skrll case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
381 1.1.2.2 skrll /* Get Interface, 9.4.4 */
382 1.1.2.2 skrll if (len > 0) {
383 1.1.2.2 skrll uint8_t *out = buf;
384 1.1.2.2 skrll
385 1.1.2.2 skrll *out = 0;
386 1.1.2.2 skrll buflen = sizeof(*out);
387 1.1.2.2 skrll }
388 1.1.2.2 skrll break;
389 1.1.2.2 skrll case C(UR_GET_STATUS, UT_READ_DEVICE):
390 1.1.2.2 skrll /* Get Status from device, 9.4.5 */
391 1.1.2.2 skrll if (len > 1) {
392 1.1.2.2 skrll usb_status_t *out = buf;
393 1.1.2.2 skrll
394 1.1.2.2 skrll USETW(out->wStatus, UDS_SELF_POWERED);
395 1.1.2.2 skrll buflen = sizeof(*out);
396 1.1.2.2 skrll }
397 1.1.2.2 skrll break;
398 1.1.2.2 skrll case C(UR_GET_STATUS, UT_READ_INTERFACE):
399 1.1.2.2 skrll case C(UR_GET_STATUS, UT_READ_ENDPOINT):
400 1.1.2.2 skrll /* Get Status from interface, endpoint, 9.4.5 */
401 1.1.2.2 skrll if (len > 1) {
402 1.1.2.2 skrll usb_status_t *out = buf;
403 1.1.2.2 skrll
404 1.1.2.2 skrll USETW(out->wStatus, 0);
405 1.1.2.2 skrll buflen = sizeof(*out);
406 1.1.2.2 skrll }
407 1.1.2.2 skrll break;
408 1.1.2.2 skrll case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
409 1.1.2.2 skrll /* Set Address, 9.4.6 */
410 1.1.2.5 skrll USBHIST_LOG(usbdebug, "UR_SET_ADDRESS, UT_WRITE_DEVICE: addr %d",
411 1.1.2.5 skrll value, 0, 0, 0);
412 1.1.2.2 skrll if (value >= USB_MAX_DEVICES) {
413 1.1.2.2 skrll goto fail;
414 1.1.2.2 skrll }
415 1.1.2.2 skrll bus->ub_rhaddr = value;
416 1.1.2.2 skrll break;
417 1.1.2.2 skrll case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
418 1.1.2.2 skrll /* Set Configuration, 9.4.7 */
419 1.1.2.2 skrll if (value != 0 && value != 1) {
420 1.1.2.2 skrll goto fail;
421 1.1.2.2 skrll }
422 1.1.2.2 skrll bus->ub_rhconf = value;
423 1.1.2.2 skrll break;
424 1.1.2.2 skrll case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
425 1.1.2.2 skrll /* Set Descriptor, 9.4.8, not supported */
426 1.1.2.2 skrll break;
427 1.1.2.2 skrll case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
428 1.1.2.2 skrll case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
429 1.1.2.2 skrll case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
430 1.1.2.2 skrll /* Set Feature, 9.4.9, not supported */
431 1.1.2.2 skrll goto fail;
432 1.1.2.2 skrll case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
433 1.1.2.2 skrll /* Set Interface, 9.4.10, not supported */
434 1.1.2.2 skrll break;
435 1.1.2.2 skrll case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
436 1.1.2.2 skrll /* Synch Frame, 9.4.11, not supported */
437 1.1.2.2 skrll break;
438 1.1.2.2 skrll default:
439 1.1.2.2 skrll /* Default to error */
440 1.1.2.2 skrll buflen = -1;
441 1.1.2.2 skrll break;
442 1.1.2.2 skrll }
443 1.1.2.2 skrll
444 1.1.2.2 skrll actlen = bus->ub_methods->ubm_rhctrl(bus, req, buf, buflen);
445 1.1.2.5 skrll USBHIST_LOG(usbdebug, "xfer %p buflen %d actlen %d", xfer, buflen,
446 1.1.2.5 skrll actlen, 0);
447 1.1.2.2 skrll if (actlen < 0)
448 1.1.2.2 skrll goto fail;
449 1.1.2.2 skrll
450 1.1.2.2 skrll xfer->ux_actlen = actlen;
451 1.1.2.2 skrll err = USBD_NORMAL_COMPLETION;
452 1.1.2.2 skrll
453 1.1.2.2 skrll fail:
454 1.1.2.5 skrll USBHIST_LOG(usbdebug, "xfer %p err %d", xfer, err, 0, 0);
455 1.1.2.5 skrll
456 1.1.2.2 skrll xfer->ux_status = err;
457 1.1.2.2 skrll mutex_enter(bus->ub_lock);
458 1.1.2.2 skrll usb_transfer_complete(xfer);
459 1.1.2.2 skrll mutex_exit(bus->ub_lock);
460 1.1.2.2 skrll
461 1.1.2.4 skrll return err;
462 1.1.2.2 skrll }
463 1.1.2.2 skrll
464 1.1.2.2 skrll /* Abort a root control request. */
465 1.1.2.2 skrll Static void
466 1.1.2.6 skrll roothub_ctrl_abort(struct usbd_xfer *xfer)
467 1.1.2.2 skrll {
468 1.1.2.2 skrll
469 1.1.2.2 skrll /* Nothing to do, all transfers are synchronous. */
470 1.1.2.2 skrll }
471 1.1.2.2 skrll
472 1.1.2.2 skrll /* Close the root pipe. */
473 1.1.2.2 skrll Static void
474 1.1.2.6 skrll roothub_ctrl_close(struct usbd_pipe *pipe)
475 1.1.2.2 skrll {
476 1.1.2.2 skrll
477 1.1.2.2 skrll /* Nothing to do. */
478 1.1.2.2 skrll }
479 1.1.2.2 skrll
480 1.1.2.2 skrll Static void
481 1.1.2.6 skrll roothub_ctrl_done(struct usbd_xfer *xfer)
482 1.1.2.2 skrll {
483 1.1.2.2 skrll
484 1.1.2.2 skrll /* Nothing to do. */
485 1.1.2.2 skrll }
486 1.1.2.2 skrll
487 1.1.2.2 skrll static void
488 1.1.2.6 skrll roothub_noop(struct usbd_pipe *pipe)
489 1.1.2.2 skrll {
490 1.1.2.2 skrll
491 1.1.2.2 skrll }
492