clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name usb_subr.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/dev/usb/usb_subr.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | #include <sys/param.h> |
36 | #include <sys/systm.h> |
37 | #include <sys/kernel.h> |
38 | #include <sys/malloc.h> |
39 | #include <sys/device.h> |
40 | #include <sys/rwlock.h> |
41 | |
42 | #include <machine/bus.h> |
43 | |
44 | #include <dev/usb/usb.h> |
45 | |
46 | #include <dev/usb/usbdi.h> |
47 | #include <dev/usb/usbdi_util.h> |
48 | #include <dev/usb/usbdivar.h> |
49 | #include <dev/usb/usbdevs.h> |
50 | #include <dev/usb/usb_quirks.h> |
51 | |
52 | #ifdef USB_DEBUG |
53 | #define DPRINTF(x) do { if (usbdebug) printf x; } while (0) |
54 | #define DPRINTFN(n,x) do { if (usbdebug>(n)) printf x; } while (0) |
55 | extern int usbdebug; |
56 | #else |
57 | #define DPRINTF(x) |
58 | #define DPRINTFN(n,x) |
59 | #endif |
60 | |
61 | usbd_status usbd_set_config(struct usbd_device *, int); |
62 | void usbd_devinfo(struct usbd_device *, int, char *, size_t); |
63 | char *usbd_get_string(struct usbd_device *, int, char *, size_t); |
64 | int usbd_getnewaddr(struct usbd_bus *); |
65 | int usbd_print(void *, const char *); |
66 | void usbd_free_iface_data(struct usbd_device *, int); |
67 | int usbd_cache_devinfo(struct usbd_device *); |
68 | usbd_status usbd_probe_and_attach(struct device *, |
69 | struct usbd_device *, int, int); |
70 | |
71 | int usbd_printBCD(char *cp, size_t len, int bcd); |
72 | void usb_free_device(struct usbd_device *); |
73 | int usbd_parse_idesc(struct usbd_device *, struct usbd_interface *); |
74 | |
75 | #ifdef USBVERBOSE |
76 | #include <dev/usb/usbdevs_data.h> |
77 | #endif /* USBVERBOSE */ |
78 | |
79 | const char * const usbd_error_strs[] = { |
80 | "NORMAL_COMPLETION", |
81 | "IN_PROGRESS", |
82 | "PENDING_REQUESTS", |
83 | "NOT_STARTED", |
84 | "INVAL", |
85 | "NOMEM", |
86 | "CANCELLED", |
87 | "BAD_ADDRESS", |
88 | "IN_USE", |
89 | "NO_ADDR", |
90 | "SET_ADDR_FAILED", |
91 | "NO_POWER", |
92 | "TOO_DEEP", |
93 | "IOERROR", |
94 | "NOT_CONFIGURED", |
95 | "TIMEOUT", |
96 | "SHORT_XFER", |
97 | "STALLED", |
98 | "INTERRUPTED", |
99 | "XXX", |
100 | }; |
101 | |
102 | const char * |
103 | usbd_errstr(usbd_status err) |
104 | { |
105 | static char buffer[5]; |
106 | |
107 | if (err < USBD_ERROR_MAX) |
108 | return (usbd_error_strs[err]); |
109 | else { |
110 | snprintf(buffer, sizeof(buffer), "%d", err); |
111 | return (buffer); |
112 | } |
113 | } |
114 | |
115 | usbd_status |
116 | usbd_get_string_desc(struct usbd_device *dev, int sindex, int langid, |
117 | usb_string_descriptor_t *sdesc, int *sizep) |
118 | { |
119 | usb_device_request_t req; |
120 | usbd_status err; |
121 | int actlen; |
122 | |
123 | req.bmRequestType = UT_READ_DEVICE; |
124 | req.bRequest = UR_GET_DESCRIPTOR; |
125 | USETW2(req.wValue, UDESC_STRING, sindex); |
126 | USETW(req.wIndex, langid); |
127 | USETW(req.wLength, 2); |
128 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, |
129 | &actlen, USBD_DEFAULT_TIMEOUT); |
130 | if (err) |
131 | return (err); |
132 | |
133 | if (actlen < 2) |
134 | return (USBD_SHORT_XFER); |
135 | |
136 | USETW(req.wLength, sdesc->bLength); |
137 | err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, |
138 | &actlen, USBD_DEFAULT_TIMEOUT); |
139 | if (err) |
140 | return (err); |
141 | |
142 | if (actlen != sdesc->bLength) { |
143 | DPRINTFN(-1, ("%s: expected %d, got %d\n", __func__, |
144 | sdesc->bLength, actlen)); |
145 | } |
146 | |
147 | *sizep = actlen; |
148 | return (USBD_NORMAL_COMPLETION); |
149 | } |
150 | |
151 | char * |
152 | usbd_get_string(struct usbd_device *dev, int si, char *buf, size_t buflen) |
153 | { |
154 | int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE; |
155 | usb_string_descriptor_t us; |
156 | char *s; |
157 | int i, n; |
158 | u_int16_t c; |
159 | usbd_status err; |
160 | int size; |
161 | |
162 | if (si == 0) |
163 | return (0); |
164 | if (dev->quirks->uq_flags & UQ_NO_STRINGS) |
165 | return (0); |
166 | if (dev->langid == USBD_NOLANG) { |
167 | |
168 | err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us, |
169 | &size); |
170 | if (err || size < 4) |
171 | dev->langid = 0; |
172 | else { |
173 | |
174 | dev->langid = UGETW(us.bString[0]); |
175 | } |
176 | } |
177 | err = usbd_get_string_desc(dev, si, dev->langid, &us, &size); |
178 | if (err) |
179 | return (0); |
180 | s = buf; |
181 | n = size / 2 - 1; |
182 | for (i = 0; i < n && i < buflen ; i++) { |
183 | c = UGETW(us.bString[i]); |
184 | |
185 | if ((c & 0xff00) == 0) |
186 | *s++ = c; |
187 | else if ((c & 0x00ff) == 0 && swap) |
188 | *s++ = c >> 8; |
189 | else |
190 | *s++ = '?'; |
191 | } |
192 | if (buflen > 0) |
193 | *s++ = 0; |
194 | return (buf); |
195 | } |
196 | |
197 | static void |
198 | usbd_trim_spaces(char *p) |
199 | { |
200 | char *q, *e; |
201 | |
202 | if (p == NULL) |
203 | return; |
204 | q = e = p; |
205 | while (*q == ' ') |
206 | q++; |
207 | while ((*p = *q++)) |
208 | if (*p++ != ' ') |
209 | e = p; |
210 | *e = 0; |
211 | } |
212 | |
213 | int |
214 | usbd_cache_devinfo(struct usbd_device *dev) |
215 | { |
216 | usb_device_descriptor_t *udd = &dev->ddesc; |
217 | |
218 | dev->serial = malloc(USB_MAX_STRING_LEN, M_USB, M_NOWAIT); |
219 | if (dev->serial == NULL) |
220 | return (ENOMEM); |
221 | |
222 | if (usbd_get_string(dev, udd->iSerialNumber, dev->serial, USB_MAX_STRING_LEN) != NULL) { |
223 | usbd_trim_spaces(dev->serial); |
224 | } else { |
225 | free(dev->serial, M_USB, USB_MAX_STRING_LEN); |
226 | dev->serial = NULL; |
227 | } |
228 | |
229 | dev->vendor = malloc(USB_MAX_STRING_LEN, M_USB, M_NOWAIT); |
230 | if (dev->vendor == NULL) |
231 | return (ENOMEM); |
232 | |
233 | if (usbd_get_string(dev, udd->iManufacturer, dev->vendor, USB_MAX_STRING_LEN) != NULL) { |
234 | usbd_trim_spaces(dev->vendor); |
235 | } else { |
236 | #ifdef USBVERBOSE |
237 | const struct usb_known_vendor *ukv; |
238 | |
239 | for (ukv = usb_known_vendors; ukv->vendorname != NULL; ukv++) { |
240 | if (ukv->vendor == UGETW(udd->idVendor)) { |
241 | strlcpy(dev->vendor, ukv->vendorname, |
242 | USB_MAX_STRING_LEN); |
243 | break; |
244 | } |
245 | } |
246 | if (ukv->vendorname == NULL) |
247 | #endif |
248 | snprintf(dev->vendor, USB_MAX_STRING_LEN, "vendor 0x%04x", |
249 | UGETW(udd->idVendor)); |
250 | } |
251 | |
252 | dev->product = malloc(USB_MAX_STRING_LEN, M_USB, M_NOWAIT); |
253 | if (dev->product == NULL) |
254 | return (ENOMEM); |
255 | |
256 | if (usbd_get_string(dev, udd->iProduct, dev->product, USB_MAX_STRING_LEN) != NULL) { |
257 | usbd_trim_spaces(dev->product); |
258 | } else { |
259 | #ifdef USBVERBOSE |
260 | const struct usb_known_product *ukp; |
261 | |
262 | for (ukp = usb_known_products; ukp->productname != NULL; ukp++) { |
263 | if (ukp->vendor == UGETW(udd->idVendor) && |
264 | (ukp->product == UGETW(udd->idProduct))) { |
265 | strlcpy(dev->product, ukp->productname, |
266 | USB_MAX_STRING_LEN); |
267 | break; |
268 | } |
269 | } |
270 | if (ukp->productname == NULL) |
271 | #endif |
272 | snprintf(dev->product, USB_MAX_STRING_LEN, "product 0x%04x", |
273 | UGETW(udd->idProduct)); |
274 | } |
275 | |
276 | return (0); |
277 | } |
278 | |
279 | int |
280 | usbd_printBCD(char *cp, size_t len, int bcd) |
281 | { |
282 | int l; |
283 | |
284 | l = snprintf(cp, len, "%x.%02x", bcd >> 8, bcd & 0xff); |
285 | if (l == -1 || len == 0) |
286 | return (0); |
287 | if (l >= len) |
288 | return len - 1; |
289 | return (l); |
290 | } |
291 | |
292 | void |
293 | usbd_devinfo(struct usbd_device *dev, int showclass, char *base, size_t len) |
294 | { |
295 | usb_device_descriptor_t *udd = &dev->ddesc; |
296 | char *cp = base; |
297 | int bcdDevice, bcdUSB; |
298 | |
299 | snprintf(cp, len, "\"%s %s\"", dev->vendor, dev->product); |
300 | cp += strlen(cp); |
301 | if (showclass) { |
302 | snprintf(cp, base + len - cp, ", class %d/%d", |
303 | udd->bDeviceClass, udd->bDeviceSubClass); |
304 | cp += strlen(cp); |
305 | } |
306 | bcdUSB = UGETW(udd->bcdUSB); |
307 | bcdDevice = UGETW(udd->bcdDevice); |
308 | snprintf(cp, base + len - cp, " rev "); |
309 | cp += strlen(cp); |
310 | usbd_printBCD(cp, base + len - cp, bcdUSB); |
311 | cp += strlen(cp); |
312 | snprintf(cp, base + len - cp, "/"); |
313 | cp += strlen(cp); |
314 | usbd_printBCD(cp, base + len - cp, bcdDevice); |
315 | cp += strlen(cp); |
316 | snprintf(cp, base + len - cp, " addr %d", dev->address); |
317 | } |
318 | |
319 | |
320 | void |
321 | usb_delay_ms(struct usbd_bus *bus, u_int ms) |
322 | { |
323 | static int usb_delay_wchan; |
324 | |
325 | if (bus->use_polling || cold) |
326 | delay((ms+1) * 1000); |
327 | else |
328 | tsleep_nsec(&usb_delay_wchan, PRIBIO, "usbdly", |
329 | MSEC_TO_NSEC(ms)); |
330 | } |
331 | |
332 | |
333 | void |
334 | usbd_delay_ms(struct usbd_device *dev, u_int ms) |
335 | { |
336 | if (usbd_is_dying(dev)) |
337 | return; |
338 | |
339 | usb_delay_ms(dev->bus, ms); |
340 | } |
341 | |
342 | usbd_status |
343 | usbd_port_disown_to_1_1(struct usbd_device *dev, int port) |
344 | { |
345 | usb_port_status_t ps; |
346 | usbd_status err; |
347 | int n; |
348 | |
349 | err = usbd_set_port_feature(dev, port, UHF_PORT_DISOWN_TO_1_1); |
350 | DPRINTF(("%s: port %d disown request done, error=%s\n", __func__, |
351 | port, usbd_errstr(err))); |
352 | if (err) |
353 | return (err); |
354 | n = 10; |
355 | do { |
356 | |
357 | usbd_delay_ms(dev, USB_PORT_RESET_DELAY); |
358 | err = usbd_get_port_status(dev, port, &ps); |
359 | if (err) { |
360 | DPRINTF(("%s: get status failed %d\n", __func__, err)); |
361 | return (err); |
362 | } |
363 | |
364 | if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) |
365 | return (USBD_NORMAL_COMPLETION); |
366 | } while ((UGETW(ps.wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0); |
367 | if (n == 0) |
368 | return (USBD_TIMEOUT); |
369 | |
370 | return (err); |
371 | } |
372 | |
373 | int |
374 | usbd_reset_port(struct usbd_device *dev, int port) |
375 | { |
376 | usb_port_status_t ps; |
377 | int n; |
378 | |
379 | if (usbd_set_port_feature(dev, port, UHF_PORT_RESET)) |
380 | return (EIO); |
381 | DPRINTF(("%s: port %d reset done\n", __func__, port)); |
382 | n = 10; |
383 | do { |
384 | |
385 | usbd_delay_ms(dev, USB_PORT_RESET_DELAY); |
386 | if (usbd_get_port_status(dev, port, &ps)) { |
387 | DPRINTF(("%s: get status failed\n", __func__)); |
388 | return (EIO); |
389 | } |
390 | |
391 | if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) |
392 | return (0); |
393 | } while ((UGETW(ps.wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0); |
394 | |
395 | |
396 | if (usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET)) { |
397 | DPRINTF(("%s: clear port feature failed\n", __func__)); |
398 | return (EIO); |
399 | } |
400 | |
401 | if (n == 0) |
402 | return (ETIMEDOUT); |
403 | |
404 | |
405 | usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY); |
406 | return (0); |
407 | } |
408 | |
409 | usb_interface_descriptor_t * |
410 | usbd_find_idesc(usb_config_descriptor_t *cd, int ifaceno, int altno) |
411 | { |
412 | char *p = (char *)cd; |
413 | char *end = p + UGETW(cd->wTotalLength); |
414 | usb_interface_descriptor_t *d; |
415 | int curidx, lastidx, curaidx = 0; |
416 | |
417 | for (curidx = lastidx = -1; p < end; ) { |
418 | d = (usb_interface_descriptor_t *)p; |
419 | DPRINTFN(4,("usbd_find_idesc: ifaceno=%d(%d) altno=%d(%d) " |
420 | "len=%d type=%d\n", |
421 | ifaceno, curidx, altno, curaidx, |
422 | d->bLength, d->bDescriptorType)); |
423 | if (d->bLength == 0) |
424 | break; |
425 | p += d->bLength; |
426 | if (p <= end && d->bDescriptorType == UDESC_INTERFACE) { |
427 | if (d->bInterfaceNumber != lastidx) { |
428 | lastidx = d->bInterfaceNumber; |
429 | curidx++; |
430 | curaidx = 0; |
431 | } else |
432 | curaidx++; |
433 | if (ifaceno == curidx && altno == curaidx) |
434 | return (d); |
435 | } |
436 | } |
437 | return (NULL); |
438 | } |
439 | |
440 | usb_endpoint_descriptor_t * |
441 | usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceno, int altno, |
442 | int endptidx) |
443 | { |
444 | char *p = (char *)cd; |
445 | char *end = p + UGETW(cd->wTotalLength); |
446 | usb_interface_descriptor_t *d; |
447 | usb_endpoint_descriptor_t *e; |
448 | int curidx; |
449 | |
450 | d = usbd_find_idesc(cd, ifaceno, altno); |
451 | if (d == NULL) |
452 | return (NULL); |
453 | if (endptidx >= d->bNumEndpoints) |
454 | return (NULL); |
455 | |
456 | curidx = -1; |
457 | for (p = (char *)d + d->bLength; p < end; ) { |
458 | e = (usb_endpoint_descriptor_t *)p; |
459 | if (e->bLength == 0) |
460 | break; |
461 | p += e->bLength; |
462 | if (p <= end && e->bDescriptorType == UDESC_INTERFACE) |
463 | return (NULL); |
464 | if (p <= end && e->bDescriptorType == UDESC_ENDPOINT) { |
465 | curidx++; |
466 | if (curidx == endptidx) |
467 | return (e); |
468 | } |
469 | } |
470 | return (NULL); |
471 | } |
472 | |
473 | usbd_status |
474 | usbd_fill_iface_data(struct usbd_device *dev, int ifaceno, int altno) |
475 | { |
476 | struct usbd_interface *ifc = &dev->ifaces[ifaceno]; |
477 | usb_interface_descriptor_t *idesc; |
478 | int nendpt; |
479 | |
480 | DPRINTFN(4,("%s: ifaceno=%d altno=%d\n", __func__, ifaceno, altno)); |
481 | |
482 | idesc = usbd_find_idesc(dev->cdesc, ifaceno, altno); |
483 | if (idesc == NULL) |
484 | return (USBD_INVAL); |
485 | |
486 | nendpt = idesc->bNumEndpoints; |
487 | DPRINTFN(4,("%s: found idesc nendpt=%d\n", __func__, nendpt)); |
488 | |
489 | ifc->device = dev; |
490 | ifc->idesc = idesc; |
491 | ifc->index = ifaceno; |
492 | ifc->altindex = altno; |
493 | ifc->endpoints = NULL; |
494 | ifc->priv = NULL; |
495 | LIST_INIT(&ifc->pipes); |
496 | ifc->nendpt = nendpt; |
497 | |
498 | if (nendpt != 0) { |
499 | ifc->endpoints = mallocarray(nendpt, sizeof(*ifc->endpoints), |
500 | M_USB, M_NOWAIT | M_ZERO); |
501 | if (ifc->endpoints == NULL) |
502 | return (USBD_NOMEM); |
503 | } |
504 | |
505 | if (usbd_parse_idesc(dev, ifc)) { |
506 | free(ifc->endpoints, M_USB, nendpt * sizeof(*ifc->endpoints)); |
507 | ifc->endpoints = NULL; |
508 | return (USBD_INVAL); |
509 | } |
510 | |
511 | return (USBD_NORMAL_COMPLETION); |
512 | } |
513 | |
514 | int |
515 | usbd_parse_idesc(struct usbd_device *dev, struct usbd_interface *ifc) |
516 | { |
517 | #define ed ((usb_endpoint_descriptor_t *)p) |
518 | char *p, *end; |
519 | int i; |
520 | |
521 | p = (char *)ifc->idesc + ifc->idesc->bLength; |
522 | end = (char *)dev->cdesc + UGETW(dev->cdesc->wTotalLength); |
523 | |
524 | for (i = 0; i < ifc->idesc->bNumEndpoints; i++) { |
525 | for (; p < end; p += ed->bLength) { |
526 | if (p + ed->bLength <= end && ed->bLength != 0 && |
527 | ed->bDescriptorType == UDESC_ENDPOINT) |
528 | break; |
529 | |
530 | if (ed->bLength == 0 || |
531 | ed->bDescriptorType == UDESC_INTERFACE) |
532 | return (-1); |
533 | } |
534 | |
535 | if (p >= end) |
536 | return (-1); |
537 | |
538 | if (dev->speed == USB_SPEED_HIGH) { |
539 | unsigned int mps; |
540 | |
541 | |
542 | switch (UE_GET_XFERTYPE(ed->bmAttributes)) { |
543 | case UE_CONTROL: |
544 | mps = USB_2_MAX_CTRL_PACKET; |
545 | goto check; |
546 | case UE_BULK: |
547 | mps = USB_2_MAX_BULK_PACKET; |
548 | check: |
549 | if (UGETW(ed->wMaxPacketSize) != mps) { |
550 | USETW(ed->wMaxPacketSize, mps); |
551 | DPRINTF(("%s: bad max packet size\n", |
552 | __func__)); |
553 | } |
554 | break; |
555 | default: |
556 | break; |
557 | } |
558 | } |
559 | |
560 | ifc->endpoints[i].edesc = ed; |
561 | ifc->endpoints[i].refcnt = 0; |
562 | ifc->endpoints[i].savedtoggle = 0; |
563 | p += ed->bLength; |
564 | } |
565 | |
566 | return (0); |
567 | #undef ed |
568 | } |
569 | |
570 | void |
571 | usbd_free_iface_data(struct usbd_device *dev, int ifcno) |
572 | { |
573 | struct usbd_interface *ifc = &dev->ifaces[ifcno]; |
574 | |
575 | free(ifc->endpoints, M_USB, ifc->nendpt * sizeof(*ifc->endpoints)); |
576 | ifc->endpoints = NULL; |
577 | } |
578 | |
579 | usbd_status |
580 | usbd_set_config(struct usbd_device *dev, int conf) |
581 | { |
582 | usb_device_request_t req; |
583 | |
584 | req.bmRequestType = UT_WRITE_DEVICE; |
585 | req.bRequest = UR_SET_CONFIG; |
586 | USETW(req.wValue, conf); |
587 | USETW(req.wIndex, 0); |
588 | USETW(req.wLength, 0); |
589 | return (usbd_do_request(dev, &req, 0)); |
590 | } |
591 | |
592 | usbd_status |
593 | usbd_set_config_no(struct usbd_device *dev, int no, int msg) |
594 | { |
595 | int index; |
596 | usb_config_descriptor_t cd; |
597 | usbd_status err; |
598 | |
599 | DPRINTFN(5,("%s: %d\n", __func__, no)); |
600 | |
601 | for (index = 0; index < dev->ddesc.bNumConfigurations; index++) { |
602 | err = usbd_get_desc(dev, UDESC_CONFIG, index, |
603 | USB_CONFIG_DESCRIPTOR_SIZE, &cd); |
604 | if (err || cd.bDescriptorType != UDESC_CONFIG) |
605 | return (err); |
606 | if (cd.bConfigurationValue == no) |
607 | return (usbd_set_config_index(dev, index, msg)); |
608 | } |
609 | return (USBD_INVAL); |
610 | } |
611 | |
612 | usbd_status |
613 | usbd_set_config_index(struct usbd_device *dev, int index, int msg) |
614 | { |
615 | usb_status_t ds; |
616 | usb_config_descriptor_t cd, *cdp; |
617 | usbd_status err; |
618 | int i, ifcidx, nifc, cdplen, selfpowered, power; |
619 | |
620 | DPRINTFN(5,("%s: dev=%p index=%d\n", __func__, dev, index)); |
621 | |
622 | |
623 | if (dev->config != USB_UNCONFIG_NO) { |
| 40 | | Assuming field 'config' is equal to USB_UNCONFIG_NO | |
|
| |
624 | DPRINTF(("%s: free old config\n", __func__)); |
625 | |
626 | nifc = dev->cdesc->bNumInterfaces; |
627 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) |
628 | usbd_free_iface_data(dev, ifcidx); |
629 | free(dev->ifaces, M_USB, nifc * sizeof(*dev->ifaces)); |
630 | free(dev->cdesc, M_USB, UGETW(dev->cdesc->wTotalLength)); |
631 | dev->ifaces = NULL; |
632 | dev->cdesc = NULL; |
633 | dev->config = USB_UNCONFIG_NO; |
634 | } |
635 | |
636 | if (index == USB_UNCONFIG_INDEX) { |
| |
637 | |
638 | DPRINTF(("%s: set config 0\n", __func__)); |
639 | err = usbd_set_config(dev, USB_UNCONFIG_NO); |
640 | if (err) |
641 | DPRINTF(("%s: setting config=0 failed, error=%s\n", |
642 | __func__, usbd_errstr(err))); |
643 | return (err); |
644 | } |
645 | |
646 | |
647 | err = usbd_get_desc(dev, UDESC_CONFIG, index, |
648 | USB_CONFIG_DESCRIPTOR_SIZE, &cd); |
649 | if (err) |
| |
| |
650 | return (err); |
651 | if (cd.bDescriptorType != UDESC_CONFIG) |
| 45 | | Assuming field 'bDescriptorType' is equal to UDESC_CONFIG | |
|
| |
652 | return (USBD_INVAL); |
653 | cdplen = UGETW(cd.wTotalLength); |
654 | cdp = malloc(cdplen, M_USB, M_NOWAIT); |
655 | if (cdp == NULL) |
| 47 | | Assuming 'cdp' is not equal to NULL | |
|
| |
656 | return (USBD_NOMEM); |
657 | |
658 | for (i = 0; i < 3; i++) { |
| 49 | | Loop condition is true. Entering loop body | |
|
659 | err = usbd_get_desc(dev, UDESC_CONFIG, index, cdplen, cdp); |
660 | if (!err) |
| 50 | | Assuming 'err' is 0, which participates in a condition later | |
|
| |
661 | break; |
662 | usbd_delay_ms(dev, 200); |
663 | } |
664 | if (err) |
| 52 | | Execution continues on line 664 | |
|
| |
665 | goto bad; |
666 | |
667 | if (cdp->bDescriptorType != UDESC_CONFIG) { |
| 54 | | Assuming field 'bDescriptorType' is equal to UDESC_CONFIG | |
|
| |
668 | DPRINTFN(-1,("%s: bad desc %d\n", __func__, |
669 | cdp->bDescriptorType)); |
670 | err = USBD_INVAL; |
671 | goto bad; |
672 | } |
673 | |
674 | |
675 | selfpowered = 0; |
676 | if (!(dev->quirks->uq_flags & UQ_BUS_POWERED) && |
| 56 | | Assuming the condition is false | |
|
677 | (cdp->bmAttributes & UC_SELF_POWERED)) { |
678 | |
679 | if (cdp->bmAttributes & UC_BUS_POWERED) { |
680 | |
681 | if (dev->quirks->uq_flags & UQ_POWER_CLAIM) { |
682 | |
683 | |
684 | |
685 | |
686 | |
687 | usb_hub_descriptor_t hd; |
688 | usb_device_request_t req; |
689 | req.bmRequestType = UT_READ_CLASS_DEVICE; |
690 | req.bRequest = UR_GET_DESCRIPTOR; |
691 | USETW(req.wValue, 0); |
692 | USETW(req.wIndex, 0); |
693 | USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE); |
694 | err = usbd_do_request(dev, &req, &hd); |
695 | if (!err && |
696 | (UGETW(hd.wHubCharacteristics) & |
697 | UHD_PWR_INDIVIDUAL)) |
698 | selfpowered = 1; |
699 | DPRINTF(("%s: charac=0x%04x, error=%s\n", |
700 | __func__, UGETW(hd.wHubCharacteristics), |
701 | usbd_errstr(err))); |
702 | } else { |
703 | err = usbd_get_device_status(dev, &ds); |
704 | if (!err && |
705 | (UGETW(ds.wStatus) & UDS_SELF_POWERED)) |
706 | selfpowered = 1; |
707 | DPRINTF(("%s: status=0x%04x, error=%s\n", |
708 | __func__, UGETW(ds.wStatus), |
709 | usbd_errstr(err))); |
710 | } |
711 | } else |
712 | selfpowered = 1; |
713 | } |
714 | DPRINTF(("%s: (addr %d) cno=%d attr=0x%02x, selfpowered=%d, power=%d\n", |
715 | __func__, dev->address, cdp->bConfigurationValue, cdp->bmAttributes, |
716 | selfpowered, cdp->bMaxPower * 2)); |
717 | |
718 | |
719 | #ifdef USB_DEBUG |
720 | if (dev->powersrc == NULL) { |
721 | DPRINTF(("%s: No power source?\n", __func__)); |
722 | err = USBD_IOERROR; |
723 | goto bad; |
724 | } |
725 | #endif |
726 | power = cdp->bMaxPower * 2; |
727 | if (power > dev->powersrc->power) { |
| 57 | | Assuming 'power' is <= field 'power' | |
|
| |
728 | DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power)); |
729 | |
730 | if (msg) |
731 | printf("%s: device addr %d (config %d) exceeds power " |
732 | "budget, %d mA > %d mA\n", |
733 | dev->bus->bdev.dv_xname, dev->address, |
734 | cdp->bConfigurationValue, |
735 | power, dev->powersrc->power); |
736 | err = USBD_NO_POWER; |
737 | goto bad; |
738 | } |
739 | dev->power = power; |
740 | dev->self_powered = selfpowered; |
741 | |
742 | |
743 | DPRINTF(("%s: set config %d\n", __func__, cdp->bConfigurationValue)); |
744 | err = usbd_set_config(dev, cdp->bConfigurationValue); |
745 | if (err) { |
| |
| |
746 | DPRINTF(("%s: setting config=%d failed, error=%s\n", __func__, |
747 | cdp->bConfigurationValue, usbd_errstr(err))); |
748 | goto bad; |
749 | } |
750 | |
751 | |
752 | nifc = cdp->bNumInterfaces; |
753 | dev->ifaces = mallocarray(nifc, sizeof(*dev->ifaces), M_USB, |
754 | M_NOWAIT | M_ZERO); |
755 | if (dev->ifaces == NULL) { |
| 61 | | Assuming field 'ifaces' is not equal to NULL | |
|
| |
756 | err = USBD_NOMEM; |
757 | goto bad; |
758 | } |
759 | DPRINTFN(5,("%s: dev=%p cdesc=%p\n", __func__, dev, cdp)); |
760 | dev->cdesc = cdp; |
761 | dev->config = cdp->bConfigurationValue; |
762 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) { |
| 63 | | Assuming 'ifcidx' is >= 'nifc' | |
|
| 64 | | Loop condition is false. Execution continues on line 768 | |
|
763 | err = usbd_fill_iface_data(dev, ifcidx, 0); |
764 | if (err) |
765 | return (err); |
766 | } |
767 | |
768 | return (USBD_NORMAL_COMPLETION); |
| 65 | | Returning zero, which participates in a condition later | |
|
769 | |
770 | bad: |
771 | free(cdp, M_USB, cdplen); |
772 | return (err); |
773 | } |
774 | |
775 | |
776 | |
777 | usbd_status |
778 | usbd_setup_pipe(struct usbd_device *dev, struct usbd_interface *iface, |
779 | struct usbd_endpoint *ep, int ival, struct usbd_pipe **pipe) |
780 | { |
781 | struct usbd_pipe *p; |
782 | usbd_status err; |
783 | |
784 | DPRINTF(("%s: dev=%p iface=%p ep=%p pipe=%p\n", __func__, |
785 | dev, iface, ep, pipe)); |
786 | p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT|M_ZERO); |
787 | if (p == NULL) |
| 9 | | Assuming 'p' is not equal to NULL | |
|
| |
788 | return (USBD_NOMEM); |
789 | p->pipe_size = dev->bus->pipe_size; |
790 | p->device = dev; |
791 | p->iface = iface; |
792 | p->endpoint = ep; |
793 | ep->refcnt++; |
794 | p->interval = ival; |
795 | SIMPLEQ_INIT(&p->queue); |
| 11 | | Loop condition is false. Exiting loop | |
|
796 | err = dev->bus->methods->open_pipe(p); |
797 | if (err) { |
| |
| |
798 | DPRINTF(("%s: endpoint=0x%x failed, error=%s\n", __func__, |
799 | ep->edesc->bEndpointAddress, usbd_errstr(err))); |
800 | free(p, M_USB, dev->bus->pipe_size); |
801 | return (err); |
802 | } |
803 | *pipe = p; |
804 | return (USBD_NORMAL_COMPLETION); |
805 | } |
806 | |
807 | int |
808 | usbd_set_address(struct usbd_device *dev, int addr) |
809 | { |
810 | usb_device_request_t req; |
811 | |
812 | req.bmRequestType = UT_WRITE_DEVICE; |
813 | req.bRequest = UR_SET_ADDRESS; |
814 | USETW(req.wValue, addr); |
815 | USETW(req.wIndex, 0); |
816 | USETW(req.wLength, 0); |
817 | if (usbd_do_request(dev, &req, 0)) |
818 | return (1); |
819 | |
820 | |
821 | usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); |
822 | |
823 | return (0); |
824 | } |
825 | |
826 | int |
827 | usbd_getnewaddr(struct usbd_bus *bus) |
828 | { |
829 | int addr; |
830 | |
831 | for (addr = 1; addr < USB_MAX_DEVICES; addr++) |
832 | if (bus->devices[addr] == NULL) |
833 | return (addr); |
834 | return (-1); |
835 | } |
836 | |
837 | usbd_status |
838 | usbd_probe_and_attach(struct device *parent, struct usbd_device *dev, int port, |
839 | int addr) |
840 | { |
841 | |
842 | |
843 | |
844 | |
845 | static char *cookie = 0; |
846 | struct usb_attach_arg uaa; |
847 | usb_device_descriptor_t *dd = &dev->ddesc; |
848 | int i, confi, nifaces; |
849 | usbd_status err; |
850 | struct device *dv; |
851 | struct usbd_interface **ifaces; |
852 | extern struct rwlock usbpalock; |
853 | |
854 | rw_enter_write(&usbpalock); |
855 | |
856 | uaa.device = dev; |
857 | uaa.iface = NULL; |
858 | uaa.ifaces = NULL; |
859 | uaa.nifaces = 0; |
860 | uaa.usegeneric = 0; |
861 | uaa.port = port; |
862 | uaa.configno = UHUB_UNK_CONFIGURATION; |
863 | uaa.ifaceno = UHUB_UNK_INTERFACE; |
864 | uaa.vendor = UGETW(dd->idVendor); |
865 | uaa.product = UGETW(dd->idProduct); |
866 | uaa.release = UGETW(dd->bcdDevice); |
867 | uaa.cookie = ++cookie; |
868 | |
869 | |
870 | DPRINTF(("usbd_probe_and_attach trying device specific drivers\n")); |
871 | dv = config_found(parent, &uaa, usbd_print); |
872 | if (dv) { |
| |
| |
873 | dev->subdevs = mallocarray(2, sizeof dv, M_USB, M_NOWAIT); |
874 | if (dev->subdevs == NULL) { |
875 | err = USBD_NOMEM; |
876 | goto fail; |
877 | } |
878 | dev->nsubdev = 2; |
879 | dev->subdevs[dev->ndevs++] = dv; |
880 | dev->subdevs[dev->ndevs] = 0; |
881 | err = USBD_NORMAL_COMPLETION; |
882 | goto fail; |
883 | } |
884 | |
885 | DPRINTF(("%s: no device specific driver found\n", __func__)); |
886 | |
887 | DPRINTF(("%s: looping over %d configurations\n", __func__, |
888 | dd->bNumConfigurations)); |
889 | |
890 | for (confi = 0; confi < dd->bNumConfigurations; confi++) { |
| 37 | | Assuming 'confi' is < field 'bNumConfigurations' | |
|
| 38 | | Loop condition is true. Entering loop body | |
|
| 77 | | Assuming 'confi' is >= field 'bNumConfigurations' | |
|
| 78 | | Loop condition is false. Execution continues on line 958 | |
|
891 | DPRINTFN(1,("%s: trying config idx=%d\n", __func__, |
892 | confi)); |
893 | err = usbd_set_config_index(dev, confi, 1); |
| 39 | | Calling 'usbd_set_config_index' | |
|
| 66 | | Returning from 'usbd_set_config_index' | |
|
894 | if (err) { |
| |
895 | #ifdef USB_DEBUG |
896 | DPRINTF(("%s: port %d, set config at addr %d failed, " |
897 | "error=%s\n", parent->dv_xname, port, |
898 | addr, usbd_errstr(err))); |
899 | #else |
900 | printf("%s: port %d, set config %d at addr %d failed\n", |
901 | parent->dv_xname, port, confi, addr); |
902 | #endif |
903 | |
904 | goto fail; |
905 | } |
906 | nifaces = dev->cdesc->bNumInterfaces; |
907 | uaa.configno = dev->cdesc->bConfigurationValue; |
908 | ifaces = mallocarray(nifaces, sizeof(*ifaces), M_USB, M_NOWAIT); |
909 | if (ifaces == NULL) { |
| 68 | | Assuming 'ifaces' is not equal to NULL | |
|
| |
910 | err = USBD_NOMEM; |
911 | goto fail; |
912 | } |
913 | for (i = 0; i < nifaces; i++) |
| 70 | | Loop condition is false. Execution continues on line 915 | |
|
914 | ifaces[i] = &dev->ifaces[i]; |
915 | uaa.ifaces = ifaces; |
916 | uaa.nifaces = nifaces; |
917 | |
918 | |
919 | dev->subdevs = mallocarray(nifaces + 2, sizeof(dv), M_USB, |
920 | M_NOWAIT | M_ZERO); |
921 | if (dev->subdevs == NULL) { |
| 71 | | Assuming field 'subdevs' is not equal to NULL | |
|
| |
922 | free(ifaces, M_USB, nifaces * sizeof(*ifaces)); |
923 | err = USBD_NOMEM; |
924 | goto fail; |
925 | } |
926 | dev->nsubdev = nifaces + 2; |
927 | |
928 | for (i = 0; i < nifaces; i++) { |
| 73 | | Loop condition is false. Execution continues on line 939 | |
|
929 | if (usbd_iface_claimed(dev, i)) |
930 | continue; |
931 | uaa.iface = ifaces[i]; |
932 | uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; |
933 | dv = config_found(parent, &uaa, usbd_print); |
934 | if (dv != NULL) { |
935 | dev->subdevs[dev->ndevs++] = dv; |
936 | usbd_claim_iface(dev, i); |
937 | } |
938 | } |
939 | free(ifaces, M_USB, nifaces * sizeof(*ifaces)); |
940 | |
941 | if (dev->ndevs > 0) { |
| 74 | | Assuming field 'ndevs' is <= 0 | |
|
| |
942 | for (i = 0; i < nifaces; i++) { |
943 | if (!usbd_iface_claimed(dev, i)) |
944 | break; |
945 | } |
946 | if (i < nifaces) |
947 | goto generic; |
948 | else |
949 | goto fail; |
950 | } |
951 | |
952 | free(dev->subdevs, M_USB, dev->nsubdev * sizeof(*dev->subdevs)); |
953 | dev->subdevs = NULL; |
| 76 | | Null pointer value stored to field 'subdevs' | |
|
954 | dev->nsubdev = 0; |
955 | } |
956 | |
957 | |
958 | if (dd->bNumConfigurations > 1) |
| |
959 | usbd_set_config_index(dev, 0, 0); |
960 | |
961 | DPRINTF(("%s: no interface drivers found\n", __func__)); |
962 | |
963 | generic: |
964 | |
965 | uaa.iface = NULL; |
966 | uaa.usegeneric = 1; |
967 | uaa.configno = dev->ndevs == 0 ? UHUB_UNK_CONFIGURATION : |
| 80 | | Assuming field 'ndevs' is not equal to 0 | |
|
| |
968 | dev->cdesc->bConfigurationValue; |
969 | uaa.ifaceno = UHUB_UNK_INTERFACE; |
970 | dv = config_found(parent, &uaa, usbd_print); |
971 | if (dv != NULL) { |
| 82 | | Assuming 'dv' is not equal to NULL | |
|
| |
972 | if (dev->ndevs == 0) { |
| |
973 | dev->subdevs = mallocarray(2, sizeof dv, M_USB, M_NOWAIT); |
974 | if (dev->subdevs == NULL) { |
975 | err = USBD_NOMEM; |
976 | goto fail; |
977 | } |
978 | dev->nsubdev = 2; |
979 | } |
980 | dev->subdevs[dev->ndevs++] = dv; |
| 85 | | Array access (via field 'subdevs') results in a null pointer dereference |
|
981 | dev->subdevs[dev->ndevs] = 0; |
982 | err = USBD_NORMAL_COMPLETION; |
983 | goto fail; |
984 | } |
985 | |
986 | |
987 | |
988 | |
989 | |
990 | |
991 | DPRINTF(("%s: generic attach failed\n", __func__)); |
992 | err = USBD_NORMAL_COMPLETION; |
993 | fail: |
994 | rw_exit_write(&usbpalock); |
995 | return (err); |
996 | } |
997 | |
998 | |
999 | |
1000 | |
1001 | |
1002 | |
1003 | |
1004 | |
1005 | usbd_status |
1006 | usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth, |
1007 | int speed, int port, struct usbd_port *up) |
1008 | { |
1009 | struct usbd_device *dev, *adev, *hub; |
1010 | usb_device_descriptor_t *dd; |
1011 | usbd_status err; |
1012 | uint32_t mps, mps0; |
1013 | int addr, i, p; |
1014 | |
1015 | DPRINTF(("%s: bus=%p port=%d depth=%d speed=%d\n", __func__, |
1016 | bus, port, depth, speed)); |
1017 | |
1018 | |
1019 | |
1020 | |
1021 | |
1022 | switch (speed) { |
| 1 | Control jumps to 'case 4:' at line 1030 | |
|
1023 | case USB_SPEED_LOW: |
1024 | mps0 = 8; |
1025 | break; |
1026 | case USB_SPEED_HIGH: |
1027 | case USB_SPEED_FULL: |
1028 | mps0 = 64; |
1029 | break; |
1030 | case USB_SPEED_SUPER: |
1031 | mps0 = 512; |
1032 | break; |
1033 | default: |
1034 | return (USBD_INVAL); |
1035 | } |
1036 | |
1037 | addr = usbd_getnewaddr(bus); |
| 2 | | Execution continues on line 1037 | |
|
1038 | if (addr < 0) { |
| |
1039 | printf("%s: No free USB addresses, new device ignored.\n", |
1040 | bus->bdev.dv_xname); |
1041 | return (USBD_NO_ADDR); |
1042 | } |
1043 | |
1044 | dev = malloc(sizeof *dev, M_USB, M_NOWAIT | M_ZERO); |
1045 | if (dev == NULL) |
| 4 | | Assuming 'dev' is not equal to NULL | |
|
| |
1046 | return (USBD_NOMEM); |
1047 | |
1048 | dev->bus = bus; |
1049 | |
1050 | |
1051 | dev->def_ep.edesc = &dev->def_ep_desc; |
1052 | |
1053 | |
1054 | dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE; |
1055 | dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT; |
1056 | dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT; |
1057 | dev->def_ep_desc.bmAttributes = UE_CONTROL; |
1058 | dev->def_ep_desc.bInterval = 0; |
1059 | USETW(dev->def_ep_desc.wMaxPacketSize, mps0); |
1060 | |
1061 | dev->quirks = &usbd_no_quirk; |
1062 | dev->address = USB_START_ADDR; |
1063 | dev->ddesc.bMaxPacketSize = 0; |
1064 | dev->depth = depth; |
1065 | dev->powersrc = up; |
1066 | dev->myhub = up->parent; |
1067 | dev->speed = speed; |
1068 | dev->langid = USBD_NOLANG; |
1069 | |
1070 | up->device = dev; |
1071 | |
1072 | |
1073 | for (adev = dev, hub = up->parent; |
1074 | hub != NULL && hub->speed != USB_SPEED_HIGH; |
| 6 | | Assuming 'hub' is equal to NULL | |
|
1075 | adev = hub, hub = hub->myhub) |
1076 | ; |
1077 | if (hub) { |
| |
1078 | for (p = 0; p < hub->hub->nports; p++) { |
1079 | if (hub->hub->ports[p].device == adev) { |
1080 | dev->myhsport = &hub->hub->ports[p]; |
1081 | goto found; |
1082 | } |
1083 | } |
1084 | panic("usbd_new_device: cannot find HS port"); |
1085 | found: |
1086 | DPRINTFN(1,("%s: high speed port %d\n", __func__, p)); |
1087 | } else { |
1088 | dev->myhsport = NULL; |
1089 | } |
1090 | |
1091 | |
1092 | err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL, |
| 8 | | Calling 'usbd_setup_pipe' | |
|
| 14 | | Returning from 'usbd_setup_pipe' | |
|
1093 | &dev->default_pipe); |
1094 | if (err) |
| |
1095 | goto fail; |
1096 | |
1097 | dd = &dev->ddesc; |
1098 | |
1099 | |
1100 | |
1101 | |
1102 | |
1103 | |
1104 | |
1105 | for (i = 0; i < 3; i++) { |
| 16 | | Loop condition is true. Entering loop body | |
|
1106 | |
1107 | |
1108 | |
1109 | err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd); |
1110 | if (!err) |
| |
| |
1111 | break; |
1112 | if (err == USBD_TIMEOUT) |
1113 | goto fail; |
1114 | usbd_delay_ms(dev, 100+50*i); |
1115 | } |
1116 | |
1117 | |
1118 | if (err) { |
| 19 | | Execution continues on line 1118 | |
|
| |
1119 | USETW(dev->def_ep_desc.wMaxPacketSize, |
1120 | USB_DEVICE_DESCRIPTOR_SIZE); |
1121 | usbd_reset_port(up->parent, port); |
1122 | for (i = 0; i < 3; i++) { |
1123 | err = usbd_get_desc(dev, UDESC_DEVICE, 0, |
1124 | USB_DEVICE_DESCRIPTOR_SIZE, dd); |
1125 | if (!err) |
1126 | break; |
1127 | if (err == USBD_TIMEOUT) |
1128 | goto fail; |
1129 | usbd_delay_ms(dev, 100+50*i); |
1130 | } |
1131 | } |
1132 | |
1133 | |
1134 | if (err) { |
| |
1135 | USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET); |
1136 | usbd_reset_port(up->parent, port); |
1137 | usbd_delay_ms(dev, 500); |
1138 | err = usbd_get_desc(dev, UDESC_DEVICE, 0, |
1139 | USB_MAX_IPACKET, dd); |
1140 | } |
1141 | |
1142 | if (err) |
1143 | goto fail; |
1144 | |
1145 | DPRINTF(("%s: adding unit addr=%d, rev=%02x, class=%d, subclass=%d, " |
1146 | "protocol=%d, maxpacket=%d, len=%d, speed=%d\n", __func__, |
1147 | addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass, |
1148 | dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, |
1149 | dev->speed)); |
1150 | |
1151 | if ((dd->bDescriptorType != UDESC_DEVICE) || |
| 22 | | Assuming field 'bDescriptorType' is equal to UDESC_DEVICE | |
|
| |
1152 | (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE)) { |
| 23 | | Assuming field 'bLength' is >= USB_DEVICE_DESCRIPTOR_SIZE | |
|
1153 | err = USBD_INVAL; |
1154 | goto fail; |
1155 | } |
1156 | |
1157 | mps = dd->bMaxPacketSize; |
1158 | if (speed == USB_SPEED_SUPER) { |
| |
1159 | if (mps == 0xff) |
| 26 | | Assuming 'mps' is not equal to 255 | |
|
| |
1160 | mps = 9; |
1161 | |
1162 | mps = (1 << mps); |
1163 | } |
1164 | |
1165 | if (mps != mps0) { |
| 28 | | Assuming 'mps' is equal to 'mps0' | |
|
1166 | if ((speed == USB_SPEED_LOW) || |
1167 | (mps != 8 && mps != 16 && mps != 32 && mps != 64)) { |
1168 | err = USBD_INVAL; |
1169 | goto fail; |
1170 | } |
1171 | USETW(dev->def_ep_desc.wMaxPacketSize, mps); |
1172 | } |
1173 | |
1174 | |
1175 | |
1176 | if (bus->methods->dev_setaddr != NULL && |
| 29 | | Assuming field 'dev_setaddr' is equal to NULL | |
|
1177 | bus->methods->dev_setaddr(dev, addr)) { |
1178 | err = USBD_SET_ADDR_FAILED; |
1179 | goto fail; |
1180 | } |
1181 | |
1182 | |
1183 | usbd_delay_ms(dev, 10); |
1184 | |
1185 | |
1186 | |
1187 | |
1188 | |
1189 | dev->address = addr; |
1190 | |
1191 | err = usbd_reload_device_desc(dev); |
1192 | if (err) |
| |
1193 | goto fail; |
1194 | |
1195 | |
1196 | if (dev->quirks->uq_flags & UQ_EHCI_NEEDTO_DISOWN) { |
| 31 | | Assuming the condition is false | |
|
| |
1197 | |
1198 | if (dev->bus->usbrev == USBREV_2_0) { |
1199 | DPRINTF(("%s: disown request issues to dev:%p on usb2.0 bus\n", |
1200 | __func__, dev)); |
1201 | usbd_port_disown_to_1_1(dev->myhub, port); |
1202 | |
1203 | usbd_reset_port(dev->myhub, port); |
1204 | return (USBD_NORMAL_COMPLETION); |
1205 | } |
1206 | } |
1207 | |
1208 | |
1209 | dev->power = USB_MIN_POWER; |
1210 | dev->self_powered = 0; |
1211 | |
1212 | DPRINTF(("%s: new dev (addr %d), dev=%p, parent=%p\n", __func__, |
1213 | addr, dev, parent)); |
1214 | |
1215 | |
1216 | err = usbd_cache_devinfo(dev); |
1217 | if (err) |
| |
1218 | goto fail; |
1219 | |
1220 | bus->devices[addr] = dev; |
1221 | |
1222 | err = usbd_probe_and_attach(parent, dev, port, addr); |
| 34 | | Calling 'usbd_probe_and_attach' | |
|
1223 | if (err) |
1224 | goto fail; |
1225 | |
1226 | return (USBD_NORMAL_COMPLETION); |
1227 | |
1228 | fail: |
1229 | usb_free_device(dev); |
1230 | up->device = NULL; |
1231 | return (err); |
1232 | } |
1233 | |
1234 | usbd_status |
1235 | usbd_reload_device_desc(struct usbd_device *dev) |
1236 | { |
1237 | usbd_status err; |
1238 | |
1239 | |
1240 | err = usbd_get_desc(dev, UDESC_DEVICE, 0, |
1241 | USB_DEVICE_DESCRIPTOR_SIZE, &dev->ddesc); |
1242 | if (err) |
1243 | return (err); |
1244 | |
1245 | |
1246 | dev->quirks = usbd_find_quirk(&dev->ddesc); |
1247 | |
1248 | return (USBD_NORMAL_COMPLETION); |
1249 | } |
1250 | |
1251 | int |
1252 | usbd_print(void *aux, const char *pnp) |
1253 | { |
1254 | struct usb_attach_arg *uaa = aux; |
1255 | char *devinfop; |
1256 | |
1257 | devinfop = malloc(DEVINFOSIZE, M_TEMP, M_WAITOK); |
1258 | usbd_devinfo(uaa->device, 0, devinfop, DEVINFOSIZE); |
1259 | |
1260 | DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device)); |
1261 | if (pnp) { |
1262 | if (!uaa->usegeneric) { |
1263 | free(devinfop, M_TEMP, DEVINFOSIZE); |
1264 | return (QUIET); |
1265 | } |
1266 | printf("%s at %s", devinfop, pnp); |
1267 | } |
1268 | if (uaa->port != 0) |
1269 | printf(" port %d", uaa->port); |
1270 | if (uaa->configno != UHUB_UNK_CONFIGURATION) |
1271 | printf(" configuration %d", uaa->configno); |
1272 | if (uaa->ifaceno != UHUB_UNK_INTERFACE) |
1273 | printf(" interface %d", uaa->ifaceno); |
1274 | |
1275 | if (!pnp) |
1276 | printf(" %s\n", devinfop); |
1277 | free(devinfop, M_TEMP, DEVINFOSIZE); |
1278 | return (UNCONF); |
1279 | } |
1280 | |
1281 | void |
1282 | usbd_fill_deviceinfo(struct usbd_device *dev, struct usb_device_info *di) |
1283 | { |
1284 | struct usbd_port *p; |
1285 | int i; |
1286 | |
1287 | di->udi_bus = dev->bus->usbctl->dv_unit; |
1288 | di->udi_addr = dev->address; |
1289 | strlcpy(di->udi_vendor, dev->vendor, sizeof(di->udi_vendor)); |
1290 | strlcpy(di->udi_product, dev->product, sizeof(di->udi_product)); |
1291 | usbd_printBCD(di->udi_release, sizeof di->udi_release, |
1292 | UGETW(dev->ddesc.bcdDevice)); |
1293 | di->udi_vendorNo = UGETW(dev->ddesc.idVendor); |
1294 | di->udi_productNo = UGETW(dev->ddesc.idProduct); |
1295 | di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice); |
1296 | di->udi_class = dev->ddesc.bDeviceClass; |
1297 | di->udi_subclass = dev->ddesc.bDeviceSubClass; |
1298 | di->udi_protocol = dev->ddesc.bDeviceProtocol; |
1299 | di->udi_config = dev->config; |
1300 | di->udi_power = dev->self_powered ? 0 : dev->power; |
1301 | di->udi_speed = dev->speed; |
1302 | di->udi_port = dev->powersrc ? dev->powersrc->portno : 0; |
1303 | |
1304 | if (dev->subdevs != NULL) { |
1305 | for (i = 0; dev->subdevs[i] && i < USB_MAX_DEVNAMES; i++) { |
1306 | strncpy(di->udi_devnames[i], |
1307 | dev->subdevs[i]->dv_xname, USB_MAX_DEVNAMELEN); |
1308 | di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0'; |
1309 | } |
1310 | } else |
1311 | i = 0; |
1312 | |
1313 | for (; i < USB_MAX_DEVNAMES; i++) |
1314 | di->udi_devnames[i][0] = 0; |
1315 | |
1316 | if (dev->hub) { |
1317 | for (i = 0; |
1318 | i < nitems(di->udi_ports) && i < dev->hub->nports; i++) { |
1319 | p = &dev->hub->ports[i]; |
1320 | di->udi_ports[i] = UGETW(p->status.wPortChange) << 16 | |
1321 | UGETW(p->status.wPortStatus); |
1322 | } |
1323 | di->udi_nports = dev->hub->nports; |
1324 | } else |
1325 | di->udi_nports = 0; |
1326 | |
1327 | bzero(di->udi_serial, sizeof(di->udi_serial)); |
1328 | if (dev->serial != NULL) |
1329 | strlcpy(di->udi_serial, dev->serial, |
1330 | sizeof(di->udi_serial)); |
1331 | } |
1332 | |
1333 | int |
1334 | usbd_get_routestring(struct usbd_device *dev, uint32_t *route) |
1335 | { |
1336 | struct usbd_device *hub; |
1337 | uint32_t r; |
1338 | uint8_t port; |
1339 | |
1340 | |
1341 | |
1342 | |
1343 | |
1344 | |
1345 | r = dev->powersrc ? dev->powersrc->portno : 0; |
1346 | for (hub = dev->myhub; hub && hub->depth > 1; hub = hub->myhub) { |
1347 | port = hub->powersrc ? hub->powersrc->portno : 0; |
1348 | if (port > 15) |
1349 | return -1; |
1350 | r <<= 4; |
1351 | r |= port; |
1352 | } |
1353 | |
1354 | |
1355 | port = (hub && hub->powersrc) ? hub->powersrc->portno : 0; |
1356 | r <<= 8; |
1357 | r |= port; |
1358 | |
1359 | *route = r; |
1360 | return 0; |
1361 | } |
1362 | |
1363 | int |
1364 | usbd_get_location(struct usbd_device *dev, struct usbd_interface *iface, |
1365 | uint8_t *bus, uint32_t *route, uint8_t *ifaceno) |
1366 | { |
1367 | int i; |
1368 | uint32_t r; |
1369 | |
1370 | if (dev == NULL || usbd_is_dying(dev) || |
1371 | dev->cdesc == NULL || |
1372 | dev->cdesc->bNumInterfaces == 0 || |
1373 | dev->bus == NULL || |
1374 | dev->bus->usbctl == NULL || |
1375 | dev->myhub == NULL || |
1376 | dev->powersrc == NULL) |
1377 | return -1; |
1378 | |
1379 | for(i = 0; i < dev->cdesc->bNumInterfaces; i++) { |
1380 | if (iface == &dev->ifaces[i]) { |
1381 | *bus = dev->bus->usbctl->dv_unit; |
1382 | *route = (usbd_get_routestring(dev, &r)) ? 0 : r; |
1383 | *ifaceno = i; |
1384 | return 0; |
1385 | } |
1386 | } |
1387 | |
1388 | return -1; |
1389 | } |
1390 | |
1391 | |
1392 | usb_config_descriptor_t * |
1393 | usbd_get_cdesc(struct usbd_device *dev, int index, u_int *lenp) |
1394 | { |
1395 | usb_config_descriptor_t *cdesc, *tdesc, cdescr; |
1396 | u_int len; |
1397 | usbd_status err; |
1398 | |
1399 | if (index == USB_CURRENT_CONFIG_INDEX) { |
1400 | tdesc = usbd_get_config_descriptor(dev); |
1401 | if (tdesc == NULL) |
1402 | return (NULL); |
1403 | len = UGETW(tdesc->wTotalLength); |
1404 | if (lenp) |
1405 | *lenp = len; |
1406 | cdesc = malloc(len, M_TEMP, M_WAITOK); |
1407 | memcpy(cdesc, tdesc, len); |
1408 | DPRINTFN(5,("%s: current, len=%u\n", __func__, len)); |
1409 | } else { |
1410 | err = usbd_get_desc(dev, UDESC_CONFIG, index, |
1411 | USB_CONFIG_DESCRIPTOR_SIZE, &cdescr); |
1412 | if (err || cdescr.bDescriptorType != UDESC_CONFIG) |
1413 | return (NULL); |
1414 | len = UGETW(cdescr.wTotalLength); |
1415 | DPRINTFN(5,("%s: index=%d, len=%u\n", __func__, index, len)); |
1416 | if (lenp) |
1417 | *lenp = len; |
1418 | cdesc = malloc(len, M_TEMP, M_WAITOK); |
1419 | err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdesc); |
1420 | if (err) { |
1421 | free(cdesc, M_TEMP, len); |
1422 | return (NULL); |
1423 | } |
1424 | } |
1425 | return (cdesc); |
1426 | } |
1427 | |
1428 | void |
1429 | usb_free_device(struct usbd_device *dev) |
1430 | { |
1431 | int ifcidx, nifc; |
1432 | |
1433 | DPRINTF(("%s: %p\n", __func__, dev)); |
1434 | |
1435 | if (dev->default_pipe != NULL) |
1436 | usbd_close_pipe(dev->default_pipe); |
1437 | if (dev->ifaces != NULL) { |
1438 | nifc = dev->cdesc->bNumInterfaces; |
1439 | for (ifcidx = 0; ifcidx < nifc; ifcidx++) |
1440 | usbd_free_iface_data(dev, ifcidx); |
1441 | free(dev->ifaces, M_USB, nifc * sizeof(*dev->ifaces)); |
1442 | } |
1443 | if (dev->cdesc != NULL) |
1444 | free(dev->cdesc, M_USB, UGETW(dev->cdesc->wTotalLength)); |
1445 | free(dev->subdevs, M_USB, dev->nsubdev * sizeof(*dev->subdevs)); |
1446 | dev->bus->devices[dev->address] = NULL; |
1447 | |
1448 | if (dev->vendor != NULL) |
1449 | free(dev->vendor, M_USB, USB_MAX_STRING_LEN); |
1450 | if (dev->product != NULL) |
1451 | free(dev->product, M_USB, USB_MAX_STRING_LEN); |
1452 | if (dev->serial != NULL) |
1453 | free(dev->serial, M_USB, USB_MAX_STRING_LEN); |
1454 | |
1455 | free(dev, M_USB, sizeof *dev); |
1456 | } |
1457 | |
1458 | |
1459 | |
1460 | |
1461 | |
1462 | int |
1463 | usbd_detach(struct usbd_device *dev, struct device *parent) |
1464 | { |
1465 | int i, rv = 0; |
1466 | |
1467 | usbd_deactivate(dev); |
1468 | |
1469 | if (dev->ndevs > 0) { |
1470 | for (i = 0; dev->subdevs[i] != NULL; i++) |
1471 | rv |= config_detach(dev->subdevs[i], DETACH_FORCE); |
1472 | } |
1473 | |
1474 | if (rv == 0) |
1475 | usb_free_device(dev); |
1476 | |
1477 | return (rv); |
1478 | } |