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