1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2019 Joyent, Inc.
25 */
26
27
28 /*
29 * USBA: Solaris USB Architecture support
30 *
31 * Utility functions
32 */
33 #define USBA_FRAMEWORK
34 #include <sys/usb/usba/usba_impl.h>
35 #include <sys/usb/usba/hcdi_impl.h>
36 #include <sys/strsun.h>
37
38 extern void usba_free_evdata(usba_evdata_t *);
39
40 static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int);
41
42 /* local functions */
43 static int usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *,
44 usba_pipe_async_req_t *, usb_flags_t);
45 static int usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *,
46 usba_pipe_async_req_t *, usb_flags_t);
47 static int usba_sync_clear_feature(dev_info_t *, usba_ph_impl_t *,
48 usba_pipe_async_req_t *, usb_flags_t);
49
50 /*
51 * Wrapper functions returning parsed standard descriptors without
52 * getting the config cloud first but by just providing the dip.
53 *
54 * The client can easily retrieve the device and config descriptor from
55 * the usb registration and no separate functions are provided
56 *
57 * These functions return failure if the full descriptor can not be
58 * retrieved. These functions will not access the device.
59 * The caller must allocate the buffer.
60 */
61
62 /*
63 * usb_get_if_descr:
64 * Function to get the cooked interface descriptor
65 * This function will not access the device.
66 *
67 * Arguments:
68 * dip - pointer to devinfo of the client
69 * if_index - interface index
70 * alt_setting - alt interface setting
71 * descr - pointer to user allocated interface descr
72 *
73 * Return Values:
74 * USB_SUCCESS - descriptor is valid
75 * USB_FAILURE - full descriptor could not be retrieved
76 * USB_* - refer to usbai.h
77 */
78 int
usb_get_if_descr(dev_info_t * dip,uint_t if_index,uint_t alt_setting,usb_if_descr_t * descr)79 usb_get_if_descr(dev_info_t *dip,
80 uint_t if_index,
81 uint_t alt_setting,
82 usb_if_descr_t *descr)
83 {
84 uchar_t *usb_cfg; /* buf for config descriptor */
85 size_t size, cfg_length;
86
87 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
88 "usb_get_if_descr: %s, index=0x%x, alt#=0x%x",
89 ddi_node_name(dip), if_index, alt_setting);
90
91 if ((dip == NULL) || (descr == NULL)) {
92
93 return (USB_INVALID_ARGS);
94 }
95
96 usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
97 size = usb_parse_if_descr(usb_cfg, cfg_length,
98 if_index, /* interface index */
99 alt_setting, /* alt interface index */
100 descr,
101 USB_IF_DESCR_SIZE);
102
103 if (size != USB_IF_DESCR_SIZE) {
104 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
105 "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
106 size, USB_IF_DESCR_SIZE);
107
108 return (USB_FAILURE);
109 }
110
111 return (USB_SUCCESS);
112 }
113
114
115 /*
116 * usb_get_ep_descr:
117 * Function to get the cooked endpoint descriptor
118 * This function will not access the device.
119 *
120 * Arguments:
121 * dip - pointer to devinfo of the client
122 * if_index - interface index
123 * alt_setting - alternate interface setting
124 * endpoint_index - endpoint index
125 * descr - pointer to user allocated interface descr
126 *
127 * Return Values:
128 * USB_SUCCESS - descriptor is valid
129 * USB_FAILURE - full descriptor could not be retrieved
130 * USB_* - refer to usbai.h
131 */
132 int
usb_get_ep_descr(dev_info_t * dip,uint_t if_index,uint_t alt_setting,uint_t endpoint_index,usb_ep_descr_t * descr)133 usb_get_ep_descr(dev_info_t *dip,
134 uint_t if_index,
135 uint_t alt_setting,
136 uint_t endpoint_index,
137 usb_ep_descr_t *descr)
138 {
139 uchar_t *usb_cfg; /* buf for config descriptor */
140 size_t size, cfg_length;
141
142 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
143 "usb_get_ep_descr: %s, index=0x%x, alt#=0x%x",
144 ddi_node_name(dip), if_index, alt_setting);
145
146 if ((dip == NULL) || (descr == NULL)) {
147
148 return (USB_INVALID_ARGS);
149 }
150
151 usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
152 size = usb_parse_ep_descr(usb_cfg, cfg_length,
153 if_index, /* interface index */
154 alt_setting, /* alt interface index */
155 endpoint_index, /* ep index */
156 descr, USB_EP_DESCR_SIZE);
157
158 if (size != USB_EP_DESCR_SIZE) {
159 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
160 "parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)",
161 size, USB_EP_DESCR_SIZE);
162
163 return (USB_FAILURE);
164 }
165
166 return (USB_SUCCESS);
167 }
168
169
170 /*
171 * usb_lookup_ep_data:
172 * usb_get_ep_data (deprecated):
173 * Function to get specific endpoint descriptor data
174 * This function will not access the device.
175 *
176 * Arguments:
177 * dip - pointer to dev info
178 * usb_client_dev_data_t - pointer to registration data
179 * interface - requested interface
180 * alternate - requested alternate
181 * skip - how many to skip
182 * type - endpoint type
183 * direction - endpoint direction or USB_DIR_DONT_CARE
184 *
185 * Return Values:
186 * NULL or an endpoint descriptor pointer
187 */
188 usb_ep_data_t *
usb_lookup_ep_data(dev_info_t * dip,usb_client_dev_data_t * dev_datap,uint_t interface,uint_t alternate,uint_t skip,uint_t type,uint_t dir)189 usb_lookup_ep_data(dev_info_t *dip,
190 usb_client_dev_data_t *dev_datap,
191 uint_t interface,
192 uint_t alternate,
193 uint_t skip,
194 uint_t type,
195 uint_t dir)
196 {
197 usb_alt_if_data_t *altif_data;
198 int i;
199
200 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
201 "usb_lookup_ep_data: "
202 "if=%d alt=%d skip=%d type=%d dir=%d",
203 interface, alternate, skip, type, dir);
204
205 if ((dip == NULL) || (dev_datap == NULL)) {
206
207 return (NULL);
208 }
209
210 altif_data = &dev_datap->dev_curr_cfg->
211 cfg_if[interface].if_alt[alternate];
212
213 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
214 "altif=0x%p n_ep=%d", (void *)altif_data, altif_data->altif_n_ep);
215
216 for (i = 0; i < altif_data->altif_n_ep; i++) {
217 usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
218 uint8_t ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
219 uint8_t ept_dir = ept->bEndpointAddress & USB_EP_DIR_MASK;
220
221 if (ept->bLength == 0) {
222 continue;
223 }
224 if ((ept_type == type) &&
225 ((type == USB_EP_ATTR_CONTROL) || (dir == ept_dir))) {
226
227 if (skip-- == 0) {
228 USB_DPRINTF_L4(DPRINT_MASK_USBA,
229 usbai_log_handle,
230 "usb_get_ep_data: data=0x%p",
231 (void *)&altif_data->altif_ep[i]);
232
233 return (&altif_data->altif_ep[i]);
234 }
235 }
236 }
237 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
238 "usb_get_ep_data: returning NULL");
239
240 return (NULL);
241 }
242
243
244 /*ARGSUSED*/
245 usb_ep_data_t *
usb_get_ep_data(dev_info_t * dip,usb_client_dev_data_t * dev_datap,uint_t interface,uint_t alternate,uint_t type,uint_t dir)246 usb_get_ep_data(dev_info_t *dip,
247 usb_client_dev_data_t *dev_datap,
248 uint_t interface,
249 uint_t alternate,
250 uint_t type,
251 uint_t dir)
252 {
253 return (usb_lookup_ep_data(dip, dev_datap, interface,
254 alternate, 0, type, dir));
255 }
256
257
258 /*
259 * usb_get_string_descr:
260 * Function to read the string descriptor
261 * This function will access the device and block.
262 *
263 * Arguments:
264 * dip - pointer to devinfo of the client
265 * langid - LANGID to read different LOCALEs
266 * index - index to the string
267 * buf - user provided buffer for string descriptor
268 * buflen - user provided length of the buffer
269 *
270 * Return Values:
271 * USB_SUCCESS - descriptor is valid
272 * USB_FAILURE - full descriptor could not be retrieved
273 * USB_* - refer to usbai.h
274 */
275 int
usb_get_string_descr(dev_info_t * dip,uint16_t langid,uint8_t index,char * buf,size_t buflen)276 usb_get_string_descr(dev_info_t *dip,
277 uint16_t langid,
278 uint8_t index,
279 char *buf,
280 size_t buflen)
281 {
282 mblk_t *data = NULL;
283 uint16_t length;
284 int rval;
285 usb_cr_t completion_reason;
286 size_t len;
287 usb_cb_flags_t cb_flags;
288
289 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
290 "usb_get_string_descr: %s, langid=0x%x index=0x%x",
291 ddi_node_name(dip), langid, index);
292
293 if ((dip == NULL) || (buf == NULL) || (buflen == 0) || (index == 0)) {
294
295 return (USB_INVALID_ARGS);
296 }
297
298 /*
299 * determine the length of the descriptor
300 */
301 rval = usb_pipe_sync_ctrl_xfer(dip,
302 usba_get_dflt_pipe_handle(dip),
303 USB_DEV_REQ_DEV_TO_HOST,
304 USB_REQ_GET_DESCR,
305 (USB_DESCR_TYPE_STRING << 8) | (index & 0xff),
306 langid,
307 4,
308 &data, USB_ATTRS_SHORT_XFER_OK,
309 &completion_reason,
310 &cb_flags, USB_FLAGS_SLEEP);
311
312 if (rval != USB_SUCCESS) {
313 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
314 "rval=%d cr=%d", rval, completion_reason);
315
316 goto done;
317 }
318 if (MBLKL(data) == 0) {
319 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
320 "0 bytes received");
321
322 goto done;
323 }
324
325 ASSERT(data);
326 length = *(data->b_rptr);
327 freemsg(data);
328 data = NULL;
329
330 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
331 "rval=%d, cr=%d, length=%d", rval, completion_reason, length);
332
333 /*
334 * if length is zero the next control request may fail.
335 * the HCD may not support a zero length control request
336 * and return an mblk_t which is NULL along with rval
337 * being USB_SUCCESS and "cr" being USB_CR_OK
338 */
339 if (length < 2) {
340 rval = USB_FAILURE;
341
342 goto done;
343 }
344
345 rval = usb_pipe_sync_ctrl_xfer(dip,
346 usba_get_dflt_pipe_handle(dip),
347 USB_DEV_REQ_DEV_TO_HOST,
348 USB_REQ_GET_DESCR,
349 (USB_DESCR_TYPE_STRING << 8) | (index & 0xff),
350 langid,
351 length,
352 &data, USB_ATTRS_SHORT_XFER_OK,
353 &completion_reason,
354 &cb_flags, USB_FLAGS_SLEEP);
355
356 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
357 "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
358
359 if ((data == NULL) || (rval != USB_SUCCESS)) {
360 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
361 "failed to get string descriptor (rval=%d cr=%d)",
362 rval, completion_reason);
363
364 goto done;
365 }
366
367 if ((length = MBLKL(data)) != 0) {
368 len = usba_ascii_string_descr(data->b_rptr, length, buf,
369 buflen);
370 USB_DPRINTF_L4(DPRINT_MASK_USBA,
371 usbai_log_handle, "buf=%s buflen=%lu", buf, len);
372
373 ASSERT(len <= buflen);
374 } else {
375 rval = USB_FAILURE;
376 }
377 done:
378 freemsg(data);
379
380 return (rval);
381 }
382
383
384 /*
385 * usb_get_dev_descr:
386 * utility function to get device descriptor from usba_device
387 *
388 * Arguments:
389 * dip - pointer to devinfo of the client
390 *
391 * Return Values:
392 * usb_dev_descr - device descriptor or NULL
393 */
394 usb_dev_descr_t *
usb_get_dev_descr(dev_info_t * dip)395 usb_get_dev_descr(dev_info_t *dip)
396 {
397 usba_device_t *usba_device;
398 usb_dev_descr_t *usb_dev_descr = NULL;
399
400 if (dip) {
401 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
402 "usb_get_dev_descr: %s", ddi_node_name(dip));
403
404 usba_device = usba_get_usba_device(dip);
405 mutex_enter(&usba_device->usb_mutex);
406 usb_dev_descr = usba_device->usb_dev_descr;
407 mutex_exit(&usba_device->usb_mutex);
408 }
409
410 return (usb_dev_descr);
411 }
412
413
414 /*
415 * usb_get_raw_cfg_data:
416 * utility function to get raw config descriptor from usba_device
417 *
418 * Arguments:
419 * dip - pointer to devinfo of the client
420 * length - pointer to copy the cfg length
421 *
422 * Return Values:
423 * usb_cfg - raw config descriptor
424 */
425 uchar_t *
usb_get_raw_cfg_data(dev_info_t * dip,size_t * length)426 usb_get_raw_cfg_data(dev_info_t *dip, size_t *length)
427 {
428 usba_device_t *usba_device;
429 uchar_t *usb_cfg;
430
431 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
432 "usb_get_raw_cfg_data: %s", ddi_node_name(dip));
433
434 if ((dip == NULL) || (length == NULL)) {
435
436 return (NULL);
437 }
438
439 usba_device = usba_get_usba_device(dip);
440
441 mutex_enter(&usba_device->usb_mutex);
442 usb_cfg = usba_device->usb_cfg;
443 *length = usba_device->usb_cfg_length;
444 mutex_exit(&usba_device->usb_mutex);
445
446 return (usb_cfg);
447 }
448
449
450 /*
451 * usb_get_addr:
452 * utility function to return current usb address, mostly
453 * for debugging purposes
454 *
455 * Arguments:
456 * dip - pointer to devinfo of the client
457 *
458 * Return Values:
459 * address - USB Device Address
460 */
461 int
usb_get_addr(dev_info_t * dip)462 usb_get_addr(dev_info_t *dip)
463 {
464 int address = 0;
465
466 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
467 "usb_get_addr: %s", ddi_node_name(dip));
468
469 if (dip) {
470 usba_device_t *usba_device = usba_get_usba_device(dip);
471
472 mutex_enter(&usba_device->usb_mutex);
473 address = usba_device->usb_addr;
474 mutex_exit(&usba_device->usb_mutex);
475 }
476
477 return (address);
478 }
479
480
481 /*
482 * usb_set_cfg():
483 * set configuration, use with caution (issues USB_REQ_SET_CONFIG)
484 * Changing configuration will fail if pipes are still open or when
485 * invoked from a driver bound to an interface on a composite device.
486 *
487 * This function will access the device and block
488 *
489 * Arguments:
490 * dip - pointer to devinfo of the client
491 * cfg_index - config index
492 * cfg_value - config value to be set
493 * flags - USB_FLAGS_SLEEP:
494 * wait for completion
495 * cb - if USB_FLAGS_SLEEP has not been specified
496 * this callback function will be called on
497 * completion. This callback may be NULL
498 * and no notification of completion will then
499 * be provided.
500 * cb_arg - 2nd argument to callback function.
501 *
502 * Return Values:
503 * USB_SUCCESS: - new configuration was set
504 * USB_FAILURE: - new configuration could not be set
505 * USB_BUSY: - some pipes were open or there were children
506 * USB_* - refer to usbai.h
507 */
508 int
usb_set_cfg(dev_info_t * dip,uint_t cfg_index,usb_flags_t usb_flags,void (* cb)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t cb_arg)509 usb_set_cfg(dev_info_t *dip,
510 uint_t cfg_index,
511 usb_flags_t usb_flags,
512 void (*cb)(
513 usb_pipe_handle_t ph,
514 usb_opaque_t arg,
515 int rval,
516 usb_cb_flags_t flags),
517 usb_opaque_t cb_arg)
518 {
519 usb_pipe_handle_t ph;
520
521 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
522 "usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x",
523 ddi_driver_name(dip), ddi_get_instance(dip), cfg_index,
524 usb_flags);
525
526 if (dip == NULL) {
527
528 return (USB_INVALID_ARGS);
529 }
530
531 if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
532
533 return (USB_INVALID_CONTEXT);
534 }
535
536 if (!usb_owns_device(dip)) {
537
538 return (USB_INVALID_PERM);
539 }
540
541 ph = usba_get_dflt_pipe_handle(dip);
542 if (usba_hold_ph_data(ph) == NULL) {
543
544 return (USB_INVALID_PIPE);
545 }
546
547 return (usba_pipe_setup_func_call(dip,
548 usba_sync_set_cfg, (usba_ph_impl_t *)ph,
549 (usb_opaque_t)((uintptr_t)cfg_index), usb_flags, cb, cb_arg));
550 }
551
552
553 static int
usba_sync_set_cfg(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t flags)554 usba_sync_set_cfg(dev_info_t *dip,
555 usba_ph_impl_t *ph_impl,
556 usba_pipe_async_req_t *request,
557 usb_flags_t flags)
558 {
559 int rval;
560 usb_cr_t completion_reason;
561 usb_cb_flags_t cb_flags;
562 usba_device_t *usba_device;
563 int i, ph_open_cnt;
564 uint_t cfg_index = (uint_t)((uintptr_t)(request->arg));
565 size_t size;
566 usb_cfg_descr_t confdescr;
567 dev_info_t *pdip;
568
569 usba_device = usba_get_usba_device(dip);
570
571 /*
572 * default pipe is still open
573 * all other pipes should be closed
574 */
575 for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
576 if (usba_device->usb_ph_list[i].usba_ph_data) {
577 ph_open_cnt++;
578 break;
579 }
580 }
581
582 if (ph_open_cnt || ddi_get_child(dip)) {
583 usba_release_ph_data(ph_impl);
584
585 return (USB_BUSY);
586 }
587
588 /*
589 * check if the configuration meets the
590 * power budget requirement
591 */
592 if (usba_is_root_hub(dip)) {
593 /*
594 * root hub should never be multi-configured.
595 * the code is here just to ensure
596 */
597 usba_release_ph_data(ph_impl);
598
599 return (USB_FAILURE);
600 }
601 pdip = ddi_get_parent(dip);
602
603 /*
604 * increase the power budget value back to the unconfigured
605 * state to eliminate the influence of the old configuration
606 * before checking the new configuration; but remember to
607 * make a decrement before leaving this routine to restore
608 * the power consumption state of the device no matter it
609 * is in the new or old configuration
610 */
611 usba_hubdi_incr_power_budget(pdip, usba_device);
612
613 if ((usba_hubdi_check_power_budget(pdip, usba_device,
614 cfg_index)) != USB_SUCCESS) {
615 usba_hubdi_decr_power_budget(pdip, usba_device);
616
617 usba_release_ph_data(ph_impl);
618
619 return (USB_FAILURE);
620 }
621
622 size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index],
623 USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE);
624
625 /* hubdi should ensure that this descriptor is correct */
626 ASSERT(size == USB_CFG_DESCR_SIZE);
627
628 /* set the configuration */
629 rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl,
630 USB_DEV_REQ_HOST_TO_DEV,
631 USB_REQ_SET_CFG,
632 confdescr.bConfigurationValue,
633 0,
634 0,
635 NULL, 0,
636 &completion_reason,
637 &cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP);
638
639 if (rval == USB_SUCCESS) {
640 mutex_enter(&usba_device->usb_mutex);
641 usba_device->usb_cfg_value = confdescr.bConfigurationValue;
642 usba_device->usb_active_cfg_ndx = cfg_index;
643 usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index];
644 usba_device->usb_cfg_length = confdescr.wTotalLength;
645 mutex_exit(&usba_device->usb_mutex);
646
647 /* update the configuration property */
648 (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
649 "configuration#", usba_device->usb_cfg_value);
650 }
651
652 /*
653 * usba_device->usb_cfg always stores current configuration
654 * descriptor no matter SET_CFG request succeeded or not,
655 * so usba_hubdi_decr_power_budget can be done regardless
656 * of rval above
657 */
658 usba_hubdi_decr_power_budget(pdip, usba_device);
659
660 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
661 "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
662
663 usba_release_ph_data(ph_impl);
664
665 return (rval);
666 }
667
668
669
670 /*
671 * usb_get_cfg():
672 * get configuration value
673 *
674 * Arguments:
675 * dip - pointer to devinfo of the client
676 * cfg_value - current config value
677 * flags - none, always blocks
678 *
679 * Return Values:
680 * USB_SUCCESS: - config value was retrieved
681 * USB_FAILURE: - config value could not be retrieved
682 * USB_* - refer to usbai.h
683 */
684 int
usb_get_cfg(dev_info_t * dip,uint_t * cfgval,usb_flags_t flags)685 usb_get_cfg(dev_info_t *dip,
686 uint_t *cfgval,
687 usb_flags_t flags)
688 {
689 int rval;
690 usb_cr_t completion_reason;
691 mblk_t *data = NULL;
692 usb_cb_flags_t cb_flags;
693 usb_pipe_handle_t ph;
694
695 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
696 "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags);
697
698 if ((cfgval == NULL) || (dip == NULL)) {
699
700 return (USB_INVALID_ARGS);
701 }
702
703 ph = usba_get_dflt_pipe_handle(dip);
704
705 /*
706 * get the cfg value
707 */
708 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
709 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV,
710 USB_REQ_GET_CFG,
711 0,
712 0,
713 1, /* returns one byte of data */
714 &data, 0,
715 &completion_reason,
716 &cb_flags, flags);
717
718 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
719 "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
720
721 if ((rval == USB_SUCCESS) && data &&
722 (MBLKL(data) == 1)) {
723 *cfgval = *(data->b_rptr);
724 } else {
725 *cfgval = 1;
726 if (rval == USB_SUCCESS) {
727 rval = USB_FAILURE;
728 }
729 }
730
731 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
732 "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval);
733
734 freemsg(data);
735
736 return (rval);
737 }
738
739
740 /*
741 * usb_get_current_cfgidx:
742 * get current current config index
743 */
744 uint_t
usb_get_current_cfgidx(dev_info_t * dip)745 usb_get_current_cfgidx(dev_info_t *dip)
746 {
747 usba_device_t *usba_device = usba_get_usba_device(dip);
748 uint_t ndx;
749
750 mutex_enter(&usba_device->usb_mutex);
751 ndx = usba_device->usb_active_cfg_ndx;
752 mutex_exit(&usba_device->usb_mutex);
753
754 return (ndx);
755 }
756
757
758 /*
759 * usb_get_if_number:
760 * get usb interface number of current OS device node.
761 *
762 * Arguments:
763 * dip - pointer to devinfo of the client
764 *
765 * Return Values:
766 * USB_COMBINED_NODE if the driver is responsible for the entire
767 * device and this dip doesn't correspond to a device node.
768 * USB_DEVICE_NODE if the driver is responsible for the entire device
769 * and this dip corresponds to a device node.
770 * interface number: otherwise.
771 */
772 int
usb_get_if_number(dev_info_t * dip)773 usb_get_if_number(dev_info_t *dip)
774 {
775 int interface_num;
776 usba_device_t *usba_device = usba_get_usba_device(dip);
777 usb_dev_descr_t *usb_dev_descr;
778
779 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
780 "usb_get_if_number: dip = 0x%p", (void *)dip);
781
782 /* not quite right but we can't return a negative return value */
783 if (dip == NULL) {
784
785 return (0);
786 }
787
788 if (usba_device) {
789 usb_dev_descr = usba_device->usb_dev_descr;
790 } else {
791
792 return (0);
793 }
794
795 interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
796 DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE);
797
798 if (interface_num == USB_COMBINED_NODE) {
799 if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
800 (usb_dev_descr->bDeviceClass == 0)) &&
801 (usba_device->usb_n_cfgs == 1) &&
802 (usba_device->usb_n_ifs == 1))) {
803 interface_num = USB_DEVICE_NODE;
804 }
805 }
806
807 return (interface_num);
808 }
809
810
811 boolean_t
usb_owns_device(dev_info_t * dip)812 usb_owns_device(dev_info_t *dip)
813 {
814 int interface_num = usb_get_if_number(dip);
815
816 return (interface_num < 0 ? B_TRUE : B_FALSE);
817 }
818
819
820 /* check whether the interface is in this interface association */
821 boolean_t
usba_check_if_in_ia(dev_info_t * dip,int n_if)822 usba_check_if_in_ia(dev_info_t *dip, int n_if)
823 {
824 int first_if, if_count;
825
826 first_if = usb_get_if_number(dip);
827 if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
828 DDI_PROP_DONTPASS, "interface-count", -1);
829 if_count += first_if;
830
831 return ((n_if >= first_if && n_if < if_count) ? B_TRUE : B_FALSE);
832 }
833
834
835 uint8_t
usba_get_ifno(dev_info_t * dip)836 usba_get_ifno(dev_info_t *dip)
837 {
838 int interface_num = usb_get_if_number(dip);
839
840 return (uint8_t)(interface_num < 0 ? 0 : interface_num);
841 }
842
843
844 /*
845 * usb_set_alt_if:
846 * set the alternate interface number. Issues USB_REQ_SET_IF
847 * This function will access the device
848 *
849 * Arguments:
850 * dip - pointer to devinfo of the client
851 * if_number - interface number
852 * alt_number - alternate interface number
853 * flags - USB_FLAGS_SLEEP:
854 * wait for completion
855 * cb - if USB_FLAGS_SLEEP has not been specified
856 * this callback function will be called on
857 * completion. This callback may be NULL
858 * and no notification of completion will then
859 * be provided.
860 * cb_arg - 2nd argument to callback function.
861 *
862 *
863 * return values:
864 * USB_SUCCESS - alternate was set
865 * USB_FAILURE - alternate could not be set because pipes
866 * were still open or some access error occurred
867 * USB_* - refer to usbai.h
868 *
869 * Note:
870 * we can't easily check if all pipes to endpoints for this interface
871 * are closed since we don't have a map of which endpoints belong
872 * to which interface. If we had this map, we would need to update
873 * this on each alternative or configuration switch
874 */
875 int
usb_set_alt_if(dev_info_t * dip,uint_t interface,uint_t alt_number,usb_flags_t usb_flags,void (* cb)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t cb_arg)876 usb_set_alt_if(dev_info_t *dip,
877 uint_t interface,
878 uint_t alt_number,
879 usb_flags_t usb_flags,
880 void (*cb)(
881 usb_pipe_handle_t ph,
882 usb_opaque_t arg,
883 int rval,
884 usb_cb_flags_t flags),
885 usb_opaque_t cb_arg)
886 {
887 usb_pipe_handle_t ph;
888
889 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
890 "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
891 ddi_driver_name(dip), ddi_get_instance(dip),
892 interface, alt_number, usb_flags);
893
894 if (dip == NULL) {
895
896 return (USB_INVALID_ARGS);
897 }
898
899 if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
900
901 return (USB_INVALID_CONTEXT);
902 }
903
904 ph = usba_get_dflt_pipe_handle(dip);
905 if (usba_hold_ph_data(ph) == NULL) {
906
907 return (USB_INVALID_PIPE);
908 }
909
910 return (usba_pipe_setup_func_call(dip,
911 usba_sync_set_alt_if, (usba_ph_impl_t *)ph,
912 (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)),
913 usb_flags, cb, cb_arg));
914 }
915
916
917 static int
usba_sync_set_alt_if(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t flags)918 usba_sync_set_alt_if(dev_info_t *dip,
919 usba_ph_impl_t *ph_impl,
920 usba_pipe_async_req_t *request,
921 usb_flags_t flags)
922 {
923 int rval;
924 usb_cr_t completion_reason;
925 usb_cb_flags_t cb_flags;
926 usb_opaque_t arg = request->arg;
927 int interface = ((uintptr_t)arg >> 8) & 0xff;
928 int alt_number = (uintptr_t)arg & 0xff;
929 usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
930 (usb_pipe_handle_t)ph_impl);
931
932 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
933 "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
934 "uf=0x%x", ddi_node_name(dip), interface,
935 alt_number, flags);
936
937 /* if we don't own the device, we must own the interface or ia */
938 if (!usb_owns_device(dip) && !usba_check_if_in_ia(dip, interface) &&
939 (interface != usb_get_if_number(dip))) {
940 usba_release_ph_data(ph_data->p_ph_impl);
941
942 return (USB_INVALID_PERM);
943 }
944
945 /* set the alternate setting */
946 rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip),
947 USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
948 USB_REQ_SET_IF,
949 alt_number,
950 interface,
951 0,
952 NULL, 0,
953 &completion_reason,
954 &cb_flags, flags | USB_FLAGS_SLEEP);
955
956 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
957 "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
958
959 usba_release_ph_data(ph_data->p_ph_impl);
960
961 return (rval);
962 }
963
964
965 /*
966 * usb_get_alt_if:
967 * get the alternate interface number. Issues USB_REQ_GET_IF
968 * This function will access the device and block
969 *
970 * Arguments:
971 * dip - pointer to devinfo of the client
972 * if_number - interface number
973 * alt_number - alternate interface number
974 * flags - none but USB_FLAGS_SLEEP may be passed
975 *
976 * return values:
977 * USB_SUCCESS: alternate was set
978 * USB_FAILURE: alternate could not be set because pipes
979 * were still open or some access error occurred
980 */
981 int
usb_get_alt_if(dev_info_t * dip,uint_t if_number,uint_t * alt_number,usb_flags_t flags)982 usb_get_alt_if(dev_info_t *dip,
983 uint_t if_number,
984 uint_t *alt_number,
985 usb_flags_t flags)
986 {
987 int rval;
988 usb_cr_t completion_reason;
989 mblk_t *data = NULL;
990 usb_cb_flags_t cb_flags;
991 usb_pipe_handle_t ph;
992
993 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
994 "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
995 "uf = 0x%x", ddi_node_name(dip), if_number,
996 (void *)alt_number, flags);
997
998 if ((alt_number == NULL) || (dip == NULL)) {
999
1000 return (USB_INVALID_ARGS);
1001 }
1002
1003 ph = usba_get_dflt_pipe_handle(dip);
1004
1005 /*
1006 * get the alternate setting
1007 */
1008 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1009 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF,
1010 USB_REQ_GET_IF,
1011 0,
1012 if_number,
1013 1, /* returns one byte of data */
1014 &data, 0,
1015 &completion_reason,
1016 &cb_flags, flags);
1017
1018 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1019 "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
1020
1021 if ((rval == USB_SUCCESS) && data &&
1022 (MBLKL(data) == 1)) {
1023 *alt_number = *(data->b_rptr);
1024 } else {
1025 *alt_number = 0;
1026 if (rval == USB_SUCCESS) {
1027 rval = USB_FAILURE;
1028 }
1029 }
1030
1031 freemsg(data);
1032
1033 return (rval);
1034 }
1035
1036
1037 /*
1038 * usba_get_cfg_cloud:
1039 * Get descriptor cloud for a given configuration.
1040 *
1041 * Arguments:
1042 * dip - pointer to devinfo of the client
1043 * default_ph - default pipe handle
1044 * cfg - which configuration to retrieve raw cloud of
1045 *
1046 * Returns:
1047 * on success: mblock containing the raw data. Caller must free.
1048 * on failure: NULL
1049 */
1050 static mblk_t *
usba_get_cfg_cloud(dev_info_t * dip,usb_pipe_handle_t default_ph,int cfg)1051 usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg)
1052 {
1053 usb_cr_t completion_reason;
1054 usb_cb_flags_t cb_flags;
1055 usb_cfg_descr_t cfg_descr;
1056 mblk_t *pdata = NULL;
1057
1058 if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
1059 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1060 USB_REQ_GET_DESCR,
1061 USB_DESCR_TYPE_SETUP_CFG | cfg,
1062 0,
1063 USB_CFG_DESCR_SIZE,
1064 &pdata,
1065 0,
1066 &completion_reason,
1067 &cb_flags,
1068 0) != USB_SUCCESS) {
1069
1070 freemsg(pdata);
1071
1072 return (NULL);
1073 }
1074
1075 (void) usb_parse_cfg_descr(pdata->b_rptr,
1076 MBLKL(pdata), &cfg_descr, USB_CFG_DESCR_SIZE);
1077 freemsg(pdata);
1078 pdata = NULL;
1079
1080 if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
1081 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1082 USB_REQ_GET_DESCR,
1083 USB_DESCR_TYPE_SETUP_CFG | cfg,
1084 0,
1085 cfg_descr.wTotalLength,
1086 &pdata,
1087 0,
1088 &completion_reason,
1089 &cb_flags,
1090 0) != USB_SUCCESS) {
1091
1092 freemsg(pdata);
1093
1094 return (NULL);
1095 }
1096
1097 return (pdata);
1098 }
1099
1100 /*
1101 * usb_check_same_device:
1102 * Check if the device connected to the port is the same as
1103 * the previous device that was in the port. The previous device is
1104 * represented by the dip on record for the port. Print a message
1105 * if the device is different. If device_string arg is not NULL, it is
1106 * included in the message. Can block.
1107 *
1108 * Arguments:
1109 * dip - pointer to devinfo of the client
1110 * log_handle - handle to which messages are logged
1111 * log_level - one of USB_LOG_*
1112 * log_mask - logging mask
1113 * check_mask - one mask containing things to check:
1114 * USB_CHK_BASIC: empty mask;
1115 * these checks are always done.
1116 * USB_CHK_VIDPID:
1117 * check vid, pid only.
1118 * USB_CHK_SERIAL: check match on device
1119 * serial number.
1120 * USB_CHK_CFG: check all raw config
1121 * clouds for a match.
1122 * NOTE: descr length and content always checked
1123 * device_string - Device string to appear in error message
1124 *
1125 * return values:
1126 * USB_SUCCESS: same device
1127 * USB_INVALID_VERSION not same device
1128 * USB_FAILURE: Failure processing request
1129 * USB_INVALID_ARG: dip is invalid
1130 */
1131 int
usb_check_same_device(dev_info_t * dip,usb_log_handle_t log_handle,int log_level,int log_mask,uint_t check_mask,char * device_string)1132 usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle,
1133 int log_level, int log_mask, uint_t check_mask, char *device_string)
1134 {
1135 usb_dev_descr_t usb_dev_descr;
1136 usba_device_t *usba_device;
1137 mblk_t *pdata = NULL;
1138 uint16_t length;
1139 int rval;
1140 char *buf;
1141 usb_cr_t completion_reason;
1142 usb_cb_flags_t cb_flags;
1143 boolean_t match = B_TRUE;
1144 usb_pipe_handle_t def_ph;
1145
1146 if (dip == NULL) {
1147
1148 return (USB_INVALID_ARGS);
1149 }
1150
1151 usba_device = usba_get_usba_device(dip);
1152 length = usba_device->usb_dev_descr->bLength;
1153 def_ph = usba_get_dflt_pipe_handle(dip);
1154 ASSERT(def_ph);
1155
1156 /* get the "new" device descriptor */
1157 rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
1158 USB_DEV_REQ_DEV_TO_HOST |
1159 USB_DEV_REQ_TYPE_STANDARD,
1160 USB_REQ_GET_DESCR, /* bRequest */
1161 USB_DESCR_TYPE_SETUP_DEV, /* wValue */
1162 0, /* wIndex */
1163 length, /* wLength */
1164 &pdata, 0,
1165 &completion_reason,
1166 &cb_flags, USB_FLAGS_SLEEP);
1167
1168 if (rval != USB_SUCCESS) {
1169 if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) {
1170 USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle,
1171 "getting device descriptor failed (%d)", rval);
1172 freemsg(pdata);
1173
1174 return (USB_FAILURE);
1175 }
1176 }
1177
1178 ASSERT(pdata != NULL);
1179
1180 (void) usb_parse_dev_descr(pdata->b_rptr,
1181 MBLKL(pdata), &usb_dev_descr,
1182 sizeof (usb_dev_descr_t));
1183
1184 freemsg(pdata);
1185 pdata = NULL;
1186
1187 /* Always check the device descriptor length. */
1188 if (usb_dev_descr.bLength != length) {
1189 match = B_FALSE;
1190 }
1191
1192 if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) {
1193 match = (usba_device->usb_dev_descr->idVendor ==
1194 usb_dev_descr.idVendor) &&
1195 (usba_device->usb_dev_descr->idProduct ==
1196 usb_dev_descr.idProduct);
1197 } else if (bcmp((char *)usba_device->usb_dev_descr,
1198 (char *)&usb_dev_descr, length) != 0) {
1199 match = B_FALSE;
1200 }
1201
1202 /* if requested & this device has a serial number check and compare */
1203 if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) &&
1204 (usba_device->usb_serialno_str != NULL)) {
1205 buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
1206 if (usb_get_string_descr(dip, USB_LANG_ID,
1207 usb_dev_descr.iSerialNumber, buf,
1208 USB_MAXSTRINGLEN) == USB_SUCCESS) {
1209 match =
1210 (strcmp(buf, usba_device->usb_serialno_str) == 0);
1211 }
1212 kmem_free(buf, USB_MAXSTRINGLEN);
1213 }
1214
1215 if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) {
1216
1217 uint8_t num_cfgs = usb_dev_descr.bNumConfigurations;
1218 uint8_t cfg;
1219 mblk_t *cloud;
1220
1221 for (cfg = 0; cfg < num_cfgs; cfg++) {
1222 cloud = usba_get_cfg_cloud(dip, def_ph, cfg);
1223 if (cloud == NULL) {
1224 USB_DPRINTF_L3(DPRINT_MASK_USBA,
1225 usbai_log_handle,
1226 "Could not retrieve config cloud for "
1227 "comparison");
1228 break;
1229 }
1230
1231 if (bcmp((char *)cloud->b_rptr,
1232 usba_device->usb_cfg_array[cfg],
1233 MBLKL(cloud)) != 0) {
1234 freemsg(cloud);
1235 break;
1236 }
1237
1238 freemsg(cloud);
1239 }
1240 if (cfg != num_cfgs) {
1241 match = B_FALSE;
1242 }
1243 }
1244
1245 if (match == B_FALSE) {
1246 boolean_t allocated_here = (device_string == NULL);
1247 if (allocated_here) {
1248 device_string =
1249 kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP);
1250 (void) usba_get_mfg_prod_sn_str(dip, device_string,
1251 USB_MAXSTRINGLEN);
1252 }
1253 if (device_string[0] != '\0') {
1254 (void) usb_log(log_handle, log_level, log_mask,
1255 "Cannot access %s. Please reconnect.",
1256 device_string);
1257 } else {
1258 (void) usb_log(log_handle, log_level, log_mask,
1259 "Device is not identical to the "
1260 "previous one this port.\n"
1261 "Please disconnect and reconnect");
1262 }
1263 if (allocated_here) {
1264 kmem_free(device_string, USB_MAXSTRINGLEN);
1265 }
1266
1267 return (USB_INVALID_VERSION);
1268 }
1269
1270 return (USB_SUCCESS);
1271 }
1272
1273
1274 /*
1275 * usb_pipe_get_state:
1276 * Return the state of the pipe
1277 *
1278 * Arguments:
1279 * pipe_handle - pipe_handle pointer
1280 * pipe_state - pointer to copy pipe state to
1281 * flags:
1282 * not used other than to check context
1283 *
1284 * Return Values:
1285 * USB_SUCCESS - port state returned
1286 * USB_* - refer to usbai.h
1287 */
1288 int
usb_pipe_get_state(usb_pipe_handle_t pipe_handle,usb_pipe_state_t * pipe_state,usb_flags_t usb_flags)1289 usb_pipe_get_state(usb_pipe_handle_t pipe_handle,
1290 usb_pipe_state_t *pipe_state,
1291 usb_flags_t usb_flags)
1292 {
1293 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1294
1295 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1296 "usb_pipe_get_state: ph_data=0x%p uf=0x%x", (void *)ph_data,
1297 usb_flags);
1298
1299 if (pipe_state == NULL) {
1300 if (ph_data) {
1301 usba_release_ph_data(ph_data->p_ph_impl);
1302 }
1303
1304 return (USB_INVALID_ARGS);
1305 }
1306
1307 if (ph_data == NULL) {
1308 *pipe_state = USB_PIPE_STATE_CLOSED;
1309
1310 return (USB_SUCCESS);
1311 }
1312
1313 mutex_enter(&ph_data->p_mutex);
1314 *pipe_state = usba_get_ph_state(ph_data);
1315 mutex_exit(&ph_data->p_mutex);
1316
1317 usba_release_ph_data(ph_data->p_ph_impl);
1318
1319 return (USB_SUCCESS);
1320 }
1321
1322
1323 /*
1324 * usba_pipe_get_policy:
1325 * Return a pipe's policy
1326 *
1327 * Arguments:
1328 * pipe_handle - pipe_handle pointer
1329 *
1330 * Return Values:
1331 * On success: the pipe's policy
1332 * On failure: NULL
1333 */
1334 usb_pipe_policy_t
usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)1335 *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)
1336 {
1337 usb_pipe_policy_t *pp = NULL;
1338
1339 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1340
1341 if (ph_data) {
1342 pp = &ph_data->p_policy;
1343
1344 usba_release_ph_data(ph_data->p_ph_impl);
1345 }
1346
1347 return (pp);
1348 }
1349
1350
1351 /*
1352 * usb_ep_num:
1353 * Return the endpoint number for a given pipe handle
1354 *
1355 * Arguments:
1356 * pipe_handle - pipe_handle pointer
1357 *
1358 * Return Values:
1359 * endpoint number
1360 */
1361 int
usb_ep_num(usb_pipe_handle_t pipe_handle)1362 usb_ep_num(usb_pipe_handle_t pipe_handle)
1363 {
1364 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1365 int ep_num;
1366
1367 if (ph_data == NULL) {
1368
1369 return (USB_INVALID_PIPE);
1370 }
1371
1372 mutex_enter(&ph_data->p_mutex);
1373 ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK;
1374 mutex_exit(&ph_data->p_mutex);
1375
1376 usba_release_ph_data(ph_data->p_ph_impl);
1377
1378 return (ep_num);
1379 }
1380
1381
1382 /*
1383 * usb_get_status
1384 * Issues USB_REQ_GET_STATUS to device/endpoint/interface
1385 * and report in "status" arg.
1386 *
1387 * status reported for a "device" is
1388 * RemoteWakeup enabled
1389 * SelfPowered device?
1390 *
1391 * status reported for an "interface" is NONE.
1392 * status reported for an "endpoint" is
1393 * HALT set (device STALLED?)
1394 *
1395 * Arguments:
1396 * dip - pointer to devinfo of the client
1397 * ph - pipe handle
1398 * type - bmRequestType to be used
1399 * what - 0 for device, otherwise interface or ep number
1400 * status - user supplied pointer for storing the status
1401 * flags - USB_FLAGS_SLEEP (mandatory)
1402 *
1403 * Return Values:
1404 * valid usb_status_t or USB_FAILURE
1405 */
1406 int
usb_get_status(dev_info_t * dip,usb_pipe_handle_t ph,uint_t type,uint_t what,uint16_t * status,usb_flags_t flags)1407 usb_get_status(dev_info_t *dip,
1408 usb_pipe_handle_t ph,
1409 uint_t type, /* bmRequestType */
1410 uint_t what, /* 0, interface, ept number */
1411 uint16_t *status,
1412 usb_flags_t flags)
1413 {
1414 int rval;
1415 usb_cr_t completion_reason;
1416 mblk_t *data = NULL;
1417 usb_cb_flags_t cb_flags;
1418
1419 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1420 "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x",
1421 type, what, flags);
1422
1423 if ((status == NULL) || (dip == NULL)) {
1424
1425 return (USB_INVALID_ARGS);
1426 }
1427 if (ph == NULL) {
1428
1429 return (USB_INVALID_PIPE);
1430 }
1431
1432 type |= USB_DEV_REQ_DEV_TO_HOST;
1433
1434 /* get the status */
1435 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1436 type,
1437 USB_REQ_GET_STATUS,
1438 0,
1439 what,
1440 USB_GET_STATUS_LEN, /* status is fixed 2 bytes long */
1441 &data, 0,
1442 &completion_reason, &cb_flags, flags);
1443
1444 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1445 "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1446
1447 if ((rval == USB_SUCCESS) && data &&
1448 (MBLKL(data) == USB_GET_STATUS_LEN)) {
1449 *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
1450 } else {
1451 *status = 0;
1452 if (rval == USB_SUCCESS) {
1453 rval = USB_FAILURE;
1454 }
1455 }
1456
1457 freemsg(data);
1458
1459 return (rval);
1460 }
1461
1462
1463 /*
1464 * usb_clear_feature:
1465 * Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1466 *
1467 * Arguments:
1468 * dip - pointer to devinfo of the client
1469 * ph - pipe handle pointer
1470 * type - bmRequestType to be used
1471 * feature - feature to be cleared
1472 * what - 0 for device, otherwise interface or ep number
1473 * flags - none (but will sleep)
1474 *
1475 * Return Values:
1476 * USB_SUCCESS - on doing a successful clear feature
1477 * USB_FAILURE - on failure
1478 * USB_* - refer to usbai.h
1479 */
1480 int
usb_clear_feature(dev_info_t * dip,usb_pipe_handle_t ph,uint_t type,uint_t feature,uint_t what,usb_flags_t flags)1481 usb_clear_feature(dev_info_t *dip,
1482 usb_pipe_handle_t ph,
1483 uint_t type, /* bmRequestType */
1484 uint_t feature,
1485 uint_t what, /* 0, interface, ept number */
1486 usb_flags_t flags)
1487 {
1488 int rval;
1489 usb_cr_t completion_reason;
1490 usb_cb_flags_t cb_flags;
1491
1492 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1493 "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1494 "uf = 0x%x", type, feature, what, flags);
1495
1496 if (dip == NULL) {
1497
1498 return (USB_INVALID_ARGS);
1499 }
1500 if (ph == NULL) {
1501
1502 return (USB_INVALID_PIPE);
1503 }
1504
1505 /* issue Clear feature */
1506 rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1507 type,
1508 USB_REQ_CLEAR_FEATURE,
1509 feature,
1510 what,
1511 0,
1512 NULL, 0,
1513 &completion_reason,
1514 &cb_flags, flags | USB_FLAGS_SLEEP);
1515
1516 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1517 "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1518
1519 return (rval);
1520 }
1521
1522
1523 /*
1524 * usb_clr_feature:
1525 * Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1526 *
1527 * Arguments:
1528 * dip - pointer to devinfo of the client
1529 * type - bmRequestType to be used
1530 * feature - feature to be cleared
1531 * what - 0 for device, otherwise interface or ep number
1532 * flags - USB_FLAGS_SLEEP:
1533 * wait for completion
1534 * cb - if USB_FLAGS_SLEEP has not been specified
1535 * this callback function will be called on
1536 * completion. This callback may be NULL
1537 * and no notification of completion will then
1538 * be provided.
1539 * cb_arg - 2nd argument to callback function.
1540 *
1541 *
1542 * Return Values:
1543 * USB_SUCCESS - on doing a successful clear feature
1544 * USB_FAILURE - on failure
1545 * USB_* - refer to usbai.h
1546 */
1547 int
usb_clr_feature(dev_info_t * dip,uint_t type,uint_t feature,uint_t what,usb_flags_t flags,void (* cb)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t cb_arg)1548 usb_clr_feature(
1549 dev_info_t *dip,
1550 uint_t type, /* bmRequestType */
1551 uint_t feature,
1552 uint_t what, /* 0, interface, ept number */
1553 usb_flags_t flags,
1554 void (*cb)(
1555 usb_pipe_handle_t ph,
1556 usb_opaque_t arg,
1557 int rval,
1558 usb_cb_flags_t flags),
1559 usb_opaque_t cb_arg)
1560 {
1561 usb_pipe_handle_t ph;
1562
1563 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1564 "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1565 "uf = 0x%x", type, feature, what, flags);
1566
1567 if (dip == NULL) {
1568
1569 return (USB_INVALID_ARGS);
1570 }
1571
1572 if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
1573
1574 return (USB_INVALID_CONTEXT);
1575 }
1576
1577 ph = usba_get_dflt_pipe_handle(dip);
1578 if (usba_hold_ph_data(ph) == NULL) {
1579
1580 return (USB_INVALID_PIPE);
1581 }
1582
1583 return (usba_pipe_setup_func_call(dip,
1584 usba_sync_clear_feature, (usba_ph_impl_t *)ph,
1585 (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))),
1586 flags, cb, cb_arg));
1587 }
1588
1589
1590 static int
usba_sync_clear_feature(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * req,usb_flags_t usb_flags)1591 usba_sync_clear_feature(dev_info_t *dip,
1592 usba_ph_impl_t *ph_impl,
1593 usba_pipe_async_req_t *req,
1594 usb_flags_t usb_flags)
1595 {
1596 uint_t n = (uint_t)((uintptr_t)(req->arg));
1597 uint_t type = ((uint_t)n >> 16) & 0xff;
1598 uint_t feature = ((uint_t)n >> 8) & 0xff;
1599 uint_t what = (uint_t)n & 0xff;
1600 int rval;
1601 usba_device_t *usba_device;
1602 usba_pipe_handle_data_t *ph_data;
1603 usba_ph_impl_t *ph_im;
1604 uchar_t ep_index;
1605 usb_ep_descr_t *eptd;
1606
1607
1608 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1609 "usb_sync_clear_feature: "
1610 "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
1611 (void *)dip, (void *)ph_impl, type, feature, what, usb_flags);
1612
1613 rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type,
1614 feature, what, usb_flags);
1615
1616 /*
1617 * Reset data toggle to DATA0 for bulk and interrupt endpoint.
1618 * Data toggle synchronization is not supported for isochronous
1619 * transfer.Halt feature is not supported by control endpoint.
1620 *
1621 * From USB2.0 specification:
1622 * 1.Section 5.8.5 Bulk Transfer Data Sequences
1623 * Removal of the halt condition is achieved via software intervention
1624 * through a separate control pipe. This recovery will reset the data
1625 * toggle bit to DATA0 for the endpoint on both the host and the device.
1626 *
1627 * 2.Section 5.7.5 Interrupt Transfer Data Sequences
1628 * Removal of the halt condition is achieved via software intervention
1629 * through a separate control pipe. This recovery will reset the data
1630 * toggle bit to DATA0 for the endpoint on both the host and the device.
1631 *
1632 * 3.Section 9.4.5
1633 * If the condition causing a halt has been removed, clearing the Halt
1634 * feature via a ClearFeature(ENDPOINT_HALT) request results in the
1635 * endpoint no longer returning a STALL. For endpoints using data
1636 * toggle, regardless of whether an endpoint has the Halt feature set, a
1637 * ClearFeature(ENDPOINT_HALT) request always results in the data toggle
1638 * being reinitialized to DATA0.
1639 *
1640 */
1641 if (rval == USB_SUCCESS && feature == 0) {
1642 usba_device = usba_get_usba_device(dip);
1643 ep_index = usb_get_ep_index((uint8_t)what);
1644 ph_im = &usba_device->usb_ph_list[ep_index];
1645 ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_im);
1646 eptd = &ph_data->p_ep;
1647 if ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
1648 USB_EP_ATTR_BULK || (eptd->bmAttributes &
1649 USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR)
1650 usba_device->usb_hcdi_ops->
1651 usba_hcdi_pipe_reset_data_toggle(ph_data);
1652 }
1653
1654 usba_release_ph_data(ph_impl);
1655
1656 return (rval);
1657 }
1658
1659
1660 /*
1661 * usb_async_req:
1662 * function used to dispatch a request to the taskq
1663 *
1664 * Arguments:
1665 * dip - pointer to devinfo node
1666 * func - pointer to function issued by taskq
1667 * flag - USB_FLAGS_SLEEP mostly
1668 *
1669 * Return Values:
1670 * USB_SUCCESS - on doing a successful taskq invocation
1671 * USB_FAILURE - on failure
1672 * USB_* - refer to usbai.h
1673 */
1674 int
usb_async_req(dev_info_t * dip,void (* func)(void *),void * arg,usb_flags_t flag)1675 usb_async_req(dev_info_t *dip,
1676 void (*func)(void *),
1677 void *arg,
1678 usb_flags_t flag)
1679 {
1680 int tq_flag;
1681
1682 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1683 "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
1684 (void *)dip, (void *)func, arg, flag);
1685
1686 if ((dip == NULL) || (func == NULL)) {
1687
1688 return (USB_INVALID_ARGS);
1689 }
1690 tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1691 if (flag & USB_FLAGS_NOQUEUE) {
1692 tq_flag |= TQ_NOQUEUE;
1693 }
1694
1695 if (taskq_dispatch(system_taskq, func, arg,
1696 tq_flag) == TASKQID_INVALID) {
1697 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1698 "usb_async_req: failure");
1699
1700 return (USB_FAILURE);
1701 }
1702
1703 return (USB_SUCCESS);
1704 }
1705
1706 /*
1707 * usba_async_ph_req:
1708 * function used to dispatch a request to the ph taskq
1709 *
1710 * Arguments:
1711 * ph_data - pointer to pipe handle data
1712 * func - pointer to function issued by taskq
1713 * flag - USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
1714 *
1715 * Return Values:
1716 * USB_SUCCESS - on doing a successful taskq invocation
1717 * USB_FAILURE - on failure
1718 * USB_* - refer to usbai.h
1719 *
1720 * Note:
1721 * If the caller specified USB_FLAGS_NOSLEEP, it must be
1722 * capable of reliably recovering from a failure return
1723 */
1724 int
usba_async_ph_req(usba_pipe_handle_data_t * ph_data,void (* func)(void *),void * arg,usb_flags_t flag)1725 usba_async_ph_req(usba_pipe_handle_data_t *ph_data,
1726 void (*func)(void *),
1727 void *arg,
1728 usb_flags_t flag)
1729 {
1730 int tq_flag;
1731 taskq_t *taskq;
1732
1733 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1734 "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
1735 (void *)ph_data, (void *)func, arg, flag);
1736
1737 if (func == NULL) {
1738
1739 return (USB_INVALID_ARGS);
1740 }
1741
1742 tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1743
1744 if (ph_data && ph_data->p_taskq) {
1745 taskq = ph_data->p_taskq;
1746 } else {
1747 taskq = system_taskq;
1748 tq_flag |= TQ_NOQUEUE;
1749 }
1750
1751 if (taskq_dispatch(taskq, func, arg, tq_flag) == TASKQID_INVALID) {
1752 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1753 "usba_async_ph_req: failure");
1754
1755 return (USB_FAILURE);
1756 }
1757
1758 return (USB_SUCCESS);
1759 }
1760
1761
1762 /*
1763 * utility functions to display CR, CB, return values
1764 */
1765 typedef struct conv_table {
1766 int what;
1767 const char *name;
1768 } conv_table_t;
1769
1770 static const char *
usba_get_name(conv_table_t * conv_table,int value)1771 usba_get_name(conv_table_t *conv_table, int value)
1772 {
1773 int i;
1774 for (i = 0; conv_table[i].name != NULL; i++) {
1775 if (conv_table[i].what == value) {
1776
1777 return (conv_table[i].name);
1778 }
1779 }
1780
1781 return ("unknown");
1782 }
1783
1784
1785 static conv_table_t cr_table[] = {
1786 { USB_CR_OK, "<no errors detected>" },
1787 { USB_CR_CRC, "<crc error detected>" },
1788 { USB_CR_BITSTUFFING, "<Bit stuffing violation>" },
1789 { USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
1790 { USB_CR_STALL, "<Endpoint returned stall PID>" },
1791 { USB_CR_DEV_NOT_RESP, "<Device not responding>" },
1792 { USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
1793 { USB_CR_UNEXP_PID, "<Receive PID was not valid>" },
1794 { USB_CR_DATA_OVERRUN, "<Data size exceeded>" },
1795 { USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
1796 { USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
1797 { USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
1798 { USB_CR_TIMEOUT, "<Command timed out>" },
1799 { USB_CR_NOT_ACCESSED, "<Not accessed by hardware>" },
1800 { USB_CR_NO_RESOURCES, "<No resources>" },
1801 { USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
1802 { USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
1803 { USB_CR_PIPE_CLOSING, "<Intr/ISOC IN pipe being closed>" },
1804 { USB_CR_PIPE_RESET, "<Intr/ISOC IN pipe reset>" },
1805 { USB_CR_NOT_SUPPORTED, "<Command not supported>" },
1806 { USB_CR_FLUSHED, "<Req was flushed>" },
1807 { USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
1808 { 0, NULL }
1809 };
1810
1811 const char *
usb_str_cr(usb_cr_t cr)1812 usb_str_cr(usb_cr_t cr)
1813 {
1814 return (usba_get_name(cr_table, cr));
1815 }
1816
1817
1818 static conv_table_t cb_flags_table[] = {
1819 { USB_CB_NO_INFO, "<callback processed>" },
1820 { USB_CB_STALL_CLEARED, "<stall cleared>" },
1821 { USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
1822 { USB_CB_PROTOCOL_STALL, "<protocol stall>" },
1823 { USB_CB_RESET_PIPE, "<pipe reset>" },
1824 { USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
1825 { USB_CB_NO_RESOURCES, "<no resources>" },
1826 { USB_CB_SUBMIT_FAILED, "<submit failed>" },
1827 { USB_CB_INTR_CONTEXT, "<Callback executing in interrupt context>" },
1828 { 0, NULL }
1829 };
1830
1831 /*ARGSUSED*/
1832 char *
usb_str_cb_flags(usb_cb_flags_t cb_flags,char * buffer,size_t length)1833 usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length)
1834 {
1835 int i;
1836 buffer[0] = '\0';
1837 if (cb_flags == USB_CB_NO_INFO) {
1838 (void) strncpy(buffer, cb_flags_table[0].name, length);
1839 } else {
1840 for (i = 0; cb_flags_table[i].name != NULL; i++) {
1841 if (cb_flags & cb_flags_table[i].what) {
1842 (void) strncpy(&buffer[strlen(buffer)],
1843 cb_flags_table[0].name,
1844 length - strlen(buffer) - 1);
1845 }
1846 }
1847 }
1848
1849 return (buffer);
1850 }
1851
1852
1853 static conv_table_t pipe_state_table[] = {
1854 { USB_PIPE_STATE_CLOSED, "<closed>" },
1855 { USB_PIPE_STATE_IDLE, "<idle>" },
1856 { USB_PIPE_STATE_ACTIVE, "<active>" },
1857 { USB_PIPE_STATE_ERROR, "<error>" },
1858 { USB_PIPE_STATE_CLOSING, "<closing>" },
1859 { 0, NULL }
1860 };
1861
1862 const char *
usb_str_pipe_state(usb_pipe_state_t state)1863 usb_str_pipe_state(usb_pipe_state_t state)
1864 {
1865 return (usba_get_name(pipe_state_table, state));
1866 }
1867
1868
1869 static conv_table_t dev_state[] = {
1870 { USB_DEV_ONLINE, "<online>" },
1871 { USB_DEV_DISCONNECTED, "<disconnected>" },
1872 { USB_DEV_SUSPENDED, "<suspended>" },
1873 { USB_DEV_PWRED_DOWN, "<powered down>" },
1874 { 0, NULL }
1875 };
1876
1877 const char *
usb_str_dev_state(int state)1878 usb_str_dev_state(int state)
1879 {
1880 return (usba_get_name(dev_state, state));
1881 }
1882
1883
1884 static conv_table_t rval_table[] = {
1885 { USB_SUCCESS, "<success>" },
1886 { USB_FAILURE, "<failure>" },
1887 { USB_NO_RESOURCES, "<no resources>" },
1888 { USB_NO_BANDWIDTH, "<no bandwidth>" },
1889 { USB_NOT_SUPPORTED, "<not supported>" },
1890 { USB_PIPE_ERROR, "<pipe error>" },
1891 { USB_INVALID_PIPE, "<invalid pipe>" },
1892 { USB_NO_FRAME_NUMBER, "<no frame number>" },
1893 { USB_INVALID_START_FRAME, "<invalid frame>" },
1894 { USB_HC_HARDWARE_ERROR, "<hw error>" },
1895 { USB_INVALID_REQUEST, "<invalid request>" },
1896 { USB_INVALID_CONTEXT, "<invalid context>" },
1897 { USB_INVALID_VERSION, "<invalid version>" },
1898 { USB_INVALID_ARGS, "<invalid args>" },
1899 { USB_INVALID_PERM, "<invalid perms>" },
1900 { USB_BUSY, "<busy>" },
1901 { 0, NULL }
1902 };
1903
1904 const char *
usb_str_rval(int rval)1905 usb_str_rval(int rval)
1906 {
1907 return (usba_get_name(rval_table, rval));
1908 }
1909
1910
1911 /*
1912 * function to convert USB return values to close errno
1913 */
1914 static struct usb_rval2errno_entry {
1915 int rval;
1916 int Errno;
1917 } usb_rval2errno_table[] = {
1918 { USB_SUCCESS, 0 },
1919 { USB_FAILURE, EIO },
1920 { USB_NO_RESOURCES, ENOMEM },
1921 { USB_NO_BANDWIDTH, EAGAIN },
1922 { USB_NOT_SUPPORTED, ENOTSUP },
1923 { USB_PIPE_ERROR, EIO },
1924 { USB_INVALID_PIPE, EINVAL },
1925 { USB_NO_FRAME_NUMBER, EINVAL },
1926 { USB_INVALID_START_FRAME, EINVAL },
1927 { USB_HC_HARDWARE_ERROR, EIO },
1928 { USB_INVALID_REQUEST, EINVAL },
1929 { USB_INVALID_CONTEXT, EINVAL },
1930 { USB_INVALID_VERSION, EINVAL },
1931 { USB_INVALID_ARGS, EINVAL },
1932 { USB_INVALID_PERM, EACCES },
1933 { USB_BUSY, EBUSY },
1934 };
1935
1936 #define USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
1937 sizeof (struct usb_rval2errno_entry))
1938 int
usb_rval2errno(int rval)1939 usb_rval2errno(int rval)
1940 {
1941 int i;
1942
1943 for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
1944 if (usb_rval2errno_table[i].rval == rval) {
1945
1946 return (usb_rval2errno_table[i].Errno);
1947 }
1948 }
1949
1950 return (EIO);
1951 }
1952
1953
1954 /*
1955 * serialization
1956 */
1957 usb_serialization_t
usb_init_serialization(dev_info_t * dip,uint_t flag)1958 usb_init_serialization(
1959 dev_info_t *dip,
1960 uint_t flag)
1961 {
1962 usba_serialization_impl_t *impl_tokenp = kmem_zalloc(
1963 sizeof (usba_serialization_impl_t), KM_SLEEP);
1964 usba_device_t *usba_device;
1965 ddi_iblock_cookie_t cookie = NULL;
1966
1967 if (dip) {
1968 usba_device = usba_get_usba_device(dip);
1969 cookie = usba_hcdi_get_hcdi(
1970 usba_device->usb_root_hub_dip)->hcdi_iblock_cookie;
1971 }
1972 impl_tokenp->s_dip = dip;
1973 impl_tokenp->s_flag = flag;
1974 mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie);
1975 cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL);
1976
1977 return ((usb_serialization_t)impl_tokenp);
1978 }
1979
1980
1981 void
usb_fini_serialization(usb_serialization_t tokenp)1982 usb_fini_serialization(
1983 usb_serialization_t tokenp)
1984 {
1985 usba_serialization_impl_t *impl_tokenp;
1986
1987 if (tokenp) {
1988 impl_tokenp = (usba_serialization_impl_t *)tokenp;
1989 ASSERT(impl_tokenp->s_count == 0);
1990 cv_destroy(&impl_tokenp->s_cv);
1991 mutex_destroy(&impl_tokenp->s_mutex);
1992 kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t));
1993 }
1994 }
1995
1996
1997 /*
1998 * usb_serialize_access() permits single threaded access.
1999 *
2000 * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
2001 * it is reentrant with respect to thread. The thread must
2002 * hold and release the same number of times.
2003 *
2004 * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
2005 * it is not reentrant by the same thread. It is something like
2006 * a semaphore.
2007 */
2008 int
usb_serialize_access(usb_serialization_t tokenp,uint_t how_to_wait,uint_t delta_timeout)2009 usb_serialize_access(
2010 usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout)
2011 {
2012 int rval = 1; /* Must be initialized > 0 */
2013 clock_t abs_timeout = 0;
2014 usba_serialization_impl_t *impl_tokenp;
2015
2016 impl_tokenp = (usba_serialization_impl_t *)tokenp;
2017
2018 /*
2019 * Convert delta timeout in ms to absolute timeout in ticks, if used.
2020 */
2021 if ((how_to_wait == USB_TIMEDWAIT) ||
2022 (how_to_wait == USB_TIMEDWAIT_SIG)) {
2023 /* Convert timeout arg (in ms) to hz */
2024 abs_timeout = ddi_get_lbolt() +
2025 drv_usectohz(delta_timeout * 1000);
2026 }
2027
2028 /* Get mutex after calc abs time, to count time waiting for mutex. */
2029 mutex_enter(&impl_tokenp->s_mutex);
2030
2031 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2032 "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
2033 "flg=0x%x, abs_tmo=0x%lx",
2034 (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2035 impl_tokenp->s_count, (void *)impl_tokenp->s_thread,
2036 how_to_wait, abs_timeout);
2037
2038 if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 ||
2039 impl_tokenp->s_thread != curthread) {
2040
2041 /*
2042 * There are three ways to break out of the loop:
2043 * 1) Condition met (s_count == 0) - higher prio test
2044 * 2) kill(2) signal received (rval == 0)
2045 * 3) timeout occurred (rval == -1)
2046 * If condition met, whether or not signal or timeout occurred
2047 * take access. If condition not met, check other exit means.
2048 */
2049 while (impl_tokenp->s_count != 0) {
2050
2051 /* cv_timedwait* returns -1 on timeout. */
2052 /* cv_wait*_sig returns 0 on (kill(2)) signal. */
2053 if (rval <= 0) {
2054 mutex_exit(&impl_tokenp->s_mutex);
2055 USB_DPRINTF_L4(DPRINT_MASK_USBA,
2056 usbai_log_handle,
2057 "usb_serialize_access: "
2058 "tok=0x%p exit due to %s",
2059 (void *)impl_tokenp,
2060 ((rval == 0) ? "signal" : "timeout"));
2061
2062 return (rval);
2063 }
2064
2065 switch (how_to_wait) {
2066 default:
2067 how_to_wait = USB_WAIT;
2068 /* FALLTHROUGH */
2069 case USB_WAIT:
2070 cv_wait(&impl_tokenp->s_cv,
2071 &impl_tokenp->s_mutex);
2072 break;
2073 case USB_WAIT_SIG:
2074 rval = cv_wait_sig(&impl_tokenp->s_cv,
2075 &impl_tokenp->s_mutex);
2076 break;
2077 case USB_TIMEDWAIT:
2078 rval = cv_timedwait(&impl_tokenp->s_cv,
2079 &impl_tokenp->s_mutex, abs_timeout);
2080 break;
2081 case USB_TIMEDWAIT_SIG:
2082 rval = cv_timedwait_sig(&impl_tokenp->s_cv,
2083 &impl_tokenp->s_mutex, abs_timeout);
2084 break;
2085 }
2086 }
2087
2088 impl_tokenp->s_thread = curthread;
2089 }
2090 impl_tokenp->s_count++;
2091
2092 ASSERT(!(impl_tokenp->s_count > 1 &&
2093 (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0));
2094
2095 mutex_exit(&impl_tokenp->s_mutex);
2096
2097 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2098 "usb_serialize_access exit: tok=0x%p thr=0x%p", (void *)impl_tokenp,
2099 (void *)curthread);
2100
2101 return (1);
2102 }
2103
2104
2105 /*ARGSUSED*/
2106 int
usb_try_serialize_access(usb_serialization_t tokenp,uint_t flag)2107 usb_try_serialize_access(
2108 usb_serialization_t tokenp, uint_t flag)
2109 {
2110 usba_serialization_impl_t *impl_tokenp =
2111 (usba_serialization_impl_t *)tokenp;
2112 mutex_enter(&impl_tokenp->s_mutex);
2113
2114 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2115 "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2116 (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2117 impl_tokenp->s_count, (void *)curthread);
2118
2119 /*
2120 * If lock is not taken (s_count is 0), take it.
2121 * If lock is already taken, the thread is owner and lock
2122 * is reentrant, take it.
2123 * Otherwise, fail the access.
2124 */
2125 if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) &&
2126 (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) {
2127 impl_tokenp->s_thread = curthread;
2128 impl_tokenp->s_count++;
2129
2130 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2131 "usb_try_serialize_access success: tok=0x%p",
2132 (void *)impl_tokenp);
2133 mutex_exit(&impl_tokenp->s_mutex);
2134
2135 return (USB_SUCCESS);
2136 }
2137
2138 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2139 "usb_try_serialize_access failed: "
2140 "tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2141 (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2142 impl_tokenp->s_count, (void *)impl_tokenp->s_thread);
2143
2144 mutex_exit(&impl_tokenp->s_mutex);
2145
2146 return (USB_FAILURE);
2147 }
2148
2149
2150 void
usb_release_access(usb_serialization_t tokenp)2151 usb_release_access(
2152 usb_serialization_t tokenp)
2153 {
2154 usba_serialization_impl_t *impl_tokenp =
2155 (usba_serialization_impl_t *)tokenp;
2156 mutex_enter(&impl_tokenp->s_mutex);
2157
2158 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2159 "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
2160 (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2161 impl_tokenp->s_count, (void *)curthread);
2162
2163 ASSERT(impl_tokenp->s_count > 0);
2164
2165 if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) {
2166 if (impl_tokenp->s_thread != curthread) {
2167 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2168 "usb_release_access: release from wrong thread");
2169 }
2170 ASSERT(impl_tokenp->s_thread == curthread);
2171 }
2172
2173 if (--impl_tokenp->s_count == 0) {
2174 impl_tokenp->s_thread = NULL;
2175 cv_broadcast(&impl_tokenp->s_cv);
2176 }
2177 mutex_exit(&impl_tokenp->s_mutex);
2178 }
2179
2180
2181 /*
2182 * usb_fail_checkpoint:
2183 * fail checkpoint as driver/device could not be quiesced
2184 */
2185 /*ARGSUSED*/
2186 void
usb_fail_checkpoint(dev_info_t * dip,usb_flags_t flags)2187 usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags)
2188 {
2189 usba_device_t *usba_device = usba_get_usba_device(dip);
2190
2191 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2192 "usb_fail_checkpoint: %s%d", ddi_driver_name(dip),
2193 ddi_get_instance(dip));
2194
2195 mutex_enter(&usba_device->usb_mutex);
2196 usba_device->usb_no_cpr++;
2197 mutex_exit(&usba_device->usb_mutex);
2198 }
2199
2200
2201 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
2202 _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
2203 /*
2204 * usba_mk_mctl:
2205 * create a USB style M_CTL message, given an iocblk and a buffer
2206 * returns mblk_t * on success, NULL on failure
2207 */
2208 mblk_t *
usba_mk_mctl(struct iocblk mctlmsg,void * buf,size_t len)2209 usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len)
2210 {
2211 mblk_t *bp1, *bp2;
2212
2213 if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) {
2214 /* LINTED E_BAD_PTR_CAST_ALIGN */
2215 *((struct iocblk *)bp1->b_datap->db_base) = mctlmsg;
2216 bp1->b_datap->db_type = M_CTL;
2217 bp1->b_wptr += sizeof (struct iocblk);
2218 if (buf != NULL) {
2219 if ((bp2 = allocb(len, BPRI_HI)) != NULL) {
2220 bp1->b_cont = bp2;
2221 bcopy(buf, bp2->b_datap->db_base, len);
2222 bp2->b_wptr += len;
2223 } else {
2224 freemsg(bp1);
2225 bp1 = NULL;
2226 }
2227 }
2228 }
2229
2230 return (bp1);
2231 }
2232
2233
2234 #ifdef ALLOCB_TEST
2235 #undef allocb
2236 mblk_t *
usba_test_allocb(size_t size,uint_t pri)2237 usba_test_allocb(size_t size, uint_t pri)
2238 {
2239 if (ddi_get_lbolt() & 0x1) {
2240
2241 return (NULL);
2242 } else {
2243
2244 return (allocb(size, pri));
2245 }
2246 }
2247 #endif
2248
2249
2250 /*
2251 * usb common power management for usb_mid, usb_ia and maybe other simple
2252 * drivers.
2253 */
2254
2255 /*
2256 * functions to handle power transition for OS levels 0 -> 3
2257 */
2258 static int
usb_common_pwrlvl0(dev_info_t * dip,uint8_t * pm,int * dev_state)2259 usb_common_pwrlvl0(dev_info_t *dip, uint8_t *pm, int *dev_state)
2260 {
2261 int rval;
2262
2263 switch (*dev_state) {
2264 case USB_DEV_ONLINE:
2265 /* Issue USB D3 command to the device here */
2266 rval = usb_set_device_pwrlvl3(dip);
2267 ASSERT(rval == USB_SUCCESS);
2268
2269 *dev_state = USB_DEV_PWRED_DOWN;
2270 *pm = USB_DEV_OS_PWR_OFF;
2271 /* FALLTHRU */
2272 case USB_DEV_DISCONNECTED:
2273 case USB_DEV_SUSPENDED:
2274 /* allow a disconnected/cpr'ed device to go to low pwr */
2275
2276 return (USB_SUCCESS);
2277 case USB_DEV_PWRED_DOWN:
2278 default:
2279 return (USB_FAILURE);
2280 }
2281 }
2282
2283
2284 /* ARGSUSED */
2285 static int
usb_common_pwrlvl1(dev_info_t * dip,uint8_t * pm,int * dev_state)2286 usb_common_pwrlvl1(dev_info_t *dip, uint8_t *pm, int *dev_state)
2287 {
2288 int rval;
2289
2290 /* Issue USB D2 command to the device here */
2291 rval = usb_set_device_pwrlvl2(dip);
2292 ASSERT(rval == USB_SUCCESS);
2293
2294 return (USB_FAILURE);
2295 }
2296
2297
2298 /* ARGSUSED */
2299 static int
usb_common_pwrlvl2(dev_info_t * dip,uint8_t * pm,int * dev_state)2300 usb_common_pwrlvl2(dev_info_t *dip, uint8_t *pm, int *dev_state)
2301 {
2302 int rval;
2303
2304 /* Issue USB D1 command to the device here */
2305 rval = usb_set_device_pwrlvl1(dip);
2306 ASSERT(rval == USB_SUCCESS);
2307
2308 return (USB_FAILURE);
2309 }
2310
2311
2312 static int
usb_common_pwrlvl3(dev_info_t * dip,uint8_t * pm,int * dev_state)2313 usb_common_pwrlvl3(dev_info_t *dip, uint8_t *pm, int *dev_state)
2314 {
2315 int rval;
2316
2317 switch (*dev_state) {
2318 case USB_DEV_PWRED_DOWN:
2319 /* Issue USB D0 command to the device here */
2320 rval = usb_set_device_pwrlvl0(dip);
2321 ASSERT(rval == USB_SUCCESS);
2322
2323 *dev_state = USB_DEV_ONLINE;
2324 *pm = USB_DEV_OS_FULL_PWR;
2325
2326 /* FALLTHRU */
2327 case USB_DEV_ONLINE:
2328 /* we are already in full power */
2329
2330 /* FALLTHRU */
2331 case USB_DEV_DISCONNECTED:
2332 case USB_DEV_SUSPENDED:
2333 /* allow a disconnected/cpr'ed device to go to low power */
2334
2335 return (USB_SUCCESS);
2336 default:
2337 USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2338 "usb_common_pwrlvl3: Illegal state (%s)",
2339 usb_str_dev_state(*dev_state));
2340
2341 return (USB_FAILURE);
2342 }
2343 }
2344
2345 /* power management */
2346 int
usba_common_power(dev_info_t * dip,uint8_t * pm,int * dev_state,int level)2347 usba_common_power(dev_info_t *dip, uint8_t *pm, int *dev_state, int level)
2348 {
2349 int rval = DDI_FAILURE;
2350
2351 switch (level) {
2352 case USB_DEV_OS_PWR_OFF:
2353 rval = usb_common_pwrlvl0(dip, pm, dev_state);
2354 break;
2355 case USB_DEV_OS_PWR_1:
2356 rval = usb_common_pwrlvl1(dip, pm, dev_state);
2357 break;
2358 case USB_DEV_OS_PWR_2:
2359 rval = usb_common_pwrlvl2(dip, pm, dev_state);
2360 break;
2361 case USB_DEV_OS_FULL_PWR:
2362 rval = usb_common_pwrlvl3(dip, pm, dev_state);
2363 break;
2364 }
2365
2366 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2367 }
2368
2369 /*
2370 * register and unregister for events from our parent for usb_mid and usb_ia
2371 * and maybe other nexus driver.
2372 *
2373 * Note: The cookie fields in usba_device structure is not used. They are
2374 * used/shared by children.
2375 */
2376 void
usba_common_register_events(dev_info_t * dip,uint_t if_num,void (* event_cb)(dev_info_t *,ddi_eventcookie_t,void *,void *))2377 usba_common_register_events(dev_info_t *dip, uint_t if_num,
2378 void (*event_cb)(dev_info_t *, ddi_eventcookie_t, void *, void *))
2379 {
2380 int rval;
2381 usba_evdata_t *evdata;
2382 ddi_eventcookie_t cookie;
2383
2384 USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2385 "usb_common_register_events:");
2386
2387 evdata = usba_get_evdata(dip);
2388
2389 /* get event cookie, discard level and icookie for now */
2390 rval = ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
2391 &cookie);
2392
2393 if (rval == DDI_SUCCESS) {
2394 rval = ddi_add_event_handler(dip,
2395 cookie, event_cb, NULL, &evdata->ev_rm_cb_id);
2396
2397 if (rval != DDI_SUCCESS) {
2398
2399 goto fail;
2400 }
2401 }
2402 rval = ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
2403 &cookie);
2404 if (rval == DDI_SUCCESS) {
2405 rval = ddi_add_event_handler(dip, cookie, event_cb,
2406 NULL, &evdata->ev_ins_cb_id);
2407
2408 if (rval != DDI_SUCCESS) {
2409
2410 goto fail;
2411 }
2412 }
2413 rval = ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, &cookie);
2414 if (rval == DDI_SUCCESS) {
2415 rval = ddi_add_event_handler(dip,
2416 cookie, event_cb, NULL, &evdata->ev_suspend_cb_id);
2417
2418 if (rval != DDI_SUCCESS) {
2419
2420 goto fail;
2421 }
2422 }
2423 rval = ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, &cookie);
2424 if (rval == DDI_SUCCESS) {
2425 rval = ddi_add_event_handler(dip, cookie, event_cb, NULL,
2426 &evdata->ev_resume_cb_id);
2427
2428 if (rval != DDI_SUCCESS) {
2429
2430 goto fail;
2431 }
2432 }
2433
2434 return;
2435
2436
2437 fail:
2438 usba_common_unregister_events(dip, if_num);
2439
2440 }
2441
2442 void
usba_common_unregister_events(dev_info_t * dip,uint_t if_num)2443 usba_common_unregister_events(dev_info_t *dip, uint_t if_num)
2444 {
2445 usba_evdata_t *evdata;
2446 usba_device_t *usba_device = usba_get_usba_device(dip);
2447 int i;
2448
2449 evdata = usba_get_evdata(dip);
2450
2451 if (evdata->ev_rm_cb_id != NULL) {
2452 (void) ddi_remove_event_handler(evdata->ev_rm_cb_id);
2453 evdata->ev_rm_cb_id = NULL;
2454 }
2455
2456 if (evdata->ev_ins_cb_id != NULL) {
2457 (void) ddi_remove_event_handler(evdata->ev_ins_cb_id);
2458 evdata->ev_ins_cb_id = NULL;
2459 }
2460
2461 if (evdata->ev_suspend_cb_id != NULL) {
2462 (void) ddi_remove_event_handler(evdata->ev_suspend_cb_id);
2463 evdata->ev_suspend_cb_id = NULL;
2464 }
2465
2466 if (evdata->ev_resume_cb_id != NULL) {
2467 (void) ddi_remove_event_handler(evdata->ev_resume_cb_id);
2468 evdata->ev_resume_cb_id = NULL;
2469 }
2470
2471 /* clear event data for children, required for cfgmadm unconfigure */
2472 mutex_enter(&usba_device->usb_mutex);
2473 if (usb_owns_device(dip)) {
2474 usba_free_evdata(usba_device->usb_evdata);
2475 usba_device->usb_evdata = NULL;
2476 usba_device->rm_cookie = NULL;
2477 usba_device->ins_cookie = NULL;
2478 usba_device->suspend_cookie = NULL;
2479 usba_device->resume_cookie = NULL;
2480 } else {
2481 for (i = 0; i < if_num; i++) {
2482 usba_device->usb_client_flags[usba_get_ifno(dip) + i]
2483 &= ~USBA_CLIENT_FLAG_EV_CBS;
2484 }
2485 }
2486 mutex_exit(&usba_device->usb_mutex);
2487 }
2488