| @@ -1,1579 +1,1572 @@ | | | @@ -1,1579 +1,1572 @@ |
1 | /* $NetBSD: usb_subr.c,v 1.180.6.1.2.3 2011/12/08 10:41:28 mrg Exp $ */ | | 1 | /* $NetBSD: usb_subr.c,v 1.180.6.1.2.4 2011/12/08 22:04:56 mrg Exp $ */ |
2 | /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */ | | 2 | /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. | | 5 | * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * This code is derived from software contributed to The NetBSD Foundation | | 8 | * This code is derived from software contributed to The NetBSD Foundation |
9 | * by Lennart Augustsson (lennart@augustsson.net) at | | 9 | * by Lennart Augustsson (lennart@augustsson.net) at |
10 | * Carlstedt Research & Technology. | | 10 | * Carlstedt Research & Technology. |
11 | * | | 11 | * |
12 | * Redistribution and use in source and binary forms, with or without | | 12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions | | 13 | * modification, are permitted provided that the following conditions |
14 | * are met: | | 14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright | | 15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. | | 16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright | | 17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the | | 18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. | | 19 | * documentation and/or other materials provided with the distribution. |
20 | * | | 20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. | | 31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ | | 32 | */ |
33 | | | 33 | |
34 | #include <sys/cdefs.h> | | 34 | #include <sys/cdefs.h> |
35 | __KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.180.6.1.2.3 2011/12/08 10:41:28 mrg Exp $"); | | 35 | __KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.180.6.1.2.4 2011/12/08 22:04:56 mrg Exp $"); |
36 | | | 36 | |
37 | #include "opt_compat_netbsd.h" | | 37 | #include "opt_compat_netbsd.h" |
38 | #include "opt_usbverbose.h" | | 38 | #include "opt_usbverbose.h" |
39 | | | 39 | |
40 | #include <sys/param.h> | | 40 | #include <sys/param.h> |
41 | #include <sys/systm.h> | | 41 | #include <sys/systm.h> |
42 | #include <sys/kernel.h> | | 42 | #include <sys/kernel.h> |
43 | #include <sys/malloc.h> | | 43 | #include <sys/malloc.h> |
44 | #include <sys/device.h> | | 44 | #include <sys/device.h> |
45 | #include <sys/select.h> | | 45 | #include <sys/select.h> |
46 | #include <sys/proc.h> | | 46 | #include <sys/proc.h> |
47 | | | 47 | |
48 | #include <sys/bus.h> | | 48 | #include <sys/bus.h> |
49 | #include <sys/module.h> | | 49 | #include <sys/module.h> |
50 | | | 50 | |
51 | #include <dev/usb/usb.h> | | 51 | #include <dev/usb/usb.h> |
52 | | | 52 | |
53 | #include <dev/usb/usbdi.h> | | 53 | #include <dev/usb/usbdi.h> |
54 | #include <dev/usb/usbdi_util.h> | | 54 | #include <dev/usb/usbdi_util.h> |
55 | #include <dev/usb/usbdivar.h> | | 55 | #include <dev/usb/usbdivar.h> |
56 | #include <dev/usb/usbdevs.h> | | 56 | #include <dev/usb/usbdevs.h> |
57 | #include <dev/usb/usb_quirks.h> | | 57 | #include <dev/usb/usb_quirks.h> |
58 | #include <dev/usb/usb_verbose.h> | | 58 | #include <dev/usb/usb_verbose.h> |
59 | | | 59 | |
60 | #include "locators.h" | | 60 | #include "locators.h" |
61 | | | 61 | |
62 | #ifdef USB_DEBUG | | 62 | #ifdef USB_DEBUG |
63 | #define DPRINTF(x) if (usbdebug) printf x | | 63 | #define DPRINTF(x) if (usbdebug) printf x |
64 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x | | 64 | #define DPRINTFN(n,x) if (usbdebug>(n)) printf x |
65 | extern int usbdebug; | | 65 | extern int usbdebug; |
66 | #else | | 66 | #else |
67 | #define DPRINTF(x) | | 67 | #define DPRINTF(x) |
68 | #define DPRINTFN(n,x) | | 68 | #define DPRINTFN(n,x) |
69 | #endif | | 69 | #endif |
70 | | | 70 | |
71 | MALLOC_DEFINE(M_USB, "USB", "USB misc. memory"); | | 71 | MALLOC_DEFINE(M_USB, "USB", "USB misc. memory"); |
72 | MALLOC_DEFINE(M_USBDEV, "USB device", "USB device driver"); | | 72 | MALLOC_DEFINE(M_USBDEV, "USB device", "USB device driver"); |
73 | MALLOC_DEFINE(M_USBHC, "USB HC", "USB host controller"); | | 73 | MALLOC_DEFINE(M_USBHC, "USB HC", "USB host controller"); |
74 | | | 74 | |
75 | Static usbd_status usbd_set_config(usbd_device_handle, int); | | 75 | Static usbd_status usbd_set_config(usbd_device_handle, int); |
76 | Static void usbd_devinfo(usbd_device_handle, int, char *, size_t); | | 76 | Static void usbd_devinfo(usbd_device_handle, int, char *, size_t); |
77 | Static void usbd_devinfo_vp(usbd_device_handle, char *, size_t, char *, size_t, | | 77 | Static void usbd_devinfo_vp(usbd_device_handle, char *, size_t, char *, size_t, |
78 | int, int); | | 78 | int, int); |
79 | Static int usbd_getnewaddr(usbd_bus_handle); | | 79 | Static int usbd_getnewaddr(usbd_bus_handle); |
80 | Static int usbd_print(void *, const char *); | | 80 | Static int usbd_print(void *, const char *); |
81 | Static int usbd_ifprint(void *, const char *); | | 81 | Static int usbd_ifprint(void *, const char *); |
82 | Static void usbd_free_iface_data(usbd_device_handle, int); | | 82 | Static void usbd_free_iface_data(usbd_device_handle, int); |
83 | Static void usbd_kill_pipe(usbd_pipe_handle); | | 83 | Static void usbd_kill_pipe(usbd_pipe_handle); |
84 | usbd_status usbd_attach_roothub(device_t, usbd_device_handle); | | 84 | usbd_status usbd_attach_roothub(device_t, usbd_device_handle); |
85 | Static usbd_status usbd_probe_and_attach(device_t, usbd_device_handle, int, | | 85 | Static usbd_status usbd_probe_and_attach(device_t, usbd_device_handle, int, |
86 | int); | | 86 | int); |
87 | | | 87 | |
88 | Static u_int32_t usb_cookie_no = 0; | | 88 | Static u_int32_t usb_cookie_no = 0; |
89 | | | 89 | |
90 | Static const char * const usbd_error_strs[] = { | | 90 | Static const char * const usbd_error_strs[] = { |
91 | "NORMAL_COMPLETION", | | 91 | "NORMAL_COMPLETION", |
92 | "IN_PROGRESS", | | 92 | "IN_PROGRESS", |
93 | "PENDING_REQUESTS", | | 93 | "PENDING_REQUESTS", |
94 | "NOT_STARTED", | | 94 | "NOT_STARTED", |
95 | "INVAL", | | 95 | "INVAL", |
96 | "NOMEM", | | 96 | "NOMEM", |
97 | "CANCELLED", | | 97 | "CANCELLED", |
98 | "BAD_ADDRESS", | | 98 | "BAD_ADDRESS", |
99 | "IN_USE", | | 99 | "IN_USE", |
100 | "NO_ADDR", | | 100 | "NO_ADDR", |
101 | "SET_ADDR_FAILED", | | 101 | "SET_ADDR_FAILED", |
102 | "NO_POWER", | | 102 | "NO_POWER", |
103 | "TOO_DEEP", | | 103 | "TOO_DEEP", |
104 | "IOERROR", | | 104 | "IOERROR", |
105 | "NOT_CONFIGURED", | | 105 | "NOT_CONFIGURED", |
106 | "TIMEOUT", | | 106 | "TIMEOUT", |
107 | "SHORT_XFER", | | 107 | "SHORT_XFER", |
108 | "STALLED", | | 108 | "STALLED", |
109 | "INTERRUPTED", | | 109 | "INTERRUPTED", |
110 | "XXX", | | 110 | "XXX", |
111 | }; | | 111 | }; |
112 | | | 112 | |
113 | void usb_load_verbose(void); | | 113 | void usb_load_verbose(void); |
114 | | | 114 | |
115 | void get_usb_vendor_stub(char *, size_t, usb_vendor_id_t); | | 115 | void get_usb_vendor_stub(char *, size_t, usb_vendor_id_t); |
116 | void get_usb_product_stub(char *, size_t, usb_vendor_id_t, usb_product_id_t); | | 116 | void get_usb_product_stub(char *, size_t, usb_vendor_id_t, usb_product_id_t); |
117 | | | 117 | |
118 | void (*get_usb_vendor)(char *, size_t, usb_vendor_id_t) = get_usb_vendor_stub; | | 118 | void (*get_usb_vendor)(char *, size_t, usb_vendor_id_t) = get_usb_vendor_stub; |
119 | void (*get_usb_product)(char *, size_t, usb_vendor_id_t, usb_product_id_t) = | | 119 | void (*get_usb_product)(char *, size_t, usb_vendor_id_t, usb_product_id_t) = |
120 | get_usb_product_stub; | | 120 | get_usb_product_stub; |
121 | | | 121 | |
122 | int usb_verbose_loaded = 0; | | 122 | int usb_verbose_loaded = 0; |
123 | | | 123 | |
124 | /* | | 124 | /* |
125 | * Load the usbverbose module | | 125 | * Load the usbverbose module |
126 | */ | | 126 | */ |
127 | void usb_load_verbose(void) | | 127 | void usb_load_verbose(void) |
128 | { | | 128 | { |
129 | if (usb_verbose_loaded == 0) | | 129 | if (usb_verbose_loaded == 0) |
130 | module_autoload("usbverbose", MODULE_CLASS_MISC); | | 130 | module_autoload("usbverbose", MODULE_CLASS_MISC); |
131 | } | | 131 | } |
132 | | | 132 | |
133 | void get_usb_vendor_stub(char *v, size_t l, usb_vendor_id_t v_id) | | 133 | void get_usb_vendor_stub(char *v, size_t l, usb_vendor_id_t v_id) |
134 | { | | 134 | { |
135 | usb_load_verbose(); | | 135 | usb_load_verbose(); |
136 | if (usb_verbose_loaded) | | 136 | if (usb_verbose_loaded) |
137 | get_usb_vendor(v, l, v_id); | | 137 | get_usb_vendor(v, l, v_id); |
138 | } | | 138 | } |
139 | | | 139 | |
140 | void get_usb_product_stub(char *p, size_t l, usb_vendor_id_t v_id, | | 140 | void get_usb_product_stub(char *p, size_t l, usb_vendor_id_t v_id, |
141 | usb_product_id_t p_id) | | 141 | usb_product_id_t p_id) |
142 | { | | 142 | { |
143 | usb_load_verbose(); | | 143 | usb_load_verbose(); |
144 | if (usb_verbose_loaded) | | 144 | if (usb_verbose_loaded) |
145 | get_usb_product(p, l, v_id, p_id); | | 145 | get_usb_product(p, l, v_id, p_id); |
146 | } | | 146 | } |
147 | | | 147 | |
148 | const char * | | 148 | const char * |
149 | usbd_errstr(usbd_status err) | | 149 | usbd_errstr(usbd_status err) |
150 | { | | 150 | { |
151 | static char buffer[5]; | | 151 | static char buffer[5]; |
152 | | | 152 | |
153 | if (err < USBD_ERROR_MAX) { | | 153 | if (err < USBD_ERROR_MAX) { |
154 | return usbd_error_strs[err]; | | 154 | return usbd_error_strs[err]; |
155 | } else { | | 155 | } else { |
156 | snprintf(buffer, sizeof buffer, "%d", err); | | 156 | snprintf(buffer, sizeof buffer, "%d", err); |
157 | return buffer; | | 157 | return buffer; |
158 | } | | 158 | } |
159 | } | | 159 | } |
160 | | | 160 | |
161 | usbd_status | | 161 | usbd_status |
162 | usbd_get_string_desc(usbd_device_handle dev, int sindex, int langid, | | 162 | usbd_get_string_desc(usbd_device_handle dev, int sindex, int langid, |
163 | usb_string_descriptor_t *sdesc, int *sizep) | | 163 | usb_string_descriptor_t *sdesc, int *sizep) |
164 | { | | 164 | { |
165 | usb_device_request_t req; | | 165 | usb_device_request_t req; |
166 | usbd_status err; | | 166 | usbd_status err; |
167 | int actlen; | | 167 | int actlen; |
168 | | | 168 | |
169 | req.bmRequestType = UT_READ_DEVICE; | | 169 | req.bmRequestType = UT_READ_DEVICE; |
170 | req.bRequest = UR_GET_DESCRIPTOR; | | 170 | req.bRequest = UR_GET_DESCRIPTOR; |
171 | USETW2(req.wValue, UDESC_STRING, sindex); | | 171 | USETW2(req.wValue, UDESC_STRING, sindex); |
172 | USETW(req.wIndex, langid); | | 172 | USETW(req.wIndex, langid); |
173 | USETW(req.wLength, 2); /* only size byte first */ | | 173 | USETW(req.wLength, 2); /* only size byte first */ |
174 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, | | 174 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, |
175 | &actlen, USBD_DEFAULT_TIMEOUT); | | 175 | &actlen, USBD_DEFAULT_TIMEOUT); |
176 | if (err) | | 176 | if (err) |
177 | return (err); | | 177 | return (err); |
178 | | | 178 | |
179 | if (actlen < 2) | | 179 | if (actlen < 2) |
180 | return (USBD_SHORT_XFER); | | 180 | return (USBD_SHORT_XFER); |
181 | | | 181 | |
182 | USETW(req.wLength, sdesc->bLength); /* the whole string */ | | 182 | USETW(req.wLength, sdesc->bLength); /* the whole string */ |
183 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, | | 183 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, |
184 | &actlen, USBD_DEFAULT_TIMEOUT); | | 184 | &actlen, USBD_DEFAULT_TIMEOUT); |
185 | if (err) | | 185 | if (err) |
186 | return (err); | | 186 | return (err); |
187 | | | 187 | |
188 | if (actlen != sdesc->bLength) { | | 188 | if (actlen != sdesc->bLength) { |
189 | DPRINTFN(-1, ("usbd_get_string_desc: expected %d, got %d\n", | | 189 | DPRINTFN(-1, ("usbd_get_string_desc: expected %d, got %d\n", |
190 | sdesc->bLength, actlen)); | | 190 | sdesc->bLength, actlen)); |
191 | } | | 191 | } |
192 | | | 192 | |
193 | *sizep = actlen; | | 193 | *sizep = actlen; |
194 | return (USBD_NORMAL_COMPLETION); | | 194 | return (USBD_NORMAL_COMPLETION); |
195 | } | | 195 | } |
196 | | | 196 | |
197 | static void | | 197 | static void |
198 | usbd_trim_spaces(char *p) | | 198 | usbd_trim_spaces(char *p) |
199 | { | | 199 | { |
200 | char *q, *e; | | 200 | char *q, *e; |
201 | | | 201 | |
202 | q = e = p; | | 202 | q = e = p; |
203 | while (*q == ' ') /* skip leading spaces */ | | 203 | while (*q == ' ') /* skip leading spaces */ |
204 | q++; | | 204 | q++; |
205 | while ((*p = *q++)) /* copy string */ | | 205 | while ((*p = *q++)) /* copy string */ |
206 | if (*p++ != ' ') /* remember last non-space */ | | 206 | if (*p++ != ' ') /* remember last non-space */ |
207 | e = p; | | 207 | e = p; |
208 | *e = '\0'; /* kill trailing spaces */ | | 208 | *e = '\0'; /* kill trailing spaces */ |
209 | } | | 209 | } |
210 | | | 210 | |
211 | Static void | | 211 | Static void |
212 | usbd_devinfo_vp(usbd_device_handle dev, char *v, size_t vl, char *p, | | 212 | usbd_devinfo_vp(usbd_device_handle dev, char *v, size_t vl, char *p, |
213 | size_t pl, int usedev, int useencoded) | | 213 | size_t pl, int usedev, int useencoded) |
214 | { | | 214 | { |
215 | usb_device_descriptor_t *udd = &dev->ddesc; | | 215 | usb_device_descriptor_t *udd = &dev->ddesc; |
216 | if (dev == NULL) | | 216 | if (dev == NULL) |
217 | return; | | 217 | return; |
218 | | | 218 | |
219 | v[0] = p[0] = '\0'; | | 219 | v[0] = p[0] = '\0'; |
220 | | | 220 | |
221 | if (usedev) { | | 221 | if (usedev) { |
222 | if (usbd_get_string0(dev, udd->iManufacturer, v, useencoded) == | | 222 | if (usbd_get_string0(dev, udd->iManufacturer, v, useencoded) == |
223 | USBD_NORMAL_COMPLETION) | | 223 | USBD_NORMAL_COMPLETION) |
224 | usbd_trim_spaces(v); | | 224 | usbd_trim_spaces(v); |
225 | if (usbd_get_string0(dev, udd->iProduct, p, useencoded) == | | 225 | if (usbd_get_string0(dev, udd->iProduct, p, useencoded) == |
226 | USBD_NORMAL_COMPLETION) | | 226 | USBD_NORMAL_COMPLETION) |
227 | usbd_trim_spaces(p); | | 227 | usbd_trim_spaces(p); |
228 | } | | 228 | } |
229 | if (v[0] == '\0') | | 229 | if (v[0] == '\0') |
230 | get_usb_vendor(v, vl, UGETW(udd->idVendor)); | | 230 | get_usb_vendor(v, vl, UGETW(udd->idVendor)); |
231 | if (p[0] == '\0') | | 231 | if (p[0] == '\0') |
232 | get_usb_product(p, pl, UGETW(udd->idVendor), | | 232 | get_usb_product(p, pl, UGETW(udd->idVendor), |
233 | UGETW(udd->idProduct)); | | 233 | UGETW(udd->idProduct)); |
234 | | | 234 | |
235 | if (v[0] == '\0') | | 235 | if (v[0] == '\0') |
236 | snprintf(v, vl, "vendor 0x%04x", UGETW(udd->idVendor)); | | 236 | snprintf(v, vl, "vendor 0x%04x", UGETW(udd->idVendor)); |
237 | if (p[0] == '\0') | | 237 | if (p[0] == '\0') |
238 | snprintf(p, pl, "product 0x%04x", UGETW(udd->idProduct)); | | 238 | snprintf(p, pl, "product 0x%04x", UGETW(udd->idProduct)); |
239 | } | | 239 | } |
240 | | | 240 | |
241 | int | | 241 | int |
242 | usbd_printBCD(char *cp, size_t l, int bcd) | | 242 | usbd_printBCD(char *cp, size_t l, int bcd) |
243 | { | | 243 | { |
244 | return snprintf(cp, l, "%x.%02x", bcd >> 8, bcd & 0xff); | | 244 | return snprintf(cp, l, "%x.%02x", bcd >> 8, bcd & 0xff); |
245 | } | | 245 | } |
246 | | | 246 | |
247 | Static void | | 247 | Static void |
248 | usbd_devinfo(usbd_device_handle dev, int showclass, char *cp, size_t l) | | 248 | usbd_devinfo(usbd_device_handle dev, int showclass, char *cp, size_t l) |
249 | { | | 249 | { |
250 | usb_device_descriptor_t *udd = &dev->ddesc; | | 250 | usb_device_descriptor_t *udd = &dev->ddesc; |
251 | char *vendor, *product; | | 251 | char *vendor, *product; |
252 | int bcdDevice, bcdUSB; | | 252 | int bcdDevice, bcdUSB; |
253 | char *ep; | | 253 | char *ep; |
254 | | | 254 | |
255 | vendor = malloc(USB_MAX_ENCODED_STRING_LEN * 2, M_USB, M_NOWAIT); | | 255 | vendor = malloc(USB_MAX_ENCODED_STRING_LEN * 2, M_USB, M_NOWAIT); |
256 | if (vendor == NULL) { | | 256 | if (vendor == NULL) { |
257 | *cp = '\0'; | | 257 | *cp = '\0'; |
258 | return; | | 258 | return; |
259 | } | | 259 | } |
260 | product = &vendor[USB_MAX_ENCODED_STRING_LEN]; | | 260 | product = &vendor[USB_MAX_ENCODED_STRING_LEN]; |
261 | | | 261 | |
262 | ep = cp + l; | | 262 | ep = cp + l; |
263 | | | 263 | |
264 | usbd_devinfo_vp(dev, vendor, USB_MAX_ENCODED_STRING_LEN, | | 264 | usbd_devinfo_vp(dev, vendor, USB_MAX_ENCODED_STRING_LEN, |
265 | product, USB_MAX_ENCODED_STRING_LEN, 1, 1); | | 265 | product, USB_MAX_ENCODED_STRING_LEN, 1, 1); |
266 | cp += snprintf(cp, ep - cp, "%s %s", vendor, product); | | 266 | cp += snprintf(cp, ep - cp, "%s %s", vendor, product); |
267 | if (showclass) | | 267 | if (showclass) |
268 | cp += snprintf(cp, ep - cp, ", class %d/%d", | | 268 | cp += snprintf(cp, ep - cp, ", class %d/%d", |
269 | udd->bDeviceClass, udd->bDeviceSubClass); | | 269 | udd->bDeviceClass, udd->bDeviceSubClass); |
270 | bcdUSB = UGETW(udd->bcdUSB); | | 270 | bcdUSB = UGETW(udd->bcdUSB); |
271 | bcdDevice = UGETW(udd->bcdDevice); | | 271 | bcdDevice = UGETW(udd->bcdDevice); |
272 | cp += snprintf(cp, ep - cp, ", rev "); | | 272 | cp += snprintf(cp, ep - cp, ", rev "); |
273 | cp += usbd_printBCD(cp, ep - cp, bcdUSB); | | 273 | cp += usbd_printBCD(cp, ep - cp, bcdUSB); |
274 | *cp++ = '/'; | | 274 | *cp++ = '/'; |
275 | cp += usbd_printBCD(cp, ep - cp, bcdDevice); | | 275 | cp += usbd_printBCD(cp, ep - cp, bcdDevice); |
276 | cp += snprintf(cp, ep - cp, ", addr %d", dev->address); | | 276 | cp += snprintf(cp, ep - cp, ", addr %d", dev->address); |
277 | *cp = 0; | | 277 | *cp = 0; |
278 | free(vendor, M_USB); | | 278 | free(vendor, M_USB); |
279 | } | | 279 | } |
280 | | | 280 | |
281 | char * | | 281 | char * |
282 | usbd_devinfo_alloc(usbd_device_handle dev, int showclass) | | 282 | usbd_devinfo_alloc(usbd_device_handle dev, int showclass) |
283 | { | | 283 | { |
284 | char *devinfop; | | 284 | char *devinfop; |
285 | | | 285 | |
286 | devinfop = malloc(DEVINFOSIZE, M_TEMP, M_WAITOK); | | 286 | devinfop = malloc(DEVINFOSIZE, M_TEMP, M_WAITOK); |
287 | usbd_devinfo(dev, showclass, devinfop, DEVINFOSIZE); | | 287 | usbd_devinfo(dev, showclass, devinfop, DEVINFOSIZE); |
288 | return devinfop; | | 288 | return devinfop; |
289 | } | | 289 | } |
290 | | | 290 | |
291 | void | | 291 | void |
292 | usbd_devinfo_free(char *devinfop) | | 292 | usbd_devinfo_free(char *devinfop) |
293 | { | | 293 | { |
294 | free(devinfop, M_TEMP); | | 294 | free(devinfop, M_TEMP); |
295 | } | | 295 | } |
296 | | | 296 | |
297 | /* Delay for a certain number of ms */ | | 297 | /* Delay for a certain number of ms */ |
298 | void | | 298 | void |
299 | usb_delay_ms(usbd_bus_handle bus, u_int ms) | | 299 | usb_delay_ms(usbd_bus_handle bus, u_int ms) |
300 | { | | 300 | { |
301 | /* Wait at least two clock ticks so we know the time has passed. */ | | 301 | /* Wait at least two clock ticks so we know the time has passed. */ |
302 | if (bus->use_polling || cold) | | 302 | if (bus->use_polling || cold) |
303 | delay((ms+1) * 1000); | | 303 | delay((ms+1) * 1000); |
304 | else | | 304 | else |
305 | tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1); | | 305 | tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1); |
306 | } | | 306 | } |
307 | | | 307 | |
308 | /* Delay given a device handle. */ | | 308 | /* Delay given a device handle. */ |
309 | void | | 309 | void |
310 | usbd_delay_ms(usbd_device_handle dev, u_int ms) | | 310 | usbd_delay_ms(usbd_device_handle dev, u_int ms) |
311 | { | | 311 | { |
312 | usb_delay_ms(dev->bus, ms); | | 312 | usb_delay_ms(dev->bus, ms); |
313 | } | | 313 | } |
314 | | | 314 | |
315 | usbd_status | | 315 | usbd_status |
316 | usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps) | | 316 | usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps) |
317 | { | | 317 | { |
318 | usb_device_request_t req; | | 318 | usb_device_request_t req; |
319 | usbd_status err; | | 319 | usbd_status err; |
320 | int n; | | 320 | int n; |
321 | | | 321 | |
322 | req.bmRequestType = UT_WRITE_CLASS_OTHER; | | 322 | req.bmRequestType = UT_WRITE_CLASS_OTHER; |
323 | req.bRequest = UR_SET_FEATURE; | | 323 | req.bRequest = UR_SET_FEATURE; |
324 | USETW(req.wValue, UHF_PORT_RESET); | | 324 | USETW(req.wValue, UHF_PORT_RESET); |
325 | USETW(req.wIndex, port); | | 325 | USETW(req.wIndex, port); |
326 | USETW(req.wLength, 0); | | 326 | USETW(req.wLength, 0); |
327 | err = usbd_do_request(dev, &req, 0); | | 327 | err = usbd_do_request(dev, &req, 0); |
328 | DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n", | | 328 | DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n", |
329 | port, usbd_errstr(err))); | | 329 | port, usbd_errstr(err))); |
330 | if (err) | | 330 | if (err) |
331 | return (err); | | 331 | return (err); |
332 | n = 10; | | 332 | n = 10; |
333 | do { | | 333 | do { |
334 | /* Wait for device to recover from reset. */ | | 334 | /* Wait for device to recover from reset. */ |
335 | usbd_delay_ms(dev, USB_PORT_RESET_DELAY); | | 335 | usbd_delay_ms(dev, USB_PORT_RESET_DELAY); |
336 | err = usbd_get_port_status(dev, port, ps); | | 336 | err = usbd_get_port_status(dev, port, ps); |
337 | if (err) { | | 337 | if (err) { |
338 | DPRINTF(("usbd_reset_port: get status failed %d\n", | | 338 | DPRINTF(("usbd_reset_port: get status failed %d\n", |
339 | err)); | | 339 | err)); |
340 | return (err); | | 340 | return (err); |
341 | } | | 341 | } |
342 | /* If the device disappeared, just give up. */ | | 342 | /* If the device disappeared, just give up. */ |
343 | if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) | | 343 | if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) |
344 | return (USBD_NORMAL_COMPLETION); | | 344 | return (USBD_NORMAL_COMPLETION); |
345 | } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0); | | 345 | } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0); |
346 | if (n == 0) | | 346 | if (n == 0) |
347 | return (USBD_TIMEOUT); | | 347 | return (USBD_TIMEOUT); |
348 | err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET); | | 348 | err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET); |
349 | #ifdef USB_DEBUG | | 349 | #ifdef USB_DEBUG |
350 | if (err) | | 350 | if (err) |
351 | DPRINTF(("usbd_reset_port: clear port feature failed %d\n", | | 351 | DPRINTF(("usbd_reset_port: clear port feature failed %d\n", |
352 | err)); | | 352 | err)); |
353 | #endif | | 353 | #endif |
354 | | | 354 | |
355 | /* Wait for the device to recover from reset. */ | | 355 | /* Wait for the device to recover from reset. */ |
356 | usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY); | | 356 | usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY); |
357 | return (err); | | 357 | return (err); |
358 | } | | 358 | } |
359 | | | 359 | |
360 | usb_interface_descriptor_t * | | 360 | usb_interface_descriptor_t * |
361 | usbd_find_idesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx) | | 361 | usbd_find_idesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx) |
362 | { | | 362 | { |
363 | char *p = (char *)cd; | | 363 | char *p = (char *)cd; |
364 | char *end = p + UGETW(cd->wTotalLength); | | 364 | char *end = p + UGETW(cd->wTotalLength); |
365 | usb_interface_descriptor_t *d; | | 365 | usb_interface_descriptor_t *d; |
366 | int curidx, lastidx, curaidx = 0; | | 366 | int curidx, lastidx, curaidx = 0; |
367 | | | 367 | |
368 | for (curidx = lastidx = -1; p < end; ) { | | 368 | for (curidx = lastidx = -1; p < end; ) { |
369 | d = (usb_interface_descriptor_t *)p; | | 369 | d = (usb_interface_descriptor_t *)p; |
370 | DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d " | | 370 | DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d " |
371 | "type=%d\n", | | 371 | "type=%d\n", |
372 | ifaceidx, curidx, altidx, curaidx, | | 372 | ifaceidx, curidx, altidx, curaidx, |
373 | d->bLength, d->bDescriptorType)); | | 373 | d->bLength, d->bDescriptorType)); |
374 | if (d->bLength == 0) /* bad descriptor */ | | 374 | if (d->bLength == 0) /* bad descriptor */ |
375 | break; | | 375 | break; |
376 | p += d->bLength; | | 376 | p += d->bLength; |
377 | if (p <= end && d->bDescriptorType == UDESC_INTERFACE) { | | 377 | if (p <= end && d->bDescriptorType == UDESC_INTERFACE) { |
378 | if (d->bInterfaceNumber != lastidx) { | | 378 | if (d->bInterfaceNumber != lastidx) { |
379 | lastidx = d->bInterfaceNumber; | | 379 | lastidx = d->bInterfaceNumber; |
380 | curidx++; | | 380 | curidx++; |
381 | curaidx = 0; | | 381 | curaidx = 0; |
382 | } else | | 382 | } else |
383 | curaidx++; | | 383 | curaidx++; |
384 | if (ifaceidx == curidx && altidx == curaidx) | | 384 | if (ifaceidx == curidx && altidx == curaidx) |
385 | return (d); | | 385 | return (d); |
386 | } | | 386 | } |
387 | } | | 387 | } |
388 | return (NULL); | | 388 | return (NULL); |
389 | } | | 389 | } |
390 | | | 390 | |
391 | usb_endpoint_descriptor_t * | | 391 | usb_endpoint_descriptor_t * |
392 | usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx, | | 392 | usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx, |
393 | int endptidx) | | 393 | int endptidx) |
394 | { | | 394 | { |
395 | char *p = (char *)cd; | | 395 | char *p = (char *)cd; |
396 | char *end = p + UGETW(cd->wTotalLength); | | 396 | char *end = p + UGETW(cd->wTotalLength); |
397 | usb_interface_descriptor_t *d; | | 397 | usb_interface_descriptor_t *d; |
398 | usb_endpoint_descriptor_t *e; | | 398 | usb_endpoint_descriptor_t *e; |
399 | int curidx; | | 399 | int curidx; |
400 | | | 400 | |
401 | d = usbd_find_idesc(cd, ifaceidx, altidx); | | 401 | d = usbd_find_idesc(cd, ifaceidx, altidx); |
402 | if (d == NULL) | | 402 | if (d == NULL) |
403 | return (NULL); | | 403 | return (NULL); |
404 | if (endptidx >= d->bNumEndpoints) /* quick exit */ | | 404 | if (endptidx >= d->bNumEndpoints) /* quick exit */ |
405 | return (NULL); | | 405 | return (NULL); |
406 | | | 406 | |
407 | curidx = -1; | | 407 | curidx = -1; |
408 | for (p = (char *)d + d->bLength; p < end; ) { | | 408 | for (p = (char *)d + d->bLength; p < end; ) { |
409 | e = (usb_endpoint_descriptor_t *)p; | | 409 | e = (usb_endpoint_descriptor_t *)p; |
410 | if (e->bLength == 0) /* bad descriptor */ | | 410 | if (e->bLength == 0) /* bad descriptor */ |
411 | break; | | 411 | break; |
412 | p += e->bLength; | | 412 | p += e->bLength; |
413 | if (p <= end && e->bDescriptorType == UDESC_INTERFACE) | | 413 | if (p <= end && e->bDescriptorType == UDESC_INTERFACE) |
414 | return (NULL); | | 414 | return (NULL); |
415 | if (p <= end && e->bDescriptorType == UDESC_ENDPOINT) { | | 415 | if (p <= end && e->bDescriptorType == UDESC_ENDPOINT) { |
416 | curidx++; | | 416 | curidx++; |
417 | if (curidx == endptidx) | | 417 | if (curidx == endptidx) |
418 | return (e); | | 418 | return (e); |
419 | } | | 419 | } |
420 | } | | 420 | } |
421 | return (NULL); | | 421 | return (NULL); |
422 | } | | 422 | } |
423 | | | 423 | |
424 | usbd_status | | 424 | usbd_status |
425 | usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx) | | 425 | usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx) |
426 | { | | 426 | { |
427 | usbd_interface_handle ifc = &dev->ifaces[ifaceidx]; | | 427 | usbd_interface_handle ifc = &dev->ifaces[ifaceidx]; |
428 | usb_interface_descriptor_t *idesc; | | 428 | usb_interface_descriptor_t *idesc; |
429 | char *p, *end; | | 429 | char *p, *end; |
430 | int endpt, nendpt; | | 430 | int endpt, nendpt; |
431 | | | 431 | |
432 | DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n", | | 432 | DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n", |
433 | ifaceidx, altidx)); | | 433 | ifaceidx, altidx)); |
434 | idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx); | | 434 | idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx); |
435 | if (idesc == NULL) | | 435 | if (idesc == NULL) |
436 | return (USBD_INVAL); | | 436 | return (USBD_INVAL); |
437 | ifc->device = dev; | | 437 | ifc->device = dev; |
438 | ifc->idesc = idesc; | | 438 | ifc->idesc = idesc; |
439 | ifc->index = ifaceidx; | | 439 | ifc->index = ifaceidx; |
440 | ifc->altindex = altidx; | | 440 | ifc->altindex = altidx; |
441 | nendpt = ifc->idesc->bNumEndpoints; | | 441 | nendpt = ifc->idesc->bNumEndpoints; |
442 | DPRINTFN(4,("usbd_fill_iface_data: found idesc nendpt=%d\n", nendpt)); | | 442 | DPRINTFN(4,("usbd_fill_iface_data: found idesc nendpt=%d\n", nendpt)); |
443 | if (nendpt != 0) { | | 443 | if (nendpt != 0) { |
444 | ifc->endpoints = malloc(nendpt * sizeof(struct usbd_endpoint), | | 444 | ifc->endpoints = malloc(nendpt * sizeof(struct usbd_endpoint), |
445 | M_USB, M_NOWAIT); | | 445 | M_USB, M_NOWAIT); |
446 | if (ifc->endpoints == NULL) | | 446 | if (ifc->endpoints == NULL) |
447 | return (USBD_NOMEM); | | 447 | return (USBD_NOMEM); |
448 | } else | | 448 | } else |
449 | ifc->endpoints = NULL; | | 449 | ifc->endpoints = NULL; |
450 | ifc->priv = NULL; | | 450 | ifc->priv = NULL; |
451 | p = (char *)ifc->idesc + ifc->idesc->bLength; | | 451 | p = (char *)ifc->idesc + ifc->idesc->bLength; |
452 | end = (char *)dev->cdesc + UGETW(dev->cdesc->wTotalLength); | | 452 | end = (char *)dev->cdesc + UGETW(dev->cdesc->wTotalLength); |
453 | #define ed ((usb_endpoint_descriptor_t *)p) | | 453 | #define ed ((usb_endpoint_descriptor_t *)p) |
454 | for (endpt = 0; endpt < nendpt; endpt++) { | | 454 | for (endpt = 0; endpt < nendpt; endpt++) { |
455 | DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt)); | | 455 | DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt)); |
456 | for (; p < end; p += ed->bLength) { | | 456 | for (; p < end; p += ed->bLength) { |
457 | DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p " | | 457 | DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p " |
458 | "len=%d type=%d\n", | | 458 | "len=%d type=%d\n", |
459 | p, end, ed->bLength, ed->bDescriptorType)); | | 459 | p, end, ed->bLength, ed->bDescriptorType)); |
460 | if (p + ed->bLength <= end && ed->bLength != 0 && | | 460 | if (p + ed->bLength <= end && ed->bLength != 0 && |
461 | ed->bDescriptorType == UDESC_ENDPOINT) | | 461 | ed->bDescriptorType == UDESC_ENDPOINT) |
462 | goto found; | | 462 | goto found; |
463 | if (ed->bLength == 0 || | | 463 | if (ed->bLength == 0 || |
464 | ed->bDescriptorType == UDESC_INTERFACE) | | 464 | ed->bDescriptorType == UDESC_INTERFACE) |
465 | break; | | 465 | break; |
466 | } | | 466 | } |
467 | /* passed end, or bad desc */ | | 467 | /* passed end, or bad desc */ |
468 | printf("usbd_fill_iface_data: bad descriptor(s): %s\n", | | 468 | printf("usbd_fill_iface_data: bad descriptor(s): %s\n", |
469 | ed->bLength == 0 ? "0 length" : | | 469 | ed->bLength == 0 ? "0 length" : |
470 | ed->bDescriptorType == UDESC_INTERFACE ? "iface desc": | | 470 | ed->bDescriptorType == UDESC_INTERFACE ? "iface desc": |
471 | "out of data"); | | 471 | "out of data"); |
472 | goto bad; | | 472 | goto bad; |
473 | found: | | 473 | found: |
474 | ifc->endpoints[endpt].edesc = ed; | | 474 | ifc->endpoints[endpt].edesc = ed; |
475 | if (dev->speed == USB_SPEED_HIGH) { | | 475 | if (dev->speed == USB_SPEED_HIGH) { |
476 | u_int mps; | | 476 | u_int mps; |
477 | /* Control and bulk endpoints have max packet limits. */ | | 477 | /* Control and bulk endpoints have max packet limits. */ |
478 | switch (UE_GET_XFERTYPE(ed->bmAttributes)) { | | 478 | switch (UE_GET_XFERTYPE(ed->bmAttributes)) { |
479 | case UE_CONTROL: | | 479 | case UE_CONTROL: |
480 | mps = USB_2_MAX_CTRL_PACKET; | | 480 | mps = USB_2_MAX_CTRL_PACKET; |
481 | goto check; | | 481 | goto check; |
482 | case UE_BULK: | | 482 | case UE_BULK: |
483 | mps = USB_2_MAX_BULK_PACKET; | | 483 | mps = USB_2_MAX_BULK_PACKET; |
484 | check: | | 484 | check: |
485 | if (UGETW(ed->wMaxPacketSize) != mps) { | | 485 | if (UGETW(ed->wMaxPacketSize) != mps) { |
486 | USETW(ed->wMaxPacketSize, mps); | | 486 | USETW(ed->wMaxPacketSize, mps); |
487 | #ifdef DIAGNOSTIC | | 487 | #ifdef DIAGNOSTIC |
488 | printf("usbd_fill_iface_data: bad max " | | 488 | printf("usbd_fill_iface_data: bad max " |
489 | "packet size\n"); | | 489 | "packet size\n"); |
490 | #endif | | 490 | #endif |
491 | } | | 491 | } |
492 | break; | | 492 | break; |
493 | default: | | 493 | default: |
494 | break; | | 494 | break; |
495 | } | | 495 | } |
496 | } | | 496 | } |
497 | ifc->endpoints[endpt].refcnt = 0; | | 497 | ifc->endpoints[endpt].refcnt = 0; |
498 | ifc->endpoints[endpt].datatoggle = 0; | | 498 | ifc->endpoints[endpt].datatoggle = 0; |
499 | p += ed->bLength; | | 499 | p += ed->bLength; |
500 | } | | 500 | } |
501 | #undef ed | | 501 | #undef ed |
502 | LIST_INIT(&ifc->pipes); | | 502 | LIST_INIT(&ifc->pipes); |
503 | return (USBD_NORMAL_COMPLETION); | | 503 | return (USBD_NORMAL_COMPLETION); |
504 | | | 504 | |
505 | bad: | | 505 | bad: |
506 | if (ifc->endpoints != NULL) { | | 506 | if (ifc->endpoints != NULL) { |
507 | free(ifc->endpoints, M_USB); | | 507 | free(ifc->endpoints, M_USB); |
508 | ifc->endpoints = NULL; | | 508 | ifc->endpoints = NULL; |
509 | } | | 509 | } |
510 | return (USBD_INVAL); | | 510 | return (USBD_INVAL); |
511 | } | | 511 | } |
512 | | | 512 | |
513 | void | | 513 | void |
514 | usbd_free_iface_data(usbd_device_handle dev, int ifcno) | | 514 | usbd_free_iface_data(usbd_device_handle dev, int ifcno) |
515 | { | | 515 | { |
516 | usbd_interface_handle ifc = &dev->ifaces[ifcno]; | | 516 | usbd_interface_handle ifc = &dev->ifaces[ifcno]; |
517 | if (ifc->endpoints) | | 517 | if (ifc->endpoints) |
518 | free(ifc->endpoints, M_USB); | | 518 | free(ifc->endpoints, M_USB); |
519 | } | | 519 | } |
520 | | | 520 | |
521 | Static usbd_status | | 521 | Static usbd_status |
522 | usbd_set_config(usbd_device_handle dev, int conf) | | 522 | usbd_set_config(usbd_device_handle dev, int conf) |
523 | { | | 523 | { |
524 | usb_device_request_t req; | | 524 | usb_device_request_t req; |
525 | | | 525 | |
526 | req.bmRequestType = UT_WRITE_DEVICE; | | 526 | req.bmRequestType = UT_WRITE_DEVICE; |
527 | req.bRequest = UR_SET_CONFIG; | | 527 | req.bRequest = UR_SET_CONFIG; |
528 | USETW(req.wValue, conf); | | 528 | USETW(req.wValue, conf); |
529 | USETW(req.wIndex, 0); | | 529 | USETW(req.wIndex, 0); |
530 | USETW(req.wLength, 0); | | 530 | USETW(req.wLength, 0); |
531 | return (usbd_do_request(dev, &req, 0)); | | 531 | return (usbd_do_request(dev, &req, 0)); |
532 | } | | 532 | } |
533 | | | 533 | |
534 | usbd_status | | 534 | usbd_status |
535 | usbd_set_config_no(usbd_device_handle dev, int no, int msg) | | 535 | usbd_set_config_no(usbd_device_handle dev, int no, int msg) |
536 | { | | 536 | { |
537 | int index; | | 537 | int index; |
538 | usb_config_descriptor_t cd; | | 538 | usb_config_descriptor_t cd; |
539 | usbd_status err; | | 539 | usbd_status err; |
540 | | | 540 | |
541 | if (no == USB_UNCONFIG_NO) | | 541 | if (no == USB_UNCONFIG_NO) |
542 | return (usbd_set_config_index(dev, USB_UNCONFIG_INDEX, msg)); | | 542 | return (usbd_set_config_index(dev, USB_UNCONFIG_INDEX, msg)); |
543 | | | 543 | |
544 | DPRINTFN(5,("usbd_set_config_no: %d\n", no)); | | 544 | DPRINTFN(5,("usbd_set_config_no: %d\n", no)); |
545 | /* Figure out what config index to use. */ | | 545 | /* Figure out what config index to use. */ |
546 | for (index = 0; index < dev->ddesc.bNumConfigurations; index++) { | | 546 | for (index = 0; index < dev->ddesc.bNumConfigurations; index++) { |
547 | err = usbd_get_config_desc(dev, index, &cd); | | 547 | err = usbd_get_config_desc(dev, index, &cd); |
548 | if (err) | | 548 | if (err) |
549 | return (err); | | 549 | return (err); |
550 | if (cd.bConfigurationValue == no) | | 550 | if (cd.bConfigurationValue == no) |
551 | return (usbd_set_config_index(dev, index, msg)); | | 551 | return (usbd_set_config_index(dev, index, msg)); |
552 | } | | 552 | } |
553 | return (USBD_INVAL); | | 553 | return (USBD_INVAL); |
554 | } | | 554 | } |
555 | | | 555 | |
556 | usbd_status | | 556 | usbd_status |
557 | usbd_set_config_index(usbd_device_handle dev, int index, int msg) | | 557 | usbd_set_config_index(usbd_device_handle dev, int index, int msg) |
558 | { | | 558 | { |
559 | usb_config_descriptor_t cd, *cdp; | | 559 | usb_config_descriptor_t cd, *cdp; |
560 | usbd_status err; | | 560 | usbd_status err; |
561 | int i, ifcidx, nifc, len, selfpowered, power; | | 561 | int i, ifcidx, nifc, len, selfpowered, power; |
562 | | | 562 | |
563 | DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index)); | | 563 | DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index)); |
564 | | | 564 | |
565 | if (index >= dev->ddesc.bNumConfigurations && | | 565 | if (index >= dev->ddesc.bNumConfigurations && |
566 | index != USB_UNCONFIG_INDEX) { | | 566 | index != USB_UNCONFIG_INDEX) { |
567 | /* panic? */ | | 567 | /* panic? */ |
568 | printf("usbd_set_config_index: illegal index\n"); | | 568 | printf("usbd_set_config_index: illegal index\n"); |
569 | return (USBD_INVAL); | | 569 | return (USBD_INVAL); |
570 | } | | 570 | } |
571 | | | 571 | |
572 | /* XXX check that all interfaces are idle */ | | 572 | /* XXX check that all interfaces are idle */ |
573 | if (dev->config != USB_UNCONFIG_NO) { | | 573 | if (dev->config != USB_UNCONFIG_NO) { |
574 | DPRINTF(("usbd_set_config_index: free old config\n")); | | 574 | DPRINTF(("usbd_set_config_index: free old config\n")); |
575 | /* Free all configuration data structures. */ | | 575 | /* Free all configuration data structures. */ |
576 | nifc = dev->cdesc->bNumInterface; | | 576 | nifc = dev->cdesc->bNumInterface; |
577 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) | | 577 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) |
578 | usbd_free_iface_data(dev, ifcidx); | | 578 | usbd_free_iface_data(dev, ifcidx); |
579 | free(dev->ifaces, M_USB); | | 579 | free(dev->ifaces, M_USB); |
580 | free(dev->cdesc, M_USB); | | 580 | free(dev->cdesc, M_USB); |
581 | dev->ifaces = NULL; | | 581 | dev->ifaces = NULL; |
582 | dev->cdesc = NULL; | | 582 | dev->cdesc = NULL; |
583 | dev->config = USB_UNCONFIG_NO; | | 583 | dev->config = USB_UNCONFIG_NO; |
584 | } | | 584 | } |
585 | | | 585 | |
586 | if (index == USB_UNCONFIG_INDEX) { | | 586 | if (index == USB_UNCONFIG_INDEX) { |
587 | /* We are unconfiguring the device, so leave unallocated. */ | | 587 | /* We are unconfiguring the device, so leave unallocated. */ |
588 | DPRINTF(("usbd_set_config_index: set config 0\n")); | | 588 | DPRINTF(("usbd_set_config_index: set config 0\n")); |
589 | err = usbd_set_config(dev, USB_UNCONFIG_NO); | | 589 | err = usbd_set_config(dev, USB_UNCONFIG_NO); |
590 | if (err) { | | 590 | if (err) { |
591 | DPRINTF(("usbd_set_config_index: setting config=0 " | | 591 | DPRINTF(("usbd_set_config_index: setting config=0 " |
592 | "failed, error=%s\n", usbd_errstr(err))); | | 592 | "failed, error=%s\n", usbd_errstr(err))); |
593 | } | | 593 | } |
594 | return (err); | | 594 | return (err); |
595 | } | | 595 | } |
596 | | | 596 | |
597 | /* Get the short descriptor. */ | | 597 | /* Get the short descriptor. */ |
598 | err = usbd_get_config_desc(dev, index, &cd); | | 598 | err = usbd_get_config_desc(dev, index, &cd); |
599 | if (err) { | | 599 | if (err) { |
600 | DPRINTF(("usbd_set_config_index: get_config_desc=%d\n", err)); | | 600 | DPRINTF(("usbd_set_config_index: get_config_desc=%d\n", err)); |
601 | return (err); | | 601 | return (err); |
602 | } | | 602 | } |
603 | len = UGETW(cd.wTotalLength); | | 603 | len = UGETW(cd.wTotalLength); |
604 | cdp = malloc(len, M_USB, M_NOWAIT); | | 604 | cdp = malloc(len, M_USB, M_NOWAIT); |
605 | if (cdp == NULL) | | 605 | if (cdp == NULL) |
606 | return (USBD_NOMEM); | | 606 | return (USBD_NOMEM); |
607 | | | 607 | |
608 | /* Get the full descriptor. Try a few times for slow devices. */ | | 608 | /* Get the full descriptor. Try a few times for slow devices. */ |
609 | for (i = 0; i < 3; i++) { | | 609 | for (i = 0; i < 3; i++) { |
610 | err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp); | | 610 | err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp); |
611 | if (!err) | | 611 | if (!err) |
612 | break; | | 612 | break; |
613 | usbd_delay_ms(dev, 200); | | 613 | usbd_delay_ms(dev, 200); |
614 | } | | 614 | } |
615 | if (err) { | | 615 | if (err) { |
616 | DPRINTF(("usbd_set_config_index: get_desc=%d\n", err)); | | 616 | DPRINTF(("usbd_set_config_index: get_desc=%d\n", err)); |
617 | goto bad; | | 617 | goto bad; |
618 | } | | 618 | } |
619 | if (cdp->bDescriptorType != UDESC_CONFIG) { | | 619 | if (cdp->bDescriptorType != UDESC_CONFIG) { |
620 | DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n", | | 620 | DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n", |
621 | cdp->bDescriptorType)); | | 621 | cdp->bDescriptorType)); |
622 | err = USBD_INVAL; | | 622 | err = USBD_INVAL; |
623 | goto bad; | | 623 | goto bad; |
624 | } | | 624 | } |
625 | | | 625 | |
626 | /* | | 626 | /* |
627 | * Figure out if the device is self or bus powered. | | 627 | * Figure out if the device is self or bus powered. |
628 | */ | | 628 | */ |
629 | #if 0 /* XXX various devices don't report the power state correctly */ | | 629 | #if 0 /* XXX various devices don't report the power state correctly */ |
630 | selfpowered = 0; | | 630 | selfpowered = 0; |
631 | err = usbd_get_device_status(dev, &ds); | | 631 | err = usbd_get_device_status(dev, &ds); |
632 | if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED)) | | 632 | if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED)) |
633 | selfpowered = 1; | | 633 | selfpowered = 1; |
634 | #endif | | 634 | #endif |
635 | /* | | 635 | /* |
636 | * Use the power state in the configuration we are going | | 636 | * Use the power state in the configuration we are going |
637 | * to set. This doesn't necessarily reflect the actual | | 637 | * to set. This doesn't necessarily reflect the actual |
638 | * power state of the device; the driver can control this | | 638 | * power state of the device; the driver can control this |
639 | * by choosing the appropriate configuration. | | 639 | * by choosing the appropriate configuration. |
640 | */ | | 640 | */ |
641 | selfpowered = !!(cdp->bmAttributes & UC_SELF_POWERED); | | 641 | selfpowered = !!(cdp->bmAttributes & UC_SELF_POWERED); |
642 | | | 642 | |
643 | DPRINTF(("usbd_set_config_index: (addr %d) cno=%d attr=0x%02x, " | | 643 | DPRINTF(("usbd_set_config_index: (addr %d) cno=%d attr=0x%02x, " |
644 | "selfpowered=%d, power=%d\n", | | 644 | "selfpowered=%d, power=%d\n", |
645 | cdp->bConfigurationValue, dev->address, cdp->bmAttributes, | | 645 | cdp->bConfigurationValue, dev->address, cdp->bmAttributes, |
646 | selfpowered, cdp->bMaxPower * 2)); | | 646 | selfpowered, cdp->bMaxPower * 2)); |
647 | | | 647 | |
648 | /* Check if we have enough power. */ | | 648 | /* Check if we have enough power. */ |
649 | #if 0 /* this is a no-op, see above */ | | 649 | #if 0 /* this is a no-op, see above */ |
650 | if ((cdp->bmAttributes & UC_SELF_POWERED) && !selfpowered) { | | 650 | if ((cdp->bmAttributes & UC_SELF_POWERED) && !selfpowered) { |
651 | if (msg) | | 651 | if (msg) |
652 | printf("%s: device addr %d (config %d): " | | 652 | printf("%s: device addr %d (config %d): " |
653 | "can't set self powered configuration\n", | | 653 | "can't set self powered configuration\n", |
654 | device_xname(dev->bus->bdev), dev->address, | | 654 | device_xname(dev->bus->bdev), dev->address, |
655 | cdp->bConfigurationValue); | | 655 | cdp->bConfigurationValue); |
656 | err = USBD_NO_POWER; | | 656 | err = USBD_NO_POWER; |
657 | goto bad; | | 657 | goto bad; |
658 | } | | 658 | } |
659 | #endif | | 659 | #endif |
660 | #ifdef USB_DEBUG | | 660 | #ifdef USB_DEBUG |
661 | if (dev->powersrc == NULL) { | | 661 | if (dev->powersrc == NULL) { |
662 | DPRINTF(("usbd_set_config_index: No power source?\n")); | | 662 | DPRINTF(("usbd_set_config_index: No power source?\n")); |
663 | err = USBD_IOERROR; | | 663 | err = USBD_IOERROR; |
664 | goto bad; | | 664 | goto bad; |
665 | } | | 665 | } |
666 | #endif | | 666 | #endif |
667 | power = cdp->bMaxPower * 2; | | 667 | power = cdp->bMaxPower * 2; |
668 | if (power > dev->powersrc->power) { | | 668 | if (power > dev->powersrc->power) { |
669 | DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power)); | | 669 | DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power)); |
670 | /* XXX print nicer message. */ | | 670 | /* XXX print nicer message. */ |
671 | if (msg) | | 671 | if (msg) |
672 | printf("%s: device addr %d (config %d) exceeds power " | | 672 | printf("%s: device addr %d (config %d) exceeds power " |
673 | "budget, %d mA > %d mA\n", | | 673 | "budget, %d mA > %d mA\n", |
674 | device_xname(dev->bus->usbctl), dev->address, | | 674 | device_xname(dev->bus->usbctl), dev->address, |
675 | cdp->bConfigurationValue, | | 675 | cdp->bConfigurationValue, |
676 | power, dev->powersrc->power); | | 676 | power, dev->powersrc->power); |
677 | err = USBD_NO_POWER; | | 677 | err = USBD_NO_POWER; |
678 | goto bad; | | 678 | goto bad; |
679 | } | | 679 | } |
680 | dev->power = power; | | 680 | dev->power = power; |
681 | dev->self_powered = selfpowered; | | 681 | dev->self_powered = selfpowered; |
682 | | | 682 | |
683 | /* Set the actual configuration value. */ | | 683 | /* Set the actual configuration value. */ |
684 | DPRINTF(("usbd_set_config_index: set config %d\n", | | 684 | DPRINTF(("usbd_set_config_index: set config %d\n", |
685 | cdp->bConfigurationValue)); | | 685 | cdp->bConfigurationValue)); |
686 | err = usbd_set_config(dev, cdp->bConfigurationValue); | | 686 | err = usbd_set_config(dev, cdp->bConfigurationValue); |
687 | if (err) { | | 687 | if (err) { |
688 | DPRINTF(("usbd_set_config_index: setting config=%d failed, " | | 688 | DPRINTF(("usbd_set_config_index: setting config=%d failed, " |
689 | "error=%s\n", | | 689 | "error=%s\n", |
690 | cdp->bConfigurationValue, usbd_errstr(err))); | | 690 | cdp->bConfigurationValue, usbd_errstr(err))); |
691 | goto bad; | | 691 | goto bad; |
692 | } | | 692 | } |
693 | | | 693 | |
694 | /* Allocate and fill interface data. */ | | 694 | /* Allocate and fill interface data. */ |
695 | nifc = cdp->bNumInterface; | | 695 | nifc = cdp->bNumInterface; |
696 | dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), | | 696 | dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), |
697 | M_USB, M_NOWAIT); | | 697 | M_USB, M_NOWAIT); |
698 | if (dev->ifaces == NULL) { | | 698 | if (dev->ifaces == NULL) { |
699 | err = USBD_NOMEM; | | 699 | err = USBD_NOMEM; |
700 | goto bad; | | 700 | goto bad; |
701 | } | | 701 | } |
702 | DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp)); | | 702 | DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp)); |
703 | dev->cdesc = cdp; | | 703 | dev->cdesc = cdp; |
704 | dev->config = cdp->bConfigurationValue; | | 704 | dev->config = cdp->bConfigurationValue; |
705 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) { | | 705 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) { |
706 | err = usbd_fill_iface_data(dev, ifcidx, 0); | | 706 | err = usbd_fill_iface_data(dev, ifcidx, 0); |
707 | if (err) { | | 707 | if (err) { |
708 | while (--ifcidx >= 0) | | 708 | while (--ifcidx >= 0) |
709 | usbd_free_iface_data(dev, ifcidx); | | 709 | usbd_free_iface_data(dev, ifcidx); |
710 | goto bad; | | 710 | goto bad; |
711 | } | | 711 | } |
712 | } | | 712 | } |
713 | | | 713 | |
714 | return (USBD_NORMAL_COMPLETION); | | 714 | return (USBD_NORMAL_COMPLETION); |
715 | | | 715 | |
716 | bad: | | 716 | bad: |
717 | free(cdp, M_USB); | | 717 | free(cdp, M_USB); |
718 | return (err); | | 718 | return (err); |
719 | } | | 719 | } |
720 | | | 720 | |
721 | /* XXX add function for alternate settings */ | | 721 | /* XXX add function for alternate settings */ |
722 | | | 722 | |
723 | usbd_status | | 723 | usbd_status |
724 | usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface, | | 724 | usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface, |
725 | struct usbd_endpoint *ep, int ival, usbd_pipe_handle *pipe) | | 725 | struct usbd_endpoint *ep, int ival, usbd_pipe_handle *pipe) |
726 | { | | 726 | { |
727 | usbd_pipe_handle p; | | 727 | usbd_pipe_handle p; |
728 | usbd_status err; | | 728 | usbd_status err; |
729 | | | 729 | |
730 | DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n", | | 730 | DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n", |
731 | dev, iface, ep, pipe)); | | 731 | dev, iface, ep, pipe)); |
732 | p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT); | | 732 | p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT); |
733 | if (p == NULL) | | 733 | if (p == NULL) |
734 | return (USBD_NOMEM); | | 734 | return (USBD_NOMEM); |
735 | p->device = dev; | | 735 | p->device = dev; |
736 | p->iface = iface; | | 736 | p->iface = iface; |
737 | p->endpoint = ep; | | 737 | p->endpoint = ep; |
738 | ep->refcnt++; | | 738 | ep->refcnt++; |
739 | p->refcnt = 1; | | 739 | p->refcnt = 1; |
740 | p->intrxfer = 0; | | 740 | p->intrxfer = 0; |
741 | p->running = 0; | | 741 | p->running = 0; |
742 | p->aborting = 0; | | 742 | p->aborting = 0; |
743 | p->repeat = 0; | | 743 | p->repeat = 0; |
744 | p->interval = ival; | | 744 | p->interval = ival; |
745 | SIMPLEQ_INIT(&p->queue); | | 745 | SIMPLEQ_INIT(&p->queue); |
746 | err = dev->bus->methods->open_pipe(p); | | 746 | err = dev->bus->methods->open_pipe(p); |
747 | if (err) { | | 747 | if (err) { |
748 | DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error=" | | 748 | DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error=" |
749 | "%s\n", | | 749 | "%s\n", |
750 | ep->edesc->bEndpointAddress, usbd_errstr(err))); | | 750 | ep->edesc->bEndpointAddress, usbd_errstr(err))); |
751 | free(p, M_USB); | | 751 | free(p, M_USB); |
752 | return (err); | | 752 | return (err); |
753 | } | | 753 | } |
754 | #if 1 | | | |
755 | if (dev->bus->methods->get_locks) { | | | |
756 | dev->bus->methods->get_locks(dev->bus, &p->intr_lock, &p->lock); | | | |
757 | } else { | | | |
758 | p->intr_lock = p->lock = NULL; | | | |
759 | } | | | |
760 | #endif | | | |
761 | *pipe = p; | | 754 | *pipe = p; |
762 | return (USBD_NORMAL_COMPLETION); | | 755 | return (USBD_NORMAL_COMPLETION); |
763 | } | | 756 | } |
764 | | | 757 | |
765 | /* Abort the device control pipe. */ | | 758 | /* Abort the device control pipe. */ |
766 | void | | 759 | void |
767 | usbd_kill_pipe(usbd_pipe_handle pipe) | | 760 | usbd_kill_pipe(usbd_pipe_handle pipe) |
768 | { | | 761 | { |
769 | usbd_abort_pipe(pipe); | | 762 | usbd_abort_pipe(pipe); |
770 | pipe->methods->close(pipe); | | 763 | pipe->methods->close(pipe); |
771 | pipe->endpoint->refcnt--; | | 764 | pipe->endpoint->refcnt--; |
772 | free(pipe, M_USB); | | 765 | free(pipe, M_USB); |
773 | } | | 766 | } |
774 | | | 767 | |
775 | int | | 768 | int |
776 | usbd_getnewaddr(usbd_bus_handle bus) | | 769 | usbd_getnewaddr(usbd_bus_handle bus) |
777 | { | | 770 | { |
778 | int addr; | | 771 | int addr; |
779 | | | 772 | |
780 | for (addr = 1; addr < USB_MAX_DEVICES; addr++) | | 773 | for (addr = 1; addr < USB_MAX_DEVICES; addr++) |
781 | if (bus->devices[addr] == 0) | | 774 | if (bus->devices[addr] == 0) |
782 | return (addr); | | 775 | return (addr); |
783 | return (-1); | | 776 | return (-1); |
784 | } | | 777 | } |
785 | | | 778 | |
786 | usbd_status | | 779 | usbd_status |
787 | usbd_attach_roothub(device_t parent, usbd_device_handle dev) | | 780 | usbd_attach_roothub(device_t parent, usbd_device_handle dev) |
788 | { | | 781 | { |
789 | struct usb_attach_arg uaa; | | 782 | struct usb_attach_arg uaa; |
790 | usb_device_descriptor_t *dd = &dev->ddesc; | | 783 | usb_device_descriptor_t *dd = &dev->ddesc; |
791 | device_t dv; | | 784 | device_t dv; |
792 | | | 785 | |
793 | uaa.device = dev; | | 786 | uaa.device = dev; |
794 | uaa.usegeneric = 0; | | 787 | uaa.usegeneric = 0; |
795 | uaa.port = 0; | | 788 | uaa.port = 0; |
796 | uaa.vendor = UGETW(dd->idVendor); | | 789 | uaa.vendor = UGETW(dd->idVendor); |
797 | uaa.product = UGETW(dd->idProduct); | | 790 | uaa.product = UGETW(dd->idProduct); |
798 | uaa.release = UGETW(dd->bcdDevice); | | 791 | uaa.release = UGETW(dd->bcdDevice); |
799 | uaa.class = dd->bDeviceClass; | | 792 | uaa.class = dd->bDeviceClass; |
800 | uaa.subclass = dd->bDeviceSubClass; | | 793 | uaa.subclass = dd->bDeviceSubClass; |
801 | uaa.proto = dd->bDeviceProtocol; | | 794 | uaa.proto = dd->bDeviceProtocol; |
802 | | | 795 | |
803 | dv = config_found_ia(parent, "usbroothubif", &uaa, 0); | | 796 | dv = config_found_ia(parent, "usbroothubif", &uaa, 0); |
804 | if (dv) { | | 797 | if (dv) { |
805 | dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); | | 798 | dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); |
806 | if (dev->subdevs == NULL) | | 799 | if (dev->subdevs == NULL) |
807 | return (USBD_NOMEM); | | 800 | return (USBD_NOMEM); |
808 | dev->subdevs[0] = dv; | | 801 | dev->subdevs[0] = dv; |
809 | dev->subdevlen = 1; | | 802 | dev->subdevlen = 1; |
810 | } | | 803 | } |
811 | return (USBD_NORMAL_COMPLETION); | | 804 | return (USBD_NORMAL_COMPLETION); |
812 | } | | 805 | } |
813 | | | 806 | |
814 | static usbd_status | | 807 | static usbd_status |
815 | usbd_attachwholedevice(device_t parent, usbd_device_handle dev, int port, | | 808 | usbd_attachwholedevice(device_t parent, usbd_device_handle dev, int port, |
816 | int usegeneric) | | 809 | int usegeneric) |
817 | { | | 810 | { |
818 | struct usb_attach_arg uaa; | | 811 | struct usb_attach_arg uaa; |
819 | usb_device_descriptor_t *dd = &dev->ddesc; | | 812 | usb_device_descriptor_t *dd = &dev->ddesc; |
820 | device_t dv; | | 813 | device_t dv; |
821 | int dlocs[USBDEVIFCF_NLOCS]; | | 814 | int dlocs[USBDEVIFCF_NLOCS]; |
822 | | | 815 | |
823 | uaa.device = dev; | | 816 | uaa.device = dev; |
824 | uaa.usegeneric = usegeneric; | | 817 | uaa.usegeneric = usegeneric; |
825 | uaa.port = port; | | 818 | uaa.port = port; |
826 | uaa.vendor = UGETW(dd->idVendor); | | 819 | uaa.vendor = UGETW(dd->idVendor); |
827 | uaa.product = UGETW(dd->idProduct); | | 820 | uaa.product = UGETW(dd->idProduct); |
828 | uaa.release = UGETW(dd->bcdDevice); | | 821 | uaa.release = UGETW(dd->bcdDevice); |
829 | uaa.class = dd->bDeviceClass; | | 822 | uaa.class = dd->bDeviceClass; |
830 | uaa.subclass = dd->bDeviceSubClass; | | 823 | uaa.subclass = dd->bDeviceSubClass; |
831 | uaa.proto = dd->bDeviceProtocol; | | 824 | uaa.proto = dd->bDeviceProtocol; |
832 | | | 825 | |
833 | dlocs[USBDEVIFCF_PORT] = uaa.port; | | 826 | dlocs[USBDEVIFCF_PORT] = uaa.port; |
834 | dlocs[USBDEVIFCF_VENDOR] = uaa.vendor; | | 827 | dlocs[USBDEVIFCF_VENDOR] = uaa.vendor; |
835 | dlocs[USBDEVIFCF_PRODUCT] = uaa.product; | | 828 | dlocs[USBDEVIFCF_PRODUCT] = uaa.product; |
836 | dlocs[USBDEVIFCF_RELEASE] = uaa.release; | | 829 | dlocs[USBDEVIFCF_RELEASE] = uaa.release; |
837 | /* the rest is historical ballast */ | | 830 | /* the rest is historical ballast */ |
838 | dlocs[USBDEVIFCF_CONFIGURATION] = -1; | | 831 | dlocs[USBDEVIFCF_CONFIGURATION] = -1; |
839 | dlocs[USBDEVIFCF_INTERFACE] = -1; | | 832 | dlocs[USBDEVIFCF_INTERFACE] = -1; |
840 | | | 833 | |
841 | dv = config_found_sm_loc(parent, "usbdevif", dlocs, &uaa, usbd_print, | | 834 | dv = config_found_sm_loc(parent, "usbdevif", dlocs, &uaa, usbd_print, |
842 | config_stdsubmatch); | | 835 | config_stdsubmatch); |
843 | if (dv) { | | 836 | if (dv) { |
844 | dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); | | 837 | dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT); |
845 | if (dev->subdevs == NULL) | | 838 | if (dev->subdevs == NULL) |
846 | return (USBD_NOMEM); | | 839 | return (USBD_NOMEM); |
847 | dev->subdevs[0] = dv; | | 840 | dev->subdevs[0] = dv; |
848 | dev->subdevlen = 1; | | 841 | dev->subdevlen = 1; |
849 | dev->nifaces_claimed = 1; /* XXX */ | | 842 | dev->nifaces_claimed = 1; /* XXX */ |
850 | } | | 843 | } |
851 | return (USBD_NORMAL_COMPLETION); | | 844 | return (USBD_NORMAL_COMPLETION); |
852 | } | | 845 | } |
853 | | | 846 | |
854 | static usbd_status | | 847 | static usbd_status |
855 | usbd_attachinterfaces(device_t parent, usbd_device_handle dev, | | 848 | usbd_attachinterfaces(device_t parent, usbd_device_handle dev, |
856 | int port, const int *locators) | | 849 | int port, const int *locators) |
857 | { | | 850 | { |
858 | struct usbif_attach_arg uiaa; | | 851 | struct usbif_attach_arg uiaa; |
859 | int ilocs[USBIFIFCF_NLOCS]; | | 852 | int ilocs[USBIFIFCF_NLOCS]; |
860 | usb_device_descriptor_t *dd = &dev->ddesc; | | 853 | usb_device_descriptor_t *dd = &dev->ddesc; |
861 | int nifaces; | | 854 | int nifaces; |
862 | usbd_interface_handle *ifaces; | | 855 | usbd_interface_handle *ifaces; |
863 | int i, j, loc; | | 856 | int i, j, loc; |
864 | device_t dv; | | 857 | device_t dv; |
865 | | | 858 | |
866 | nifaces = dev->cdesc->bNumInterface; | | 859 | nifaces = dev->cdesc->bNumInterface; |
867 | ifaces = malloc(nifaces * sizeof(*ifaces), M_USB, M_NOWAIT|M_ZERO); | | 860 | ifaces = malloc(nifaces * sizeof(*ifaces), M_USB, M_NOWAIT|M_ZERO); |
868 | if (!ifaces) | | 861 | if (!ifaces) |
869 | return (USBD_NOMEM); | | 862 | return (USBD_NOMEM); |
870 | for (i = 0; i < nifaces; i++) | | 863 | for (i = 0; i < nifaces; i++) |
871 | if (!dev->subdevs[i]) | | 864 | if (!dev->subdevs[i]) |
872 | ifaces[i] = &dev->ifaces[i]; | | 865 | ifaces[i] = &dev->ifaces[i]; |
873 | | | 866 | |
874 | uiaa.device = dev; | | 867 | uiaa.device = dev; |
875 | uiaa.port = port; | | 868 | uiaa.port = port; |
876 | uiaa.vendor = UGETW(dd->idVendor); | | 869 | uiaa.vendor = UGETW(dd->idVendor); |
877 | uiaa.product = UGETW(dd->idProduct); | | 870 | uiaa.product = UGETW(dd->idProduct); |
878 | uiaa.release = UGETW(dd->bcdDevice); | | 871 | uiaa.release = UGETW(dd->bcdDevice); |
879 | uiaa.configno = dev->cdesc->bConfigurationValue; | | 872 | uiaa.configno = dev->cdesc->bConfigurationValue; |
880 | uiaa.ifaces = ifaces; | | 873 | uiaa.ifaces = ifaces; |
881 | uiaa.nifaces = nifaces; | | 874 | uiaa.nifaces = nifaces; |
882 | ilocs[USBIFIFCF_PORT] = uiaa.port; | | 875 | ilocs[USBIFIFCF_PORT] = uiaa.port; |
883 | ilocs[USBIFIFCF_VENDOR] = uiaa.vendor; | | 876 | ilocs[USBIFIFCF_VENDOR] = uiaa.vendor; |
884 | ilocs[USBIFIFCF_PRODUCT] = uiaa.product; | | 877 | ilocs[USBIFIFCF_PRODUCT] = uiaa.product; |
885 | ilocs[USBIFIFCF_RELEASE] = uiaa.release; | | 878 | ilocs[USBIFIFCF_RELEASE] = uiaa.release; |
886 | ilocs[USBIFIFCF_CONFIGURATION] = uiaa.configno; | | 879 | ilocs[USBIFIFCF_CONFIGURATION] = uiaa.configno; |
887 | | | 880 | |
888 | for (i = 0; i < nifaces; i++) { | | 881 | for (i = 0; i < nifaces; i++) { |
889 | if (!ifaces[i]) | | 882 | if (!ifaces[i]) |
890 | continue; /* interface already claimed */ | | 883 | continue; /* interface already claimed */ |
891 | uiaa.iface = ifaces[i]; | | 884 | uiaa.iface = ifaces[i]; |
892 | uiaa.class = ifaces[i]->idesc->bInterfaceClass; | | 885 | uiaa.class = ifaces[i]->idesc->bInterfaceClass; |
893 | uiaa.subclass = ifaces[i]->idesc->bInterfaceSubClass; | | 886 | uiaa.subclass = ifaces[i]->idesc->bInterfaceSubClass; |
894 | uiaa.proto = ifaces[i]->idesc->bInterfaceProtocol; | | 887 | uiaa.proto = ifaces[i]->idesc->bInterfaceProtocol; |
895 | uiaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; | | 888 | uiaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; |
896 | ilocs[USBIFIFCF_INTERFACE] = uiaa.ifaceno; | | 889 | ilocs[USBIFIFCF_INTERFACE] = uiaa.ifaceno; |
897 | if (locators != NULL) { | | 890 | if (locators != NULL) { |
898 | loc = locators[USBIFIFCF_CONFIGURATION]; | | 891 | loc = locators[USBIFIFCF_CONFIGURATION]; |
899 | if (loc != USBIFIFCF_CONFIGURATION_DEFAULT && | | 892 | if (loc != USBIFIFCF_CONFIGURATION_DEFAULT && |
900 | loc != uiaa.configno) | | 893 | loc != uiaa.configno) |
901 | continue; | | 894 | continue; |
902 | loc = locators[USBIFIFCF_INTERFACE]; | | 895 | loc = locators[USBIFIFCF_INTERFACE]; |
903 | if (loc != USBIFIFCF_INTERFACE && loc != uiaa.ifaceno) | | 896 | if (loc != USBIFIFCF_INTERFACE && loc != uiaa.ifaceno) |
904 | continue; | | 897 | continue; |
905 | } | | 898 | } |
906 | dv = config_found_sm_loc(parent, "usbifif", ilocs, &uiaa, | | 899 | dv = config_found_sm_loc(parent, "usbifif", ilocs, &uiaa, |
907 | usbd_ifprint, config_stdsubmatch); | | 900 | usbd_ifprint, config_stdsubmatch); |
908 | if (!dv) | | 901 | if (!dv) |
909 | continue; | | 902 | continue; |
910 | ifaces[i] = 0; /* claim */ | | 903 | ifaces[i] = 0; /* claim */ |
911 | /* account for ifaces claimed by the driver behind our back */ | | 904 | /* account for ifaces claimed by the driver behind our back */ |
912 | for (j = 0; j < nifaces; j++) { | | 905 | for (j = 0; j < nifaces; j++) { |
913 | if (!ifaces[j] && !dev->subdevs[j]) { | | 906 | if (!ifaces[j] && !dev->subdevs[j]) { |
914 | dev->subdevs[j] = dv; | | 907 | dev->subdevs[j] = dv; |
915 | dev->nifaces_claimed++; | | 908 | dev->nifaces_claimed++; |
916 | } | | 909 | } |
917 | } | | 910 | } |
918 | } | | 911 | } |
919 | | | 912 | |
920 | free(ifaces, M_USB); | | 913 | free(ifaces, M_USB); |
921 | return (USBD_NORMAL_COMPLETION); | | 914 | return (USBD_NORMAL_COMPLETION); |
922 | } | | 915 | } |
923 | | | 916 | |
924 | usbd_status | | 917 | usbd_status |
925 | usbd_probe_and_attach(device_t parent, usbd_device_handle dev, | | 918 | usbd_probe_and_attach(device_t parent, usbd_device_handle dev, |
926 | int port, int addr) | | 919 | int port, int addr) |
927 | { | | 920 | { |
928 | usb_device_descriptor_t *dd = &dev->ddesc; | | 921 | usb_device_descriptor_t *dd = &dev->ddesc; |
929 | int confi, nifaces; | | 922 | int confi, nifaces; |
930 | usbd_status err; | | 923 | usbd_status err; |
931 | | | 924 | |
932 | /* First try with device specific drivers. */ | | 925 | /* First try with device specific drivers. */ |
933 | DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n")); | | 926 | DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n")); |
934 | err = usbd_attachwholedevice(parent, dev, port, 0); | | 927 | err = usbd_attachwholedevice(parent, dev, port, 0); |
935 | if (dev->nifaces_claimed || err) | | 928 | if (dev->nifaces_claimed || err) |
936 | return (err); | | 929 | return (err); |
937 | DPRINTF(("usbd_probe_and_attach: no device specific driver found\n")); | | 930 | DPRINTF(("usbd_probe_and_attach: no device specific driver found\n")); |
938 | | | 931 | |
939 | DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n", | | 932 | DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n", |
940 | dd->bNumConfigurations)); | | 933 | dd->bNumConfigurations)); |
941 | for (confi = 0; confi < dd->bNumConfigurations; confi++) { | | 934 | for (confi = 0; confi < dd->bNumConfigurations; confi++) { |
942 | DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n", | | 935 | DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n", |
943 | confi)); | | 936 | confi)); |
944 | err = usbd_set_config_index(dev, confi, 1); | | 937 | err = usbd_set_config_index(dev, confi, 1); |
945 | if (err) { | | 938 | if (err) { |
946 | #ifdef USB_DEBUG | | 939 | #ifdef USB_DEBUG |
947 | DPRINTF(("%s: port %d, set config at addr %d failed, " | | 940 | DPRINTF(("%s: port %d, set config at addr %d failed, " |
948 | "error=%s\n", device_xname(parent), port, | | 941 | "error=%s\n", device_xname(parent), port, |
949 | addr, usbd_errstr(err))); | | 942 | addr, usbd_errstr(err))); |
950 | #else | | 943 | #else |
951 | printf("%s: port %d, set config at addr %d failed\n", | | 944 | printf("%s: port %d, set config at addr %d failed\n", |
952 | device_xname(parent), port, addr); | | 945 | device_xname(parent), port, addr); |
953 | #endif | | 946 | #endif |
954 | return (err); | | 947 | return (err); |
955 | } | | 948 | } |
956 | nifaces = dev->cdesc->bNumInterface; | | 949 | nifaces = dev->cdesc->bNumInterface; |
957 | dev->subdevs = malloc(nifaces * sizeof(device_t), M_USB, | | 950 | dev->subdevs = malloc(nifaces * sizeof(device_t), M_USB, |
958 | M_NOWAIT|M_ZERO); | | 951 | M_NOWAIT|M_ZERO); |
959 | if (dev->subdevs == NULL) | | 952 | if (dev->subdevs == NULL) |
960 | return (USBD_NOMEM); | | 953 | return (USBD_NOMEM); |
961 | dev->subdevlen = nifaces; | | 954 | dev->subdevlen = nifaces; |
962 | | | 955 | |
963 | err = usbd_attachinterfaces(parent, dev, port, NULL); | | 956 | err = usbd_attachinterfaces(parent, dev, port, NULL); |
964 | | | 957 | |
965 | if (!dev->nifaces_claimed) { | | 958 | if (!dev->nifaces_claimed) { |
966 | free(dev->subdevs, M_USB); | | 959 | free(dev->subdevs, M_USB); |
967 | dev->subdevs = 0; | | 960 | dev->subdevs = 0; |
968 | dev->subdevlen = 0; | | 961 | dev->subdevlen = 0; |
969 | } | | 962 | } |
970 | if (dev->nifaces_claimed || err) | | 963 | if (dev->nifaces_claimed || err) |
971 | return (err); | | 964 | return (err); |
972 | } | | 965 | } |
973 | /* No interfaces were attached in any of the configurations. */ | | 966 | /* No interfaces were attached in any of the configurations. */ |
974 | | | 967 | |
975 | if (dd->bNumConfigurations > 1) /* don't change if only 1 config */ | | 968 | if (dd->bNumConfigurations > 1) /* don't change if only 1 config */ |
976 | usbd_set_config_index(dev, 0, 0); | | 969 | usbd_set_config_index(dev, 0, 0); |
977 | | | 970 | |
978 | DPRINTF(("usbd_probe_and_attach: no interface drivers found\n")); | | 971 | DPRINTF(("usbd_probe_and_attach: no interface drivers found\n")); |
979 | | | 972 | |
980 | /* Finally try the generic driver. */ | | 973 | /* Finally try the generic driver. */ |
981 | err = usbd_attachwholedevice(parent, dev, port, 1); | | 974 | err = usbd_attachwholedevice(parent, dev, port, 1); |
982 | | | 975 | |
983 | /* | | 976 | /* |
984 | * The generic attach failed, but leave the device as it is. | | 977 | * The generic attach failed, but leave the device as it is. |
985 | * We just did not find any drivers, that's all. The device is | | 978 | * We just did not find any drivers, that's all. The device is |
986 | * fully operational and not harming anyone. | | 979 | * fully operational and not harming anyone. |
987 | */ | | 980 | */ |
988 | DPRINTF(("usbd_probe_and_attach: generic attach failed\n")); | | 981 | DPRINTF(("usbd_probe_and_attach: generic attach failed\n")); |
989 | return (USBD_NORMAL_COMPLETION); | | 982 | return (USBD_NORMAL_COMPLETION); |
990 | } | | 983 | } |
991 | | | 984 | |
992 | /** | | 985 | /** |
993 | * Called from uhub_rescan(). usbd_new_device() for the target dev must be | | 986 | * Called from uhub_rescan(). usbd_new_device() for the target dev must be |
994 | * called before calling this. | | 987 | * called before calling this. |
995 | */ | | 988 | */ |
996 | usbd_status | | 989 | usbd_status |
997 | usbd_reattach_device(device_t parent, usbd_device_handle dev, | | 990 | usbd_reattach_device(device_t parent, usbd_device_handle dev, |
998 | int port, const int *locators) | | 991 | int port, const int *locators) |
999 | { | | 992 | { |
1000 | int i, loc; | | 993 | int i, loc; |
1001 | | | 994 | |
1002 | if (locators != NULL) { | | 995 | if (locators != NULL) { |
1003 | loc = locators[USBIFIFCF_PORT]; | | 996 | loc = locators[USBIFIFCF_PORT]; |
1004 | if (loc != USBIFIFCF_PORT_DEFAULT && loc != port) | | 997 | if (loc != USBIFIFCF_PORT_DEFAULT && loc != port) |
1005 | return USBD_NORMAL_COMPLETION; | | 998 | return USBD_NORMAL_COMPLETION; |
1006 | loc = locators[USBIFIFCF_VENDOR]; | | 999 | loc = locators[USBIFIFCF_VENDOR]; |
1007 | if (loc != USBIFIFCF_VENDOR_DEFAULT && | | 1000 | if (loc != USBIFIFCF_VENDOR_DEFAULT && |
1008 | loc != UGETW(dev->ddesc.idVendor)) | | 1001 | loc != UGETW(dev->ddesc.idVendor)) |
1009 | return USBD_NORMAL_COMPLETION; | | 1002 | return USBD_NORMAL_COMPLETION; |
1010 | loc = locators[USBIFIFCF_PRODUCT]; | | 1003 | loc = locators[USBIFIFCF_PRODUCT]; |
1011 | if (loc != USBIFIFCF_PRODUCT_DEFAULT && | | 1004 | if (loc != USBIFIFCF_PRODUCT_DEFAULT && |
1012 | loc != UGETW(dev->ddesc.idProduct)) | | 1005 | loc != UGETW(dev->ddesc.idProduct)) |
1013 | return USBD_NORMAL_COMPLETION; | | 1006 | return USBD_NORMAL_COMPLETION; |
1014 | loc = locators[USBIFIFCF_RELEASE]; | | 1007 | loc = locators[USBIFIFCF_RELEASE]; |
1015 | if (loc != USBIFIFCF_RELEASE_DEFAULT && | | 1008 | if (loc != USBIFIFCF_RELEASE_DEFAULT && |
1016 | loc != UGETW(dev->ddesc.bcdDevice)) | | 1009 | loc != UGETW(dev->ddesc.bcdDevice)) |
1017 | return USBD_NORMAL_COMPLETION; | | 1010 | return USBD_NORMAL_COMPLETION; |
1018 | } | | 1011 | } |
1019 | if (dev->subdevlen == 0) { | | 1012 | if (dev->subdevlen == 0) { |
1020 | /* XXX: check USBIFIFCF_CONFIGURATION and | | 1013 | /* XXX: check USBIFIFCF_CONFIGURATION and |
1021 | * USBIFIFCF_INTERFACE too */ | | 1014 | * USBIFIFCF_INTERFACE too */ |
1022 | return usbd_probe_and_attach(parent, dev, port, dev->address); | | 1015 | return usbd_probe_and_attach(parent, dev, port, dev->address); |
1023 | } else if (dev->subdevlen != dev->cdesc->bNumInterface) { | | 1016 | } else if (dev->subdevlen != dev->cdesc->bNumInterface) { |
1024 | /* device-specific or generic driver is already attached. */ | | 1017 | /* device-specific or generic driver is already attached. */ |
1025 | return USBD_NORMAL_COMPLETION; | | 1018 | return USBD_NORMAL_COMPLETION; |
1026 | } | | 1019 | } |
1027 | /* Does the device have unconfigured interfaces? */ | | 1020 | /* Does the device have unconfigured interfaces? */ |
1028 | for (i = 0; i < dev->subdevlen; i++) { | | 1021 | for (i = 0; i < dev->subdevlen; i++) { |
1029 | if (dev->subdevs[i] == NULL) { | | 1022 | if (dev->subdevs[i] == NULL) { |
1030 | break; | | 1023 | break; |
1031 | } | | 1024 | } |
1032 | } | | 1025 | } |
1033 | if (i >= dev->subdevlen) | | 1026 | if (i >= dev->subdevlen) |
1034 | return USBD_NORMAL_COMPLETION; | | 1027 | return USBD_NORMAL_COMPLETION; |
1035 | return usbd_attachinterfaces(parent, dev, port, locators); | | 1028 | return usbd_attachinterfaces(parent, dev, port, locators); |
1036 | } | | 1029 | } |
1037 | | | 1030 | |
1038 | /* | | 1031 | /* |
1039 | * Get the first 8 bytes of the device descriptor. | | 1032 | * Get the first 8 bytes of the device descriptor. |
1040 | * Do as Windows does: try to read 64 bytes -- there are devices which | | 1033 | * Do as Windows does: try to read 64 bytes -- there are devices which |
1041 | * recognize the initial descriptor fetch (before the control endpoint's | | 1034 | * recognize the initial descriptor fetch (before the control endpoint's |
1042 | * MaxPacketSize is known by the host) by exactly this length. | | 1035 | * MaxPacketSize is known by the host) by exactly this length. |
1043 | */ | | 1036 | */ |
1044 | static usbd_status | | 1037 | static usbd_status |
1045 | usbd_get_initial_ddesc(usbd_device_handle dev, usb_device_descriptor_t *desc) | | 1038 | usbd_get_initial_ddesc(usbd_device_handle dev, usb_device_descriptor_t *desc) |
1046 | { | | 1039 | { |
1047 | usb_device_request_t req; | | 1040 | usb_device_request_t req; |
1048 | char buf[64]; | | 1041 | char buf[64]; |
1049 | int res, actlen; | | 1042 | int res, actlen; |
1050 | | | 1043 | |
1051 | req.bmRequestType = UT_READ_DEVICE; | | 1044 | req.bmRequestType = UT_READ_DEVICE; |
1052 | req.bRequest = UR_GET_DESCRIPTOR; | | 1045 | req.bRequest = UR_GET_DESCRIPTOR; |
1053 | USETW2(req.wValue, UDESC_DEVICE, 0); | | 1046 | USETW2(req.wValue, UDESC_DEVICE, 0); |
1054 | USETW(req.wIndex, 0); | | 1047 | USETW(req.wIndex, 0); |
1055 | USETW(req.wLength, 64); | | 1048 | USETW(req.wLength, 64); |
1056 | res = usbd_do_request_flags(dev, &req, buf, USBD_SHORT_XFER_OK, | | 1049 | res = usbd_do_request_flags(dev, &req, buf, USBD_SHORT_XFER_OK, |
1057 | &actlen, USBD_DEFAULT_TIMEOUT); | | 1050 | &actlen, USBD_DEFAULT_TIMEOUT); |
1058 | if (res) | | 1051 | if (res) |
1059 | return res; | | 1052 | return res; |
1060 | if (actlen < 8) | | 1053 | if (actlen < 8) |
1061 | return USBD_SHORT_XFER; | | 1054 | return USBD_SHORT_XFER; |
1062 | memcpy(desc, buf, 8); | | 1055 | memcpy(desc, buf, 8); |
1063 | return USBD_NORMAL_COMPLETION; | | 1056 | return USBD_NORMAL_COMPLETION; |
1064 | } | | 1057 | } |
1065 | | | 1058 | |
1066 | /* | | 1059 | /* |
1067 | * Called when a new device has been put in the powered state, | | 1060 | * Called when a new device has been put in the powered state, |
1068 | * but not yet in the addressed state. | | 1061 | * but not yet in the addressed state. |
1069 | * Get initial descriptor, set the address, get full descriptor, | | 1062 | * Get initial descriptor, set the address, get full descriptor, |
1070 | * and attach a driver. | | 1063 | * and attach a driver. |
1071 | */ | | 1064 | */ |
1072 | usbd_status | | 1065 | usbd_status |
1073 | usbd_new_device(device_t parent, usbd_bus_handle bus, int depth, | | 1066 | usbd_new_device(device_t parent, usbd_bus_handle bus, int depth, |
1074 | int speed, int port, struct usbd_port *up) | | 1067 | int speed, int port, struct usbd_port *up) |
1075 | { | | 1068 | { |
1076 | usbd_device_handle dev, adev; | | 1069 | usbd_device_handle dev, adev; |
1077 | struct usbd_device *hub; | | 1070 | struct usbd_device *hub; |
1078 | usb_device_descriptor_t *dd; | | 1071 | usb_device_descriptor_t *dd; |
1079 | usb_port_status_t ps; | | 1072 | usb_port_status_t ps; |
1080 | usbd_status err; | | 1073 | usbd_status err; |
1081 | int addr; | | 1074 | int addr; |
1082 | int i; | | 1075 | int i; |
1083 | int p; | | 1076 | int p; |
1084 | | | 1077 | |
1085 | DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n", | | 1078 | DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n", |
1086 | bus, port, depth, speed)); | | 1079 | bus, port, depth, speed)); |
1087 | addr = usbd_getnewaddr(bus); | | 1080 | addr = usbd_getnewaddr(bus); |
1088 | if (addr < 0) { | | 1081 | if (addr < 0) { |
1089 | printf("%s: No free USB addresses, new device ignored.\n", | | 1082 | printf("%s: No free USB addresses, new device ignored.\n", |
1090 | device_xname(bus->usbctl)); | | 1083 | device_xname(bus->usbctl)); |
1091 | return (USBD_NO_ADDR); | | 1084 | return (USBD_NO_ADDR); |
1092 | } | | 1085 | } |
1093 | | | 1086 | |
1094 | dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO); | | 1087 | dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO); |
1095 | if (dev == NULL) | | 1088 | if (dev == NULL) |
1096 | return (USBD_NOMEM); | | 1089 | return (USBD_NOMEM); |
1097 | | | 1090 | |
1098 | dev->bus = bus; | | 1091 | dev->bus = bus; |
1099 | | | 1092 | |
1100 | /* Set up default endpoint handle. */ | | 1093 | /* Set up default endpoint handle. */ |
1101 | dev->def_ep.edesc = &dev->def_ep_desc; | | 1094 | dev->def_ep.edesc = &dev->def_ep_desc; |
1102 | | | 1095 | |
1103 | /* Set up default endpoint descriptor. */ | | 1096 | /* Set up default endpoint descriptor. */ |
1104 | dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE; | | 1097 | dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE; |
1105 | dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT; | | 1098 | dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT; |
1106 | dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT; | | 1099 | dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT; |
1107 | dev->def_ep_desc.bmAttributes = UE_CONTROL; | | 1100 | dev->def_ep_desc.bmAttributes = UE_CONTROL; |
1108 | /* | | 1101 | /* |
1109 | * temporary, will be fixed after first descriptor fetch | | 1102 | * temporary, will be fixed after first descriptor fetch |
1110 | * (which uses 64 bytes so it shouldn't be less), | | 1103 | * (which uses 64 bytes so it shouldn't be less), |
1111 | * highspeed devices must support 64 byte packets anyway | | 1104 | * highspeed devices must support 64 byte packets anyway |
1112 | */ | | 1105 | */ |
1113 | USETW(dev->def_ep_desc.wMaxPacketSize, 64); | | 1106 | USETW(dev->def_ep_desc.wMaxPacketSize, 64); |
1114 | dev->def_ep_desc.bInterval = 0; | | 1107 | dev->def_ep_desc.bInterval = 0; |
1115 | | | 1108 | |
1116 | /* doesn't matter, just don't let it uninitialized */ | | 1109 | /* doesn't matter, just don't let it uninitialized */ |
1117 | dev->def_ep.datatoggle = 0; | | 1110 | dev->def_ep.datatoggle = 0; |
1118 | | | 1111 | |
1119 | dev->quirks = &usbd_no_quirk; | | 1112 | dev->quirks = &usbd_no_quirk; |
1120 | dev->address = USB_START_ADDR; | | 1113 | dev->address = USB_START_ADDR; |
1121 | dev->ddesc.bMaxPacketSize = 0; | | 1114 | dev->ddesc.bMaxPacketSize = 0; |
1122 | dev->depth = depth; | | 1115 | dev->depth = depth; |
1123 | dev->powersrc = up; | | 1116 | dev->powersrc = up; |
1124 | dev->myhub = up->parent; | | 1117 | dev->myhub = up->parent; |
1125 | | | 1118 | |
1126 | up->device = dev; | | 1119 | up->device = dev; |
1127 | | | 1120 | |
1128 | /* Locate port on upstream high speed hub */ | | 1121 | /* Locate port on upstream high speed hub */ |
1129 | for (adev = dev, hub = up->parent; | | 1122 | for (adev = dev, hub = up->parent; |
1130 | hub != NULL && hub->speed != USB_SPEED_HIGH; | | 1123 | hub != NULL && hub->speed != USB_SPEED_HIGH; |
1131 | adev = hub, hub = hub->myhub) | | 1124 | adev = hub, hub = hub->myhub) |
1132 | ; | | 1125 | ; |
1133 | if (hub) { | | 1126 | if (hub) { |
1134 | for (p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) { | | 1127 | for (p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) { |
1135 | if (hub->hub->ports[p].device == adev) { | | 1128 | if (hub->hub->ports[p].device == adev) { |
1136 | dev->myhsport = &hub->hub->ports[p]; | | 1129 | dev->myhsport = &hub->hub->ports[p]; |
1137 | goto found; | | 1130 | goto found; |
1138 | } | | 1131 | } |
1139 | } | | 1132 | } |
1140 | panic("usbd_new_device: cannot find HS port\n"); | | 1133 | panic("usbd_new_device: cannot find HS port\n"); |
1141 | found: | | 1134 | found: |
1142 | DPRINTFN(1,("usbd_new_device: high speed port %d\n", p)); | | 1135 | DPRINTFN(1,("usbd_new_device: high speed port %d\n", p)); |
1143 | } else { | | 1136 | } else { |
1144 | dev->myhsport = NULL; | | 1137 | dev->myhsport = NULL; |
1145 | } | | 1138 | } |
1146 | dev->speed = speed; | | 1139 | dev->speed = speed; |
1147 | dev->langid = USBD_NOLANG; | | 1140 | dev->langid = USBD_NOLANG; |
1148 | dev->cookie.cookie = ++usb_cookie_no; | | 1141 | dev->cookie.cookie = ++usb_cookie_no; |
1149 | | | 1142 | |
1150 | /* Establish the default pipe. */ | | 1143 | /* Establish the default pipe. */ |
1151 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, | | 1144 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, |
1152 | &dev->default_pipe); | | 1145 | &dev->default_pipe); |
1153 | if (err) { | | 1146 | if (err) { |
1154 | usbd_remove_device(dev, up); | | 1147 | usbd_remove_device(dev, up); |
1155 | return (err); | | 1148 | return (err); |
1156 | } | | 1149 | } |
1157 | | | 1150 | |
1158 | dd = &dev->ddesc; | | 1151 | dd = &dev->ddesc; |
1159 | /* Try a few times in case the device is slow (i.e. outside specs.) */ | | 1152 | /* Try a few times in case the device is slow (i.e. outside specs.) */ |
1160 | for (i = 0; i < 10; i++) { | | 1153 | for (i = 0; i < 10; i++) { |
1161 | /* Get the first 8 bytes of the device descriptor. */ | | 1154 | /* Get the first 8 bytes of the device descriptor. */ |
1162 | err = usbd_get_initial_ddesc(dev, dd); | | 1155 | err = usbd_get_initial_ddesc(dev, dd); |
1163 | if (!err) | | 1156 | if (!err) |
1164 | break; | | 1157 | break; |
1165 | usbd_delay_ms(dev, 200); | | 1158 | usbd_delay_ms(dev, 200); |
1166 | if ((i & 3) == 3) | | 1159 | if ((i & 3) == 3) |
1167 | usbd_reset_port(up->parent, port, &ps); | | 1160 | usbd_reset_port(up->parent, port, &ps); |
1168 | } | | 1161 | } |
1169 | if (err) { | | 1162 | if (err) { |
1170 | DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc " | | 1163 | DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc " |
1171 | "failed: %d\n", addr, err)); | | 1164 | "failed: %d\n", addr, err)); |
1172 | usbd_remove_device(dev, up); | | 1165 | usbd_remove_device(dev, up); |
1173 | return (err); | | 1166 | return (err); |
1174 | } | | 1167 | } |
1175 | | | 1168 | |
1176 | /* Windows resets the port here, do likewise */ | | 1169 | /* Windows resets the port here, do likewise */ |
1177 | if (up->parent) | | 1170 | if (up->parent) |
1178 | usbd_reset_port(up->parent, port, &ps); | | 1171 | usbd_reset_port(up->parent, port, &ps); |
1179 | | | 1172 | |
1180 | if (speed == USB_SPEED_HIGH) { | | 1173 | if (speed == USB_SPEED_HIGH) { |
1181 | /* Max packet size must be 64 (sec 5.5.3). */ | | 1174 | /* Max packet size must be 64 (sec 5.5.3). */ |
1182 | if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) { | | 1175 | if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) { |
1183 | #ifdef DIAGNOSTIC | | 1176 | #ifdef DIAGNOSTIC |
1184 | printf("usbd_new_device: addr=%d bad max packet " | | 1177 | printf("usbd_new_device: addr=%d bad max packet " |
1185 | "size=%d. adjusting to %d.\n", | | 1178 | "size=%d. adjusting to %d.\n", |
1186 | addr, dd->bMaxPacketSize, USB_2_MAX_CTRL_PACKET); | | 1179 | addr, dd->bMaxPacketSize, USB_2_MAX_CTRL_PACKET); |
1187 | #endif | | 1180 | #endif |
1188 | dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET; | | 1181 | dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET; |
1189 | } | | 1182 | } |
1190 | } | | 1183 | } |
1191 | | | 1184 | |
1192 | DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, " | | 1185 | DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, " |
1193 | "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", | | 1186 | "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", |
1194 | addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass, | | 1187 | addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass, |
1195 | dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, | | 1188 | dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, |
1196 | dev->speed)); | | 1189 | dev->speed)); |
1197 | | | 1190 | |
1198 | if (dd->bDescriptorType != UDESC_DEVICE) { | | 1191 | if (dd->bDescriptorType != UDESC_DEVICE) { |
1199 | /* Illegal device descriptor */ | | 1192 | /* Illegal device descriptor */ |
1200 | DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n", | | 1193 | DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n", |
1201 | dd->bDescriptorType)); | | 1194 | dd->bDescriptorType)); |
1202 | usbd_remove_device(dev, up); | | 1195 | usbd_remove_device(dev, up); |
1203 | return (USBD_INVAL); | | 1196 | return (USBD_INVAL); |
1204 | } | | 1197 | } |
1205 | | | 1198 | |
1206 | if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) { | | 1199 | if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) { |
1207 | DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength)); | | 1200 | DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength)); |
1208 | usbd_remove_device(dev, up); | | 1201 | usbd_remove_device(dev, up); |
1209 | return (USBD_INVAL); | | 1202 | return (USBD_INVAL); |
1210 | } | | 1203 | } |
1211 | | | 1204 | |
1212 | USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize); | | 1205 | USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize); |
1213 | | | 1206 | |
1214 | /* Set the address */ | | 1207 | /* Set the address */ |
1215 | DPRINTFN(5, ("usbd_new_device: setting device address=%d\n", addr)); | | 1208 | DPRINTFN(5, ("usbd_new_device: setting device address=%d\n", addr)); |
1216 | err = usbd_set_address(dev, addr); | | 1209 | err = usbd_set_address(dev, addr); |
1217 | if (err) { | | 1210 | if (err) { |
1218 | DPRINTFN(-1, ("usbd_new_device: set address %d failed\n", addr)); | | 1211 | DPRINTFN(-1, ("usbd_new_device: set address %d failed\n", addr)); |
1219 | err = USBD_SET_ADDR_FAILED; | | 1212 | err = USBD_SET_ADDR_FAILED; |
1220 | usbd_remove_device(dev, up); | | 1213 | usbd_remove_device(dev, up); |
1221 | return err; | | 1214 | return err; |
1222 | } | | 1215 | } |
1223 | | | 1216 | |
1224 | /* Allow device time to set new address */ | | 1217 | /* Allow device time to set new address */ |
1225 | usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); | | 1218 | usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); |
1226 | dev->address = addr; /* new device address now */ | | 1219 | dev->address = addr; /* new device address now */ |
1227 | bus->devices[addr] = dev; | | 1220 | bus->devices[addr] = dev; |
1228 | | | 1221 | |
1229 | err = usbd_reload_device_desc(dev); | | 1222 | err = usbd_reload_device_desc(dev); |
1230 | if (err) { | | 1223 | if (err) { |
1231 | DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc " | | 1224 | DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc " |
1232 | "failed\n", addr)); | | 1225 | "failed\n", addr)); |
1233 | usbd_remove_device(dev, up); | | 1226 | usbd_remove_device(dev, up); |
1234 | return (err); | | 1227 | return (err); |
1235 | } | | 1228 | } |
1236 | | | 1229 | |
1237 | /* Re-establish the default pipe with the new address. */ | | 1230 | /* Re-establish the default pipe with the new address. */ |
1238 | usbd_kill_pipe(dev->default_pipe); | | 1231 | usbd_kill_pipe(dev->default_pipe); |
1239 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, | | 1232 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, |
1240 | &dev->default_pipe); | | 1233 | &dev->default_pipe); |
1241 | if (err) { | | 1234 | if (err) { |
1242 | DPRINTFN(-1, ("usbd_new_device: setup default pipe failed\n")); | | 1235 | DPRINTFN(-1, ("usbd_new_device: setup default pipe failed\n")); |
1243 | usbd_remove_device(dev, up); | | 1236 | usbd_remove_device(dev, up); |
1244 | return err; | | 1237 | return err; |
1245 | } | | 1238 | } |
1246 | | | 1239 | |
1247 | /* Assume 100mA bus powered for now. Changed when configured. */ | | 1240 | /* Assume 100mA bus powered for now. Changed when configured. */ |
1248 | dev->power = USB_MIN_POWER; | | 1241 | dev->power = USB_MIN_POWER; |
1249 | dev->self_powered = 0; | | 1242 | dev->self_powered = 0; |
1250 | | | 1243 | |
1251 | DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n", | | 1244 | DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n", |
1252 | addr, dev, parent)); | | 1245 | addr, dev, parent)); |
1253 | | | 1246 | |
1254 | usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); | | 1247 | usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev); |
1255 | | | 1248 | |
1256 | if (port == 0) { /* root hub */ | | 1249 | if (port == 0) { /* root hub */ |
1257 | KASSERT(addr == 1); | | 1250 | KASSERT(addr == 1); |
1258 | usbd_attach_roothub(parent, dev); | | 1251 | usbd_attach_roothub(parent, dev); |
1259 | return (USBD_NORMAL_COMPLETION); | | 1252 | return (USBD_NORMAL_COMPLETION); |
1260 | } | | 1253 | } |
1261 | | | 1254 | |
1262 | err = usbd_probe_and_attach(parent, dev, port, addr); | | 1255 | err = usbd_probe_and_attach(parent, dev, port, addr); |
1263 | if (err) { | | 1256 | if (err) { |
1264 | usbd_remove_device(dev, up); | | 1257 | usbd_remove_device(dev, up); |
1265 | return (err); | | 1258 | return (err); |
1266 | } | | 1259 | } |
1267 | | | 1260 | |
1268 | return (USBD_NORMAL_COMPLETION); | | 1261 | return (USBD_NORMAL_COMPLETION); |
1269 | } | | 1262 | } |
1270 | | | 1263 | |
1271 | usbd_status | | 1264 | usbd_status |
1272 | usbd_reload_device_desc(usbd_device_handle dev) | | 1265 | usbd_reload_device_desc(usbd_device_handle dev) |
1273 | { | | 1266 | { |
1274 | usbd_status err; | | 1267 | usbd_status err; |
1275 | | | 1268 | |
1276 | /* Get the full device descriptor. */ | | 1269 | /* Get the full device descriptor. */ |
1277 | err = usbd_get_device_desc(dev, &dev->ddesc); | | 1270 | err = usbd_get_device_desc(dev, &dev->ddesc); |
1278 | if (err) | | 1271 | if (err) |
1279 | return (err); | | 1272 | return (err); |
1280 | | | 1273 | |
1281 | /* Figure out what's wrong with this device. */ | | 1274 | /* Figure out what's wrong with this device. */ |
1282 | dev->quirks = usbd_find_quirk(&dev->ddesc); | | 1275 | dev->quirks = usbd_find_quirk(&dev->ddesc); |
1283 | | | 1276 | |
1284 | return (USBD_NORMAL_COMPLETION); | | 1277 | return (USBD_NORMAL_COMPLETION); |
1285 | } | | 1278 | } |
1286 | | | 1279 | |
1287 | void | | 1280 | void |
1288 | usbd_remove_device(usbd_device_handle dev, struct usbd_port *up) | | 1281 | usbd_remove_device(usbd_device_handle dev, struct usbd_port *up) |
1289 | { | | 1282 | { |
1290 | DPRINTF(("usbd_remove_device: %p\n", dev)); | | 1283 | DPRINTF(("usbd_remove_device: %p\n", dev)); |
1291 | | | 1284 | |
1292 | if (dev->default_pipe != NULL) | | 1285 | if (dev->default_pipe != NULL) |
1293 | usbd_kill_pipe(dev->default_pipe); | | 1286 | usbd_kill_pipe(dev->default_pipe); |
1294 | up->device = NULL; | | 1287 | up->device = NULL; |
1295 | dev->bus->devices[dev->address] = NULL; | | 1288 | dev->bus->devices[dev->address] = NULL; |
1296 | | | 1289 | |
1297 | free(dev, M_USB); | | 1290 | free(dev, M_USB); |
1298 | } | | 1291 | } |
1299 | | | 1292 | |
1300 | int | | 1293 | int |
1301 | usbd_print(void *aux, const char *pnp) | | 1294 | usbd_print(void *aux, const char *pnp) |
1302 | { | | 1295 | { |
1303 | struct usb_attach_arg *uaa = aux; | | 1296 | struct usb_attach_arg *uaa = aux; |
1304 | | | 1297 | |
1305 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); | | 1298 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); |
1306 | if (pnp) { | | 1299 | if (pnp) { |
1307 | #define USB_DEVINFO 1024 | | 1300 | #define USB_DEVINFO 1024 |
1308 | char *devinfo; | | 1301 | char *devinfo; |
1309 | if (!uaa->usegeneric) | | 1302 | if (!uaa->usegeneric) |
1310 | return (QUIET); | | 1303 | return (QUIET); |
1311 | devinfo = malloc(USB_DEVINFO, M_TEMP, M_WAITOK); | | 1304 | devinfo = malloc(USB_DEVINFO, M_TEMP, M_WAITOK); |
1312 | usbd_devinfo(uaa->device, 1, devinfo, USB_DEVINFO); | | 1305 | usbd_devinfo(uaa->device, 1, devinfo, USB_DEVINFO); |
1313 | aprint_normal("%s, %s", devinfo, pnp); | | 1306 | aprint_normal("%s, %s", devinfo, pnp); |
1314 | free(devinfo, M_TEMP); | | 1307 | free(devinfo, M_TEMP); |
1315 | } | | 1308 | } |
1316 | aprint_normal(" port %d", uaa->port); | | 1309 | aprint_normal(" port %d", uaa->port); |
1317 | #if 0 | | 1310 | #if 0 |
1318 | /* | | 1311 | /* |
1319 | * It gets very crowded with these locators on the attach line. | | 1312 | * It gets very crowded with these locators on the attach line. |
1320 | * They are not really needed since they are printed in the clear | | 1313 | * They are not really needed since they are printed in the clear |
1321 | * by each driver. | | 1314 | * by each driver. |
1322 | */ | | 1315 | */ |
1323 | if (uaa->vendor != UHUB_UNK_VENDOR) | | 1316 | if (uaa->vendor != UHUB_UNK_VENDOR) |
1324 | aprint_normal(" vendor 0x%04x", uaa->vendor); | | 1317 | aprint_normal(" vendor 0x%04x", uaa->vendor); |
1325 | if (uaa->product != UHUB_UNK_PRODUCT) | | 1318 | if (uaa->product != UHUB_UNK_PRODUCT) |
1326 | aprint_normal(" product 0x%04x", uaa->product); | | 1319 | aprint_normal(" product 0x%04x", uaa->product); |
1327 | if (uaa->release != UHUB_UNK_RELEASE) | | 1320 | if (uaa->release != UHUB_UNK_RELEASE) |
1328 | aprint_normal(" release 0x%04x", uaa->release); | | 1321 | aprint_normal(" release 0x%04x", uaa->release); |
1329 | #endif | | 1322 | #endif |
1330 | return (UNCONF); | | 1323 | return (UNCONF); |
1331 | } | | 1324 | } |
1332 | | | 1325 | |
1333 | int | | 1326 | int |
1334 | usbd_ifprint(void *aux, const char *pnp) | | 1327 | usbd_ifprint(void *aux, const char *pnp) |
1335 | { | | 1328 | { |
1336 | struct usbif_attach_arg *uaa = aux; | | 1329 | struct usbif_attach_arg *uaa = aux; |
1337 | | | 1330 | |
1338 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); | | 1331 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); |
1339 | if (pnp) | | 1332 | if (pnp) |
1340 | return (QUIET); | | 1333 | return (QUIET); |
1341 | aprint_normal(" port %d", uaa->port); | | 1334 | aprint_normal(" port %d", uaa->port); |
1342 | aprint_normal(" configuration %d", uaa->configno); | | 1335 | aprint_normal(" configuration %d", uaa->configno); |
1343 | aprint_normal(" interface %d", uaa->ifaceno); | | 1336 | aprint_normal(" interface %d", uaa->ifaceno); |
1344 | #if 0 | | 1337 | #if 0 |
1345 | /* | | 1338 | /* |
1346 | * It gets very crowded with these locators on the attach line. | | 1339 | * It gets very crowded with these locators on the attach line. |
1347 | * They are not really needed since they are printed in the clear | | 1340 | * They are not really needed since they are printed in the clear |
1348 | * by each driver. | | 1341 | * by each driver. |
1349 | */ | | 1342 | */ |
1350 | if (uaa->vendor != UHUB_UNK_VENDOR) | | 1343 | if (uaa->vendor != UHUB_UNK_VENDOR) |
1351 | aprint_normal(" vendor 0x%04x", uaa->vendor); | | 1344 | aprint_normal(" vendor 0x%04x", uaa->vendor); |
1352 | if (uaa->product != UHUB_UNK_PRODUCT) | | 1345 | if (uaa->product != UHUB_UNK_PRODUCT) |
1353 | aprint_normal(" product 0x%04x", uaa->product); | | 1346 | aprint_normal(" product 0x%04x", uaa->product); |
1354 | if (uaa->release != UHUB_UNK_RELEASE) | | 1347 | if (uaa->release != UHUB_UNK_RELEASE) |
1355 | aprint_normal(" release 0x%04x", uaa->release); | | 1348 | aprint_normal(" release 0x%04x", uaa->release); |
1356 | #endif | | 1349 | #endif |
1357 | return (UNCONF); | | 1350 | return (UNCONF); |
1358 | } | | 1351 | } |
1359 | | | 1352 | |
1360 | void | | 1353 | void |
1361 | usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di, | | 1354 | usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di, |
1362 | int usedev) | | 1355 | int usedev) |
1363 | { | | 1356 | { |
1364 | struct usbd_port *p; | | 1357 | struct usbd_port *p; |
1365 | int i, j, err, s; | | 1358 | int i, j, err, s; |
1366 | | | 1359 | |
1367 | di->udi_bus = device_unit(dev->bus->usbctl); | | 1360 | di->udi_bus = device_unit(dev->bus->usbctl); |
1368 | di->udi_addr = dev->address; | | 1361 | di->udi_addr = dev->address; |
1369 | di->udi_cookie = dev->cookie; | | 1362 | di->udi_cookie = dev->cookie; |
1370 | usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor), | | 1363 | usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor), |
1371 | di->udi_product, sizeof(di->udi_product), usedev, 1); | | 1364 | di->udi_product, sizeof(di->udi_product), usedev, 1); |
1372 | usbd_printBCD(di->udi_release, sizeof(di->udi_release), | | 1365 | usbd_printBCD(di->udi_release, sizeof(di->udi_release), |
1373 | UGETW(dev->ddesc.bcdDevice)); | | 1366 | UGETW(dev->ddesc.bcdDevice)); |
1374 | di->udi_serial[0] = 0; | | 1367 | di->udi_serial[0] = 0; |
1375 | if (usedev) | | 1368 | if (usedev) |
1376 | (void)usbd_get_string(dev, dev->ddesc.iSerialNumber, | | 1369 | (void)usbd_get_string(dev, dev->ddesc.iSerialNumber, |
1377 | di->udi_serial); | | 1370 | di->udi_serial); |
1378 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); | | 1371 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); |
1379 | di->udi_productNo = UGETW(dev->ddesc.idProduct); | | 1372 | di->udi_productNo = UGETW(dev->ddesc.idProduct); |
1380 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); | | 1373 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); |
1381 | di->udi_class = dev->ddesc.bDeviceClass; | | 1374 | di->udi_class = dev->ddesc.bDeviceClass; |
1382 | di->udi_subclass = dev->ddesc.bDeviceSubClass; | | 1375 | di->udi_subclass = dev->ddesc.bDeviceSubClass; |
1383 | di->udi_protocol = dev->ddesc.bDeviceProtocol; | | 1376 | di->udi_protocol = dev->ddesc.bDeviceProtocol; |
1384 | di->udi_config = dev->config; | | 1377 | di->udi_config = dev->config; |
1385 | di->udi_power = dev->self_powered ? 0 : dev->power; | | 1378 | di->udi_power = dev->self_powered ? 0 : dev->power; |
1386 | di->udi_speed = dev->speed; | | 1379 | di->udi_speed = dev->speed; |
1387 | | | 1380 | |
1388 | if (dev->subdevlen > 0) { | | 1381 | if (dev->subdevlen > 0) { |
1389 | for (i = 0, j = 0; i < dev->subdevlen && | | 1382 | for (i = 0, j = 0; i < dev->subdevlen && |
1390 | j < USB_MAX_DEVNAMES; i++) { | | 1383 | j < USB_MAX_DEVNAMES; i++) { |
1391 | if (!dev->subdevs[i]) | | 1384 | if (!dev->subdevs[i]) |
1392 | continue; | | 1385 | continue; |
1393 | strncpy(di->udi_devnames[j], | | 1386 | strncpy(di->udi_devnames[j], |
1394 | device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); | | 1387 | device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); |
1395 | di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; | | 1388 | di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; |
1396 | j++; | | 1389 | j++; |
1397 | } | | 1390 | } |
1398 | } else { | | 1391 | } else { |
1399 | j = 0; | | 1392 | j = 0; |
1400 | } | | 1393 | } |
1401 | for (/* j is set */; j < USB_MAX_DEVNAMES; j++) | | 1394 | for (/* j is set */; j < USB_MAX_DEVNAMES; j++) |
1402 | di->udi_devnames[j][0] = 0; /* empty */ | | 1395 | di->udi_devnames[j][0] = 0; /* empty */ |
1403 | | | 1396 | |
1404 | if (dev->hub) { | | 1397 | if (dev->hub) { |
1405 | for (i = 0; | | 1398 | for (i = 0; |
1406 | i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && | | 1399 | i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && |
1407 | i < dev->hub->hubdesc.bNbrPorts; | | 1400 | i < dev->hub->hubdesc.bNbrPorts; |
1408 | i++) { | | 1401 | i++) { |
1409 | p = &dev->hub->ports[i]; | | 1402 | p = &dev->hub->ports[i]; |
1410 | if (p->device) | | 1403 | if (p->device) |
1411 | err = p->device->address; | | 1404 | err = p->device->address; |
1412 | else { | | 1405 | else { |
1413 | s = UGETW(p->status.wPortStatus); | | 1406 | s = UGETW(p->status.wPortStatus); |
1414 | if (s & UPS_PORT_ENABLED) | | 1407 | if (s & UPS_PORT_ENABLED) |
1415 | err = USB_PORT_ENABLED; | | 1408 | err = USB_PORT_ENABLED; |
1416 | else if (s & UPS_SUSPEND) | | 1409 | else if (s & UPS_SUSPEND) |
1417 | err = USB_PORT_SUSPENDED; | | 1410 | err = USB_PORT_SUSPENDED; |
1418 | else if (s & UPS_PORT_POWER) | | 1411 | else if (s & UPS_PORT_POWER) |
1419 | err = USB_PORT_POWERED; | | 1412 | err = USB_PORT_POWERED; |
1420 | else | | 1413 | else |
1421 | err = USB_PORT_DISABLED; | | 1414 | err = USB_PORT_DISABLED; |
1422 | } | | 1415 | } |
1423 | di->udi_ports[i] = err; | | 1416 | di->udi_ports[i] = err; |
1424 | } | | 1417 | } |
1425 | di->udi_nports = dev->hub->hubdesc.bNbrPorts; | | 1418 | di->udi_nports = dev->hub->hubdesc.bNbrPorts; |
1426 | } else | | 1419 | } else |
1427 | di->udi_nports = 0; | | 1420 | di->udi_nports = 0; |
1428 | } | | 1421 | } |
1429 | | | 1422 | |
1430 | #ifdef COMPAT_30 | | 1423 | #ifdef COMPAT_30 |
1431 | void | | 1424 | void |
1432 | usbd_fill_deviceinfo_old(usbd_device_handle dev, struct usb_device_info_old *di, | | 1425 | usbd_fill_deviceinfo_old(usbd_device_handle dev, struct usb_device_info_old *di, |
1433 | int usedev) | | 1426 | int usedev) |
1434 | { | | 1427 | { |
1435 | struct usbd_port *p; | | 1428 | struct usbd_port *p; |
1436 | int i, j, err, s; | | 1429 | int i, j, err, s; |
1437 | | | 1430 | |
1438 | di->udi_bus = device_unit(dev->bus->usbctl); | | 1431 | di->udi_bus = device_unit(dev->bus->usbctl); |
1439 | di->udi_addr = dev->address; | | 1432 | di->udi_addr = dev->address; |
1440 | di->udi_cookie = dev->cookie; | | 1433 | di->udi_cookie = dev->cookie; |
1441 | usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor), | | 1434 | usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor), |
1442 | di->udi_product, sizeof(di->udi_product), usedev, 0); | | 1435 | di->udi_product, sizeof(di->udi_product), usedev, 0); |
1443 | usbd_printBCD(di->udi_release, sizeof(di->udi_release), | | 1436 | usbd_printBCD(di->udi_release, sizeof(di->udi_release), |
1444 | UGETW(dev->ddesc.bcdDevice)); | | 1437 | UGETW(dev->ddesc.bcdDevice)); |
1445 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); | | 1438 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); |
1446 | di->udi_productNo = UGETW(dev->ddesc.idProduct); | | 1439 | di->udi_productNo = UGETW(dev->ddesc.idProduct); |
1447 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); | | 1440 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); |
1448 | di->udi_class = dev->ddesc.bDeviceClass; | | 1441 | di->udi_class = dev->ddesc.bDeviceClass; |
1449 | di->udi_subclass = dev->ddesc.bDeviceSubClass; | | 1442 | di->udi_subclass = dev->ddesc.bDeviceSubClass; |
1450 | di->udi_protocol = dev->ddesc.bDeviceProtocol; | | 1443 | di->udi_protocol = dev->ddesc.bDeviceProtocol; |
1451 | di->udi_config = dev->config; | | 1444 | di->udi_config = dev->config; |
1452 | di->udi_power = dev->self_powered ? 0 : dev->power; | | 1445 | di->udi_power = dev->self_powered ? 0 : dev->power; |
1453 | di->udi_speed = dev->speed; | | 1446 | di->udi_speed = dev->speed; |
1454 | | | 1447 | |
1455 | if (dev->subdevlen > 0) { | | 1448 | if (dev->subdevlen > 0) { |
1456 | for (i = 0, j = 0; i < dev->subdevlen && | | 1449 | for (i = 0, j = 0; i < dev->subdevlen && |
1457 | j < USB_MAX_DEVNAMES; i++) { | | 1450 | j < USB_MAX_DEVNAMES; i++) { |
1458 | if (!dev->subdevs[i]) | | 1451 | if (!dev->subdevs[i]) |
1459 | continue; | | 1452 | continue; |
1460 | strncpy(di->udi_devnames[j], | | 1453 | strncpy(di->udi_devnames[j], |
1461 | device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); | | 1454 | device_xname(dev->subdevs[i]), USB_MAX_DEVNAMELEN); |
1462 | di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; | | 1455 | di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; |
1463 | j++; | | 1456 | j++; |
1464 | } | | 1457 | } |
1465 | } else { | | 1458 | } else { |
1466 | j = 0; | | 1459 | j = 0; |
1467 | } | | 1460 | } |
1468 | for (/* j is set */; j < USB_MAX_DEVNAMES; j++) | | 1461 | for (/* j is set */; j < USB_MAX_DEVNAMES; j++) |
1469 | di->udi_devnames[j][0] = 0; /* empty */ | | 1462 | di->udi_devnames[j][0] = 0; /* empty */ |
1470 | | | 1463 | |
1471 | if (dev->hub) { | | 1464 | if (dev->hub) { |
1472 | for (i = 0; | | 1465 | for (i = 0; |
1473 | i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && | | 1466 | i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) && |
1474 | i < dev->hub->hubdesc.bNbrPorts; | | 1467 | i < dev->hub->hubdesc.bNbrPorts; |
1475 | i++) { | | 1468 | i++) { |
1476 | p = &dev->hub->ports[i]; | | 1469 | p = &dev->hub->ports[i]; |
1477 | if (p->device) | | 1470 | if (p->device) |
1478 | err = p->device->address; | | 1471 | err = p->device->address; |
1479 | else { | | 1472 | else { |
1480 | s = UGETW(p->status.wPortStatus); | | 1473 | s = UGETW(p->status.wPortStatus); |
1481 | if (s & UPS_PORT_ENABLED) | | 1474 | if (s & UPS_PORT_ENABLED) |
1482 | err = USB_PORT_ENABLED; | | 1475 | err = USB_PORT_ENABLED; |
1483 | else if (s & UPS_SUSPEND) | | 1476 | else if (s & UPS_SUSPEND) |
1484 | err = USB_PORT_SUSPENDED; | | 1477 | err = USB_PORT_SUSPENDED; |
1485 | else if (s & UPS_PORT_POWER) | | 1478 | else if (s & UPS_PORT_POWER) |
1486 | err = USB_PORT_POWERED; | | 1479 | err = USB_PORT_POWERED; |
1487 | else | | 1480 | else |
1488 | err = USB_PORT_DISABLED; | | 1481 | err = USB_PORT_DISABLED; |
1489 | } | | 1482 | } |
1490 | di->udi_ports[i] = err; | | 1483 | di->udi_ports[i] = err; |
1491 | } | | 1484 | } |
1492 | di->udi_nports = dev->hub->hubdesc.bNbrPorts; | | 1485 | di->udi_nports = dev->hub->hubdesc.bNbrPorts; |
1493 | } else | | 1486 | } else |
1494 | di->udi_nports = 0; | | 1487 | di->udi_nports = 0; |
1495 | } | | 1488 | } |
1496 | #endif | | 1489 | #endif |
1497 | | | 1490 | |
1498 | | | 1491 | |
1499 | void | | 1492 | void |
1500 | usb_free_device(usbd_device_handle dev) | | 1493 | usb_free_device(usbd_device_handle dev) |
1501 | { | | 1494 | { |
1502 | int ifcidx, nifc; | | 1495 | int ifcidx, nifc; |
1503 | | | 1496 | |
1504 | if (dev->default_pipe != NULL) | | 1497 | if (dev->default_pipe != NULL) |
1505 | usbd_kill_pipe(dev->default_pipe); | | 1498 | usbd_kill_pipe(dev->default_pipe); |
1506 | if (dev->ifaces != NULL) { | | 1499 | if (dev->ifaces != NULL) { |
1507 | nifc = dev->cdesc->bNumInterface; | | 1500 | nifc = dev->cdesc->bNumInterface; |
1508 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) | | 1501 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) |
1509 | usbd_free_iface_data(dev, ifcidx); | | 1502 | usbd_free_iface_data(dev, ifcidx); |
1510 | free(dev->ifaces, M_USB); | | 1503 | free(dev->ifaces, M_USB); |
1511 | } | | 1504 | } |
1512 | if (dev->cdesc != NULL) | | 1505 | if (dev->cdesc != NULL) |
1513 | free(dev->cdesc, M_USB); | | 1506 | free(dev->cdesc, M_USB); |
1514 | if (dev->subdevlen > 0) { | | 1507 | if (dev->subdevlen > 0) { |
1515 | free(dev->subdevs, M_USB); | | 1508 | free(dev->subdevs, M_USB); |
1516 | dev->subdevlen = 0; | | 1509 | dev->subdevlen = 0; |
1517 | } | | 1510 | } |
1518 | free(dev, M_USB); | | 1511 | free(dev, M_USB); |
1519 | } | | 1512 | } |
1520 | | | 1513 | |
1521 | /* | | 1514 | /* |
1522 | * The general mechanism for detaching drivers works as follows: Each | | 1515 | * The general mechanism for detaching drivers works as follows: Each |
1523 | * driver is responsible for maintaining a reference count on the | | 1516 | * driver is responsible for maintaining a reference count on the |
1524 | * number of outstanding references to its softc (e.g. from | | 1517 | * number of outstanding references to its softc (e.g. from |
1525 | * processing hanging in a read or write). The detach method of the | | 1518 | * processing hanging in a read or write). The detach method of the |
1526 | * driver decrements this counter and flags in the softc that the | | 1519 | * driver decrements this counter and flags in the softc that the |
1527 | * driver is dying and then wakes any sleepers. It then sleeps on the | | 1520 | * driver is dying and then wakes any sleepers. It then sleeps on the |
1528 | * softc. Each place that can sleep must maintain the reference | | 1521 | * softc. Each place that can sleep must maintain the reference |
1529 | * count. When the reference count drops to -1 (0 is the normal value | | 1522 | * count. When the reference count drops to -1 (0 is the normal value |
1530 | * of the reference count) the a wakeup on the softc is performed | | 1523 | * of the reference count) the a wakeup on the softc is performed |
1531 | * signaling to the detach waiter that all references are gone. | | 1524 | * signaling to the detach waiter that all references are gone. |
1532 | */ | | 1525 | */ |
1533 | | | 1526 | |
1534 | /* | | 1527 | /* |
1535 | * Called from process context when we discover that a port has | | 1528 | * Called from process context when we discover that a port has |
1536 | * been disconnected. | | 1529 | * been disconnected. |
1537 | */ | | 1530 | */ |
1538 | int | | 1531 | int |
1539 | usb_disconnect_port(struct usbd_port *up, device_t parent, int flags) | | 1532 | usb_disconnect_port(struct usbd_port *up, device_t parent, int flags) |
1540 | { | | 1533 | { |
1541 | usbd_device_handle dev = up->device; | | 1534 | usbd_device_handle dev = up->device; |
1542 | device_t subdev; | | 1535 | device_t subdev; |
1543 | char subdevname[16]; | | 1536 | char subdevname[16]; |
1544 | const char *hubname = device_xname(parent); | | 1537 | const char *hubname = device_xname(parent); |
1545 | int i, rc; | | 1538 | int i, rc; |
1546 | | | 1539 | |
1547 | DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", | | 1540 | DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", |
1548 | up, dev, up->portno)); | | 1541 | up, dev, up->portno)); |
1549 | | | 1542 | |
1550 | if (dev == NULL) { | | 1543 | if (dev == NULL) { |
1551 | #ifdef DIAGNOSTIC | | 1544 | #ifdef DIAGNOSTIC |
1552 | printf("usb_disconnect_port: no device\n"); | | 1545 | printf("usb_disconnect_port: no device\n"); |
1553 | #endif | | 1546 | #endif |
1554 | return 0; | | 1547 | return 0; |
1555 | } | | 1548 | } |
1556 | | | 1549 | |
1557 | if (dev->subdevlen > 0) { | | 1550 | if (dev->subdevlen > 0) { |
1558 | DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n")); | | 1551 | DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n")); |
1559 | for (i = 0; i < dev->subdevlen; i++) { | | 1552 | for (i = 0; i < dev->subdevlen; i++) { |
1560 | if ((subdev = dev->subdevs[i]) == NULL) | | 1553 | if ((subdev = dev->subdevs[i]) == NULL) |
1561 | continue; | | 1554 | continue; |
1562 | strlcpy(subdevname, device_xname(subdev), | | 1555 | strlcpy(subdevname, device_xname(subdev), |
1563 | sizeof(subdevname)); | | 1556 | sizeof(subdevname)); |
1564 | if ((rc = config_detach(subdev, flags)) != 0) | | 1557 | if ((rc = config_detach(subdev, flags)) != 0) |
1565 | return rc; | | 1558 | return rc; |
1566 | printf("%s: at %s", subdevname, hubname); | | 1559 | printf("%s: at %s", subdevname, hubname); |
1567 | if (up->portno != 0) | | 1560 | if (up->portno != 0) |
1568 | printf(" port %d", up->portno); | | 1561 | printf(" port %d", up->portno); |
1569 | printf(" (addr %d) disconnected\n", dev->address); | | 1562 | printf(" (addr %d) disconnected\n", dev->address); |
1570 | } | | 1563 | } |
1571 | KASSERT(!dev->nifaces_claimed); | | 1564 | KASSERT(!dev->nifaces_claimed); |
1572 | } | | 1565 | } |
1573 | | | 1566 | |
1574 | usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev); | | 1567 | usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev); |
1575 | dev->bus->devices[dev->address] = NULL; | | 1568 | dev->bus->devices[dev->address] = NULL; |
1576 | up->device = NULL; | | 1569 | up->device = NULL; |
1577 | usb_free_device(dev); | | 1570 | usb_free_device(dev); |
1578 | return 0; | | 1571 | return 0; |
1579 | } | | 1572 | } |