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 * WUSB cable association driver
28 *
29 * This driver implements the cable association mechanism defined in
30 * "Association Models Supplement to the Certified Wireless Universal
31 * Serial Bus Specification 1.0". Cable association compliant devices,
32 * i.e. with bInterfaceClass=0xEF, bInterfaceSubClass=0x03 and
33 * bInterfaceProtocol=0x01(compatible names: "usbif,classef.3.1") will
34 * be supported by this driver.
35 *
36 * The Cable Association Model uses the USB Cable-Based Association
37 * Framework (CBAF). The basic operation under this framework is:
38 *
39 * - The user connects the device to the host using a USB cable.
40 *
41 * - The host detects that the device supports the CBAF and it is capable
42 * of configuring WUSB CC(Connection Context).
43 *
44 * - The host sends its CHID to the device, along with other information
45 *
46 * - If the device has a valid CC with a matching CHID, the device will
47 * respond to the host with the CDID from the CC.
48 *
49 * - As of this driver implementation, no matter if the CDID returned
50 * from the device matches the CDID in the host's copy of CC, we choose
51 * to skip further explicit user conditioning, generate a new CC and send
52 * it to the device.
53 *
54 * - Upon receiving the CC, the device must store the CC in non-volatile
55 * memory, replacing any existing CC with a matching CHID if it exists.
56 *
57 * - First time association is complete: Host has securely transferred the CC
58 * to the device
59 *
60 * CBAF requires device to use the default control endpoint to exchange
61 * requests and data with host. Three control requests are defined by spec
62 * and supported by this driver:
63 * - GET_ASSOCIATION_INFORMATION
64 * - GET_ASSOCIATION_REQUEST
65 * - SET_ASSOCIATION_RESPONSE
66 *
67 */
68
69 #if defined(lint) && !defined(DEBUG)
70 #define DEBUG
71 #endif
72
73 #define USBDRV_MAJOR_VER 2
74 #define USBDRV_MINOR_VER 0
75
76 #include <sys/usb/usba.h>
77 #include <sys/stream.h>
78 #include <sys/strsun.h>
79 #include <sys/usb/clients/wusb_ca/wusb_ca_priv.h>
80 #include <sys/usb/clients/wusb_ca/wusb_ca.h>
81
82
83 uint_t wusb_ca_errlevel = USB_LOG_L4;
84 uint_t wusb_ca_errmask = (uint_t)PRINT_MASK_ALL;
85 uint_t wusb_ca_instance_debug = (uint_t)-1;
86
87 /*
88 * Function Prototypes
89 */
90 static int wusb_ca_attach(dev_info_t *, ddi_attach_cmd_t);
91 static int wusb_ca_detach(dev_info_t *, ddi_detach_cmd_t);
92 static int wusb_ca_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
93 static int wusb_ca_cleanup(dev_info_t *, wusb_ca_state_t *);
94 static int wusb_ca_open(dev_t *, int, int, cred_t *);
95 static int wusb_ca_close(dev_t, int, int, cred_t *);
96 static int wusb_ca_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
97 static int wusb_ca_disconnect_callback(dev_info_t *);
98 static int wusb_ca_reconnect_callback(dev_info_t *);
99 static void wusb_ca_restore_device_state(dev_info_t *, wusb_ca_state_t *);
100
101 static int wusb_ca_cpr_suspend(dev_info_t *);
102 static void wusb_ca_cpr_resume(dev_info_t *);
103 static int wusb_ca_pm_busy_component(wusb_ca_state_t *);
104 static void wusb_ca_pm_idle_component(wusb_ca_state_t *);
105 static int wusb_ca_power(dev_info_t *, int, int);
106 static void wusb_ca_init_power_mgmt(wusb_ca_state_t *);
107 static void wusb_ca_destroy_power_mgmt(wusb_ca_state_t *);
108
109 static int wusb_ca_serialize_access(wusb_ca_state_t *, boolean_t);
110 static void wusb_ca_release_access(wusb_ca_state_t *);
111 static int wusb_ca_check_same_device(wusb_ca_state_t *);
112
113 static mblk_t *trans_from_host_info(wusb_cbaf_host_info_t *);
114 static mblk_t *trans_from_cc_data(wusb_cbaf_cc_data_t *);
115 static mblk_t *trans_from_cc_fail(wusb_cbaf_cc_fail_t *);
116 static int trans_to_device_info(wusb_ca_state_t *, mblk_t *,
117 wusb_cbaf_device_info_t *);
118
119 /* _NOTE is an advice for locklint. Locklint checks lock use for deadlocks. */
120 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
121 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf))
122 _NOTE(SCHEME_PROTECTS_DATA("unique per call", msgb))
123 /* module loading stuff */
124 struct cb_ops wusb_ca_cb_ops = {
125 wusb_ca_open, /* open */
126 wusb_ca_close, /* close */
127 nulldev, /* strategy */
128 nulldev, /* print */
129 nulldev, /* dump */
130 nodev, /* read */
131 nodev, /* write */
132 wusb_ca_ioctl, /* ioctl */
133 nulldev, /* devmap */
134 nodev, /* mmap */
135 nodev, /* segmap */
136 nochpoll, /* poll */
137 ddi_prop_op, /* cb_prop_op */
138 NULL, /* streamtab */
139 D_MP
140 };
141
142 static struct dev_ops wusb_ca_ops = {
143 DEVO_REV, /* devo_rev, */
144 0, /* refcnt */
145 wusb_ca_info, /* info */
146 nulldev, /* identify */
147 nulldev, /* probe */
148 wusb_ca_attach, /* attach */
149 wusb_ca_detach, /* detach */
150 nodev, /* reset */
151 &wusb_ca_cb_ops, /* driver operations */
152 NULL, /* bus operations */
153 wusb_ca_power, /* power */
154 ddi_quiesce_not_needed, /* quiesce */
155 };
156
157 static struct modldrv wusb_ca_modldrv = {
158 &mod_driverops,
159 "WUSB Cable Association driver",
160 &wusb_ca_ops
161 };
162
163 static struct modlinkage modlinkage = {
164 MODREV_1,
165 &wusb_ca_modldrv,
166 NULL
167 };
168
169 /* local variables */
170
171 /* Soft state structures */
172 #define WUSB_CA_INITIAL_SOFT_SPACE 1
173 static void *wusb_ca_statep;
174
175
176 /*
177 * Module-wide initialization routine.
178 */
179 int
_init(void)180 _init(void)
181 {
182 int rval;
183
184 if ((rval = ddi_soft_state_init(&wusb_ca_statep,
185 sizeof (wusb_ca_state_t), WUSB_CA_INITIAL_SOFT_SPACE)) != 0) {
186
187 return (rval);
188 }
189
190 if ((rval = mod_install(&modlinkage)) != 0) {
191 ddi_soft_state_fini(&wusb_ca_statep);
192 }
193
194 return (rval);
195 }
196
197
198 /*
199 * Module-wide tear-down routine.
200 */
201 int
_fini(void)202 _fini(void)
203 {
204 int rval;
205
206 if ((rval = mod_remove(&modlinkage)) != 0) {
207
208 return (rval);
209 }
210
211 ddi_soft_state_fini(&wusb_ca_statep);
212
213 return (rval);
214 }
215
216
217 int
_info(struct modinfo * modinfop)218 _info(struct modinfo *modinfop)
219 {
220 return (mod_info(&modlinkage, modinfop));
221 }
222
223
224 /*
225 * wusb_ca_info:
226 * Get minor number, soft state structure, etc.
227 */
228 /*ARGSUSED*/
229 static int
wusb_ca_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)230 wusb_ca_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
231 void *arg, void **result)
232 {
233 wusb_ca_state_t *wusb_cap;
234 int error = DDI_FAILURE;
235
236 switch (infocmd) {
237 case DDI_INFO_DEVT2DEVINFO:
238 if ((wusb_cap = ddi_get_soft_state(wusb_ca_statep,
239 getminor((dev_t)arg))) != NULL) {
240 *result = wusb_cap->wusb_ca_dip;
241 if (*result != NULL) {
242 error = DDI_SUCCESS;
243 }
244 } else {
245 *result = NULL;
246 }
247 break;
248 case DDI_INFO_DEVT2INSTANCE:
249 *result = (void *)(uintptr_t)getminor((dev_t)arg);
250 error = DDI_SUCCESS;
251 break;
252 default:
253 break;
254 }
255
256 return (error);
257 }
258
259
260 /*
261 * wusb_ca_attach:
262 * Attach or resume.
263 *
264 * For attach, initialize state and device, including:
265 * state variables, locks, device node
266 * device registration with system
267 * power management, hotplugging
268 * For resume, restore device and state
269 */
270 static int
wusb_ca_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)271 wusb_ca_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
272 {
273 int instance = ddi_get_instance(dip);
274 char *devinst;
275 int devinstlen;
276 wusb_ca_state_t *wusb_cap = NULL;
277 int status;
278
279 switch (cmd) {
280 case DDI_ATTACH:
281 break;
282
283 case DDI_RESUME:
284 wusb_ca_cpr_resume(dip);
285
286 /*
287 * Always return success to work around enumeration failures.
288 * This works around an issue where devices which are present
289 * before a suspend and absent upon resume could cause a system
290 * panic on resume.
291 */
292 return (DDI_SUCCESS);
293 default:
294 return (DDI_FAILURE);
295 }
296
297 if (ddi_soft_state_zalloc(wusb_ca_statep, instance) == DDI_SUCCESS) {
298 wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
299 }
300 if (wusb_cap == NULL) {
301
302 return (DDI_FAILURE);
303 }
304
305 wusb_cap->wusb_ca_dip = dip;
306
307 devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
308 devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ",
309 ddi_driver_name(dip), instance);
310
311 wusb_cap->wusb_ca_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
312 (void) strncpy(wusb_cap->wusb_ca_devinst, devinst, devinstlen);
313 kmem_free(devinst, USB_MAXSTRINGLEN);
314
315 wusb_cap->wusb_ca_log_hdl = usb_alloc_log_hdl(dip, "wusb_ca",
316 &wusb_ca_errlevel, &wusb_ca_errmask, &wusb_ca_instance_debug, 0);
317
318 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
319 "Attach: enter for attach");
320
321
322
323 if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) !=
324 USB_SUCCESS) {
325 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
326 "attach: usb_client_attach failed, error code:%d", status);
327 goto fail;
328 }
329
330 if ((status = usb_get_dev_data(dip, &wusb_cap->wusb_ca_reg,
331 USB_PARSE_LVL_ALL, 0)) != USB_SUCCESS) {
332 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
333 "attach: usb_get_dev_data failed, error code:%d", status);
334 goto fail;
335 }
336
337 usb_free_descr_tree(dip, wusb_cap->wusb_ca_reg);
338
339 mutex_init(&wusb_cap->wusb_ca_mutex, NULL, MUTEX_DRIVER,
340 wusb_cap->wusb_ca_reg->dev_iblock_cookie);
341
342 cv_init(&wusb_cap->wusb_ca_serial_cv, NULL, CV_DRIVER, NULL);
343 wusb_cap->wusb_ca_serial_inuse = B_FALSE;
344
345 wusb_cap->wusb_ca_locks_initialized = B_TRUE;
346
347 /* create minor node */
348 if (ddi_create_minor_node(dip, "wusb_ca", S_IFCHR, instance,
349 "wusb_ca", 0) != DDI_SUCCESS) {
350 USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
351 "attach: Error creating minor node");
352
353 goto fail;
354 }
355
356 /* Put online before PM init as can get power managed afterward. */
357 wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
358
359 /* initialize power management */
360 wusb_ca_init_power_mgmt(wusb_cap);
361
362 if (usb_register_hotplug_cbs(dip, wusb_ca_disconnect_callback,
363 wusb_ca_reconnect_callback) != USB_SUCCESS) {
364
365 goto fail;
366 }
367
368 /* Report device */
369 ddi_report_dev(dip);
370
371 return (DDI_SUCCESS);
372
373 fail:
374 if (wusb_cap) {
375 (void) wusb_ca_cleanup(dip, wusb_cap);
376 }
377
378 return (DDI_FAILURE);
379 }
380
381
382 /*
383 * wusb_ca_detach:
384 * detach or suspend driver instance
385 *
386 * Note: in detach, only contention threads is from pm and disconnnect.
387 */
388 static int
wusb_ca_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)389 wusb_ca_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
390 {
391 int instance = ddi_get_instance(dip);
392 int rval = DDI_FAILURE;
393 wusb_ca_state_t *wusb_cap;
394
395 wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
396 switch (cmd) {
397 case DDI_DETACH:
398 mutex_enter(&wusb_cap->wusb_ca_mutex);
399 ASSERT((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) == 0);
400 mutex_exit(&wusb_cap->wusb_ca_mutex);
401
402 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
403 "Detach: enter for detach");
404
405 rval = wusb_ca_cleanup(dip, wusb_cap);
406
407 break;
408 case DDI_SUSPEND:
409 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
410 "Detach: enter for suspend");
411
412 rval = wusb_ca_cpr_suspend(dip);
413 default:
414
415 break;
416 }
417
418 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
419 }
420
421
422 /*
423 * wusb_ca_cleanup:
424 * clean up the driver state for detach
425 */
426 static int
wusb_ca_cleanup(dev_info_t * dip,wusb_ca_state_t * wusb_cap)427 wusb_ca_cleanup(dev_info_t *dip, wusb_ca_state_t *wusb_cap)
428 {
429 USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
430 "Cleanup: enter");
431
432 if (wusb_cap->wusb_ca_locks_initialized) {
433
434 /* This must be done 1st to prevent more events from coming. */
435 usb_unregister_hotplug_cbs(dip);
436
437 /*
438 * At this point, no new activity can be initiated. The driver
439 * has disabled hotplug callbacks. The Solaris framework has
440 * disabled new opens on a device being detached, and does not
441 * allow detaching an open device.
442 *
443 * The following ensures that all driver activity has drained.
444 */
445 mutex_enter(&wusb_cap->wusb_ca_mutex);
446 (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
447 wusb_ca_release_access(wusb_cap);
448 mutex_exit(&wusb_cap->wusb_ca_mutex);
449
450 /* All device activity has died down. */
451 wusb_ca_destroy_power_mgmt(wusb_cap);
452
453 /* start dismantling */
454 ddi_remove_minor_node(dip, NULL);
455
456 cv_destroy(&wusb_cap->wusb_ca_serial_cv);
457 mutex_destroy(&wusb_cap->wusb_ca_mutex);
458 }
459
460 usb_client_detach(dip, wusb_cap->wusb_ca_reg);
461
462 usb_free_log_hdl(wusb_cap->wusb_ca_log_hdl);
463
464 if (wusb_cap->wusb_ca_devinst != NULL) {
465 kmem_free(wusb_cap->wusb_ca_devinst,
466 strlen(wusb_cap->wusb_ca_devinst) + 1);
467 }
468
469 ddi_soft_state_free(wusb_ca_statep, ddi_get_instance(dip));
470 ddi_prop_remove_all(dip);
471
472 return (USB_SUCCESS);
473 }
474
475
476 /*ARGSUSED*/
477 static int
wusb_ca_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)478 wusb_ca_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
479 {
480 wusb_ca_state_t *wusb_cap =
481 ddi_get_soft_state(wusb_ca_statep, getminor(*devp));
482 int rval = 0;
483
484 if (wusb_cap == NULL) {
485
486 return (ENXIO);
487 }
488
489 USB_DPRINTF_L4(PRINT_MASK_OPEN, wusb_cap->wusb_ca_log_hdl,
490 "open: enter");
491
492 /*
493 * Keep it simple: one client at a time.
494 * Exclusive open only
495 */
496 mutex_enter(&wusb_cap->wusb_ca_mutex);
497 if ((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) != 0) {
498 mutex_exit(&wusb_cap->wusb_ca_mutex);
499
500 return (EBUSY);
501 }
502 wusb_cap->wusb_ca_drv_state |= WUSB_CA_OPEN;
503
504 /*
505 * This is in place so that a disconnect or CPR doesn't interfere with
506 * pipe opens.
507 */
508 if (wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_SIG) == 0) {
509 wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
510 mutex_exit(&wusb_cap->wusb_ca_mutex);
511
512 return (EINTR);
513 }
514
515 mutex_exit(&wusb_cap->wusb_ca_mutex);
516 if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
517 USB_DPRINTF_L2(PRINT_MASK_OPEN, wusb_cap->wusb_ca_log_hdl,
518 "open: Error raising power");
519 rval = EIO;
520 goto done;
521 }
522 mutex_enter(&wusb_cap->wusb_ca_mutex);
523
524 /* Fail if device is no longer ready. */
525 if (wusb_cap->wusb_ca_dev_state != USB_DEV_ONLINE) {
526 mutex_exit(&wusb_cap->wusb_ca_mutex);
527 rval = EIO;
528 goto done;
529 }
530
531 mutex_exit(&wusb_cap->wusb_ca_mutex);
532
533 done:
534 if (rval != 0) {
535 mutex_enter(&wusb_cap->wusb_ca_mutex);
536 wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
537
538 wusb_ca_release_access(wusb_cap);
539 mutex_exit(&wusb_cap->wusb_ca_mutex);
540
541 wusb_ca_pm_idle_component(wusb_cap);
542 } else {
543
544 /* Device is idle until it is used. */
545 mutex_enter(&wusb_cap->wusb_ca_mutex);
546 wusb_ca_release_access(wusb_cap);
547 mutex_exit(&wusb_cap->wusb_ca_mutex);
548 }
549
550 return (rval);
551 }
552
553
554 /*ARGSUSED*/
555 static int
wusb_ca_close(dev_t dev,int flag,int otyp,cred_t * cred_p)556 wusb_ca_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
557 {
558 wusb_ca_state_t *wusb_cap =
559 ddi_get_soft_state(wusb_ca_statep, getminor(dev));
560
561 USB_DPRINTF_L4(PRINT_MASK_CLOSE, wusb_cap->wusb_ca_log_hdl,
562 "close: enter");
563
564 mutex_enter(&wusb_cap->wusb_ca_mutex);
565 (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
566 mutex_exit(&wusb_cap->wusb_ca_mutex);
567
568 /* Perform device session cleanup here. */
569
570 USB_DPRINTF_L4(PRINT_MASK_CLOSE, wusb_cap->wusb_ca_log_hdl,
571 "close: cleaning up...");
572
573 /*
574 * USBA automatically flushes/resets active non-default pipes
575 * when they are closed. We can't reset default pipe, but we
576 * can wait for all requests on it from this dip to drain.
577 */
578 (void) usb_pipe_drain_reqs(wusb_cap->wusb_ca_dip,
579 wusb_cap->wusb_ca_reg->dev_default_ph, 0,
580 USB_FLAGS_SLEEP, NULL, 0);
581
582 mutex_enter(&wusb_cap->wusb_ca_mutex);
583
584 wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
585
586 wusb_ca_release_access(wusb_cap);
587 mutex_exit(&wusb_cap->wusb_ca_mutex);
588
589 wusb_ca_pm_idle_component(wusb_cap);
590
591 return (0);
592 }
593
594
595 /*
596 * ioctl for cable association operations.
597 */
598 /*ARGSUSED*/
599 static int
wusb_ca_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)600 wusb_ca_ioctl(dev_t dev, int cmd, intptr_t arg,
601 int mode, cred_t *cred_p, int *rval_p)
602 {
603 wusb_ca_state_t *wusb_cap =
604 ddi_get_soft_state(wusb_ca_statep, getminor(dev));
605
606 USB_DPRINTF_L4(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
607 "ioctl enter");
608
609 mutex_enter(&wusb_cap->wusb_ca_mutex);
610
611 switch (cmd) {
612 case CBAF_IOCTL_GET_ASSO_INFO:
613 *rval_p = wusb_cbaf_get_asso_info(wusb_cap, arg, mode);
614
615 break;
616 case CBAF_IOCTL_GET_ASSO_REQS:
617 *rval_p = wusb_cbaf_get_asso_reqs(wusb_cap, arg, mode);
618
619 break;
620 case CBAF_IOCTL_SET_HOST_INFO:
621 *rval_p = wusb_cbaf_set_host_info(wusb_cap, arg, mode);
622
623 break;
624 case CBAF_IOCTL_GET_DEVICE_INFO:
625 *rval_p = wusb_cbaf_get_device_info(wusb_cap, arg, mode);
626
627 break;
628 case CBAF_IOCTL_SET_CONNECTION:
629 *rval_p = wusb_cbaf_set_connection(wusb_cap, arg, mode);
630
631 break;
632 case CBAF_IOCTL_SET_FAILURE:
633 *rval_p = wusb_cbaf_set_failure(wusb_cap, arg, mode);
634
635 break;
636 default:
637
638 *rval_p = EINVAL;
639 }
640
641 mutex_exit(&wusb_cap->wusb_ca_mutex);
642
643 return (*rval_p);
644 }
645
646
647 /*
648 * wusb_ca_disconnect_callback:
649 * Called when device hotplug-removed.
650 * Close pipes. (This does not attempt to contact device.)
651 * Set state to DISCONNECTED
652 */
653 static int
wusb_ca_disconnect_callback(dev_info_t * dip)654 wusb_ca_disconnect_callback(dev_info_t *dip)
655 {
656 int instance = ddi_get_instance(dip);
657 wusb_ca_state_t *wusb_cap;
658
659 wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
660
661 USB_DPRINTF_L4(PRINT_MASK_CB, wusb_cap->wusb_ca_log_hdl,
662 "disconnect: enter");
663
664 mutex_enter(&wusb_cap->wusb_ca_mutex);
665 (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
666
667 /*
668 * Save any state of device or IO in progress required by
669 * wusb_ca_restore_device_state for proper device "thawing" later.
670 */
671 wusb_cap->wusb_ca_dev_state = USB_DEV_DISCONNECTED;
672
673 wusb_ca_release_access(wusb_cap);
674 mutex_exit(&wusb_cap->wusb_ca_mutex);
675
676 return (USB_SUCCESS);
677 }
678
679
680 /*
681 * wusb_ca_reconnect_callback:
682 * Called with device hotplug-inserted
683 * Restore state
684 */
685 static int
wusb_ca_reconnect_callback(dev_info_t * dip)686 wusb_ca_reconnect_callback(dev_info_t *dip)
687 {
688 int instance = ddi_get_instance(dip);
689 wusb_ca_state_t *wusb_cap;
690
691 wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
692
693 USB_DPRINTF_L4(PRINT_MASK_CB, wusb_cap->wusb_ca_log_hdl,
694 "reconnect: enter");
695
696 mutex_enter(&wusb_cap->wusb_ca_mutex);
697 (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
698 wusb_ca_restore_device_state(dip, wusb_cap);
699 wusb_ca_release_access(wusb_cap);
700 mutex_exit(&wusb_cap->wusb_ca_mutex);
701
702 return (USB_SUCCESS);
703 }
704
705
706 /*
707 * wusb_ca_restore_device_state:
708 * Called during hotplug-reconnect and resume.
709 * reenable power management
710 * Verify the device is the same as before the disconnect/suspend.
711 * Restore device state
712 * Thaw any IO which was frozen.
713 * Quiesce device. (Other routines will activate if thawed IO.)
714 * Set device online.
715 * Leave device disconnected if there are problems.
716 */
717 static void
wusb_ca_restore_device_state(dev_info_t * dip,wusb_ca_state_t * wusb_cap)718 wusb_ca_restore_device_state(dev_info_t *dip, wusb_ca_state_t *wusb_cap)
719 {
720 USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
721 "wusb_ca_restore_device_state: enter");
722
723 ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
724
725 ASSERT((wusb_cap->wusb_ca_dev_state == USB_DEV_DISCONNECTED) ||
726 (wusb_cap->wusb_ca_dev_state == USB_DEV_SUSPENDED));
727
728 mutex_exit(&wusb_cap->wusb_ca_mutex);
729
730 if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
731 USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
732 "wusb_ca_restore_device_state: Error raising power");
733
734 goto fail;
735 }
736
737 /* Check if we are talking to the same device */
738 if (wusb_ca_check_same_device(wusb_cap) != USB_SUCCESS) {
739 wusb_ca_pm_idle_component(wusb_cap);
740
741 goto fail;
742 }
743
744 mutex_enter(&wusb_cap->wusb_ca_mutex);
745 wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
746
747 if ((wusb_cap->wusb_ca_pm) &&
748 (wusb_cap->wusb_ca_pm->wusb_ca_remote_wakeup)) {
749 mutex_exit(&wusb_cap->wusb_ca_mutex);
750
751 /* Failure here means device disappeared again. */
752 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) !=
753 USB_SUCCESS) {
754 USB_DPRINTF_L2(PRINT_MASK_CPR,
755 wusb_cap->wusb_ca_log_hdl,
756 "device may or may not be accessible. "
757 "Please verify reconnection");
758 }
759
760 mutex_enter(&wusb_cap->wusb_ca_mutex);
761 }
762
763 mutex_exit(&wusb_cap->wusb_ca_mutex);
764 wusb_ca_pm_idle_component(wusb_cap);
765 mutex_enter(&wusb_cap->wusb_ca_mutex);
766
767 USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
768 "wusb_ca_restore_device_state: end");
769
770 return;
771
772 fail:
773 /* change the device state from suspended to disconnected */
774 mutex_enter(&wusb_cap->wusb_ca_mutex);
775 wusb_cap->wusb_ca_dev_state = USB_DEV_DISCONNECTED;
776 }
777
778
779 /*
780 * wusb_ca_cpr_suspend:
781 * Clean up device.
782 * Wait for any IO to finish, then close pipes.
783 * Quiesce device.
784 */
785 static int
wusb_ca_cpr_suspend(dev_info_t * dip)786 wusb_ca_cpr_suspend(dev_info_t *dip)
787 {
788 int instance = ddi_get_instance(dip);
789 wusb_ca_state_t *wusb_cap;
790
791 wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
792
793 USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
794 "suspend enter");
795
796 /* Serialize to prevent races with detach, open, device access. */
797 mutex_enter(&wusb_cap->wusb_ca_mutex);
798 (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
799 mutex_exit(&wusb_cap->wusb_ca_mutex);
800
801 if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
802 USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
803 "suspend: Error raising power");
804 wusb_ca_pm_idle_component(wusb_cap);
805
806 return (USB_FAILURE);
807 }
808
809 mutex_enter(&wusb_cap->wusb_ca_mutex);
810
811 /*
812 * Set dev_state to suspended so other driver threads don't start any
813 * new I/O.
814 */
815
816 /* Don't suspend if the device is open. */
817 if ((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) != 0) {
818 USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
819 "suspend: Device is open. Can't suspend");
820
821 wusb_ca_release_access(wusb_cap);
822 mutex_exit(&wusb_cap->wusb_ca_mutex);
823
824 wusb_ca_pm_idle_component(wusb_cap);
825
826 return (USB_FAILURE);
827 }
828
829 wusb_cap->wusb_ca_dev_state = USB_DEV_SUSPENDED;
830
831 wusb_ca_release_access(wusb_cap);
832 mutex_exit(&wusb_cap->wusb_ca_mutex);
833
834 wusb_ca_pm_idle_component(wusb_cap);
835
836 USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
837 "suspend: success");
838
839 return (USB_SUCCESS);
840 }
841
842
843 /*
844 * wusb_ca_cpr_resume:
845 *
846 * wusb_ca_restore_device_state marks success by putting device back online
847 */
848 static void
wusb_ca_cpr_resume(dev_info_t * dip)849 wusb_ca_cpr_resume(dev_info_t *dip)
850 {
851 int instance = ddi_get_instance(dip);
852 wusb_ca_state_t *wusb_cap;
853
854 wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
855
856 USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
857 "resume: enter");
858
859 /*
860 * A pm_raise_power in wusb_ca_restore_device_state will bring
861 * the power-up state of device into synch with the system.
862 */
863 mutex_enter(&wusb_cap->wusb_ca_mutex);
864 wusb_ca_restore_device_state(dip, wusb_cap);
865 mutex_exit(&wusb_cap->wusb_ca_mutex);
866 }
867
868
869 static int
wusb_ca_pm_busy_component(wusb_ca_state_t * wusb_cap)870 wusb_ca_pm_busy_component(wusb_ca_state_t *wusb_cap)
871 {
872 int rval = DDI_SUCCESS;
873
874 mutex_enter(&wusb_cap->wusb_ca_mutex);
875 if (wusb_cap->wusb_ca_pm != NULL) {
876 wusb_cap->wusb_ca_pm->wusb_ca_pm_busy++;
877 mutex_exit(&wusb_cap->wusb_ca_mutex);
878 if (pm_busy_component(wusb_cap->wusb_ca_dip, 0) ==
879 DDI_SUCCESS) {
880 (void) pm_raise_power(
881 wusb_cap->wusb_ca_dip, 0, USB_DEV_OS_FULL_PWR);
882 mutex_enter(&wusb_cap->wusb_ca_mutex);
883 } else {
884 mutex_enter(&wusb_cap->wusb_ca_mutex);
885 wusb_cap->wusb_ca_pm->wusb_ca_pm_busy--;
886 }
887 }
888 mutex_exit(&wusb_cap->wusb_ca_mutex);
889
890 return (rval);
891 }
892
893 static void
wusb_ca_pm_idle_component(wusb_ca_state_t * wusb_cap)894 wusb_ca_pm_idle_component(wusb_ca_state_t *wusb_cap)
895 {
896 mutex_enter(&wusb_cap->wusb_ca_mutex);
897 if (wusb_cap->wusb_ca_pm != NULL) {
898 mutex_exit(&wusb_cap->wusb_ca_mutex);
899 if (pm_idle_component(wusb_cap->wusb_ca_dip, 0) ==
900 DDI_SUCCESS) {
901 mutex_enter(&wusb_cap->wusb_ca_mutex);
902 ASSERT(wusb_cap->wusb_ca_pm->wusb_ca_pm_busy > 0);
903 wusb_cap->wusb_ca_pm->wusb_ca_pm_busy--;
904 mutex_exit(&wusb_cap->wusb_ca_mutex);
905 }
906 mutex_enter(&wusb_cap->wusb_ca_mutex);
907 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
908 "wusb_ca_pm_idle_component: %d",
909 wusb_cap->wusb_ca_pm->wusb_ca_pm_busy);
910 }
911 mutex_exit(&wusb_cap->wusb_ca_mutex);
912 }
913
914 /*
915 * wusb_ca_power :
916 * Power entry point, the workhorse behind pm_raise_power, pm_lower_power,
917 * usb_req_raise_power and usb_req_lower_power.
918 */
919 /* ARGSUSED */
920 static int
wusb_ca_power(dev_info_t * dip,int comp,int level)921 wusb_ca_power(dev_info_t *dip, int comp, int level)
922 {
923 wusb_ca_state_t *wusb_cap;
924 wusb_ca_power_t *pm;
925 int rval = USB_SUCCESS;
926
927 wusb_cap = ddi_get_soft_state(wusb_ca_statep, ddi_get_instance(dip));
928
929 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
930 "wusb_ca_power: enter: level = %d", level);
931
932 mutex_enter(&wusb_cap->wusb_ca_mutex);
933 (void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
934
935 /*
936 * If we are disconnected/suspended, return success. Note that if we
937 * return failure, bringing down the system will hang when PM tries
938 * to power up all devices
939 */
940 if ((wusb_cap->wusb_ca_dev_state == USB_DEV_DISCONNECTED) ||
941 (wusb_cap->wusb_ca_dev_state == USB_DEV_SUSPENDED)) {
942
943 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
944 "wusb_ca_power: disconnected/suspended "
945 "dev_state=%d", wusb_cap->wusb_ca_dev_state);
946 rval = USB_SUCCESS;
947
948 goto done;
949 }
950
951 if (wusb_cap->wusb_ca_pm == NULL) {
952
953 goto done;
954 }
955
956 pm = wusb_cap->wusb_ca_pm;
957
958 /* Check if we are transitioning to a legal power level */
959 if (USB_DEV_PWRSTATE_OK(pm->wusb_ca_pwr_states, level)) {
960 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
961 "wusb_ca_power: illegal power level = %d "
962 "pwr_states: %x", level, pm->wusb_ca_pwr_states);
963
964 goto done;
965 }
966
967 switch (level) {
968 case USB_DEV_OS_PWR_OFF :
969 /* fail attempt to go to low power if busy */
970 if (pm->wusb_ca_pm_busy) {
971
972 goto done;
973 }
974 if (wusb_cap->wusb_ca_dev_state == USB_DEV_ONLINE) {
975 (void) usb_set_device_pwrlvl3(wusb_cap->wusb_ca_dip);
976
977 wusb_cap->wusb_ca_dev_state = USB_DEV_PWRED_DOWN;
978 wusb_cap->wusb_ca_pm->wusb_ca_current_power =
979 USB_DEV_OS_PWR_OFF;
980 }
981
982 break;
983
984 case USB_DEV_OS_FULL_PWR :
985 /*
986 * PM framework tries to put us in full power during system
987 * shutdown. Handle USB_DEV_PWRED_DOWN only.
988 */
989 if (wusb_cap->wusb_ca_dev_state == USB_DEV_PWRED_DOWN) {
990 (void) usb_set_device_pwrlvl0(wusb_cap->wusb_ca_dip);
991 wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
992 wusb_cap->wusb_ca_pm->wusb_ca_current_power =
993 USB_DEV_OS_FULL_PWR;
994 }
995
996 break;
997
998 /* Levels 1 and 2 are not supported by this driver to keep it simple. */
999 default:
1000 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1001 "wusb_ca_power: power level %d not supported", level);
1002 break;
1003 }
1004 done:
1005 wusb_ca_release_access(wusb_cap);
1006 mutex_exit(&wusb_cap->wusb_ca_mutex);
1007
1008 /* Generally return success to make PM succeed */
1009 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1010 }
1011
1012
1013 /*
1014 * wusb_ca_init_power_mgmt:
1015 * Initialize power management and remote wakeup functionality.
1016 * No mutex is necessary in this function as it's called only by attach.
1017 */
1018 static void
wusb_ca_init_power_mgmt(wusb_ca_state_t * wusb_cap)1019 wusb_ca_init_power_mgmt(wusb_ca_state_t *wusb_cap)
1020 {
1021 wusb_ca_power_t *wusb_capm;
1022 uint_t pwr_states;
1023
1024 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1025 "init_power_mgmt enter");
1026
1027 /* Allocate the state structure */
1028 wusb_capm = kmem_zalloc(sizeof (wusb_ca_power_t), KM_SLEEP);
1029 wusb_cap->wusb_ca_pm = wusb_capm;
1030 wusb_capm->wusb_ca_state = wusb_cap;
1031 wusb_capm->wusb_ca_pm_capabilities = 0;
1032 wusb_capm->wusb_ca_current_power = USB_DEV_OS_FULL_PWR;
1033
1034 if (usb_create_pm_components(wusb_cap->wusb_ca_dip,
1035 &pwr_states) == USB_SUCCESS) {
1036 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1037 "wusb_ca_init_power_mgmt: created PM components");
1038
1039 wusb_capm->wusb_ca_pwr_states = (uint8_t)pwr_states;
1040 (void) pm_raise_power(wusb_cap->wusb_ca_dip, 0,
1041 USB_DEV_OS_FULL_PWR);
1042 } else {
1043 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1044 "wusb_ca_init_power_mgmt: create_pm_compts failed");
1045 }
1046
1047 /*
1048 * If remote wakeup is not available you may not want to do
1049 * power management.
1050 */
1051 if (usb_handle_remote_wakeup(wusb_cap->wusb_ca_dip,
1052 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
1053 wusb_capm->wusb_ca_remote_wakeup = 1;
1054 } else {
1055 USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1056 "wusb_ca_init_power_mgmt: failure enabling remote wakeup");
1057 }
1058
1059 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1060 "wusb_ca_init_power_mgmt: end");
1061 }
1062
1063
1064 /*
1065 * wusb_ca_destroy_power_mgmt:
1066 * Shut down and destroy power management and remote wakeup functionality.
1067 */
1068 static void
wusb_ca_destroy_power_mgmt(wusb_ca_state_t * wusb_cap)1069 wusb_ca_destroy_power_mgmt(wusb_ca_state_t *wusb_cap)
1070 {
1071 wusb_ca_power_t *wusb_capm;
1072
1073 USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1074 "destroy_power_mgmt enter");
1075
1076 ASSERT(!mutex_owned(&wusb_cap->wusb_ca_mutex));
1077
1078 mutex_enter(&wusb_cap->wusb_ca_mutex);
1079
1080 wusb_capm = wusb_cap->wusb_ca_pm;
1081 if (!wusb_capm) {
1082 mutex_exit(&wusb_cap->wusb_ca_mutex);
1083
1084 return;
1085 }
1086
1087 mutex_exit(&wusb_cap->wusb_ca_mutex);
1088
1089 (void) wusb_ca_pm_busy_component(wusb_cap);
1090
1091 mutex_enter(&wusb_cap->wusb_ca_mutex);
1092 if (wusb_cap->wusb_ca_dev_state != USB_DEV_DISCONNECTED) {
1093 int rval;
1094
1095 if (wusb_capm->wusb_ca_remote_wakeup) {
1096 mutex_exit(&wusb_cap->wusb_ca_mutex);
1097
1098 (void) pm_raise_power(wusb_cap->wusb_ca_dip, 0,
1099 USB_DEV_OS_FULL_PWR);
1100
1101 rval = usb_handle_remote_wakeup(
1102 wusb_cap->wusb_ca_dip,
1103 USB_REMOTE_WAKEUP_DISABLE);
1104
1105 USB_DPRINTF_L2(PRINT_MASK_PM,
1106 wusb_cap->wusb_ca_log_hdl,
1107 "wusb_ca_destroy_power_mgmt: "
1108 "Error disabling rmt wakeup: rval = %d",
1109 rval);
1110
1111 mutex_enter(&wusb_cap->wusb_ca_mutex);
1112 }
1113 }
1114
1115 mutex_exit(&wusb_cap->wusb_ca_mutex);
1116
1117 /*
1118 * Since remote wakeup is disabled now,
1119 * no one can raise power
1120 * and get to device once power is lowered here.
1121 */
1122 (void) pm_lower_power(wusb_cap->wusb_ca_dip, 0, USB_DEV_OS_PWR_OFF);
1123 wusb_ca_pm_idle_component(wusb_cap);
1124
1125 mutex_enter(&wusb_cap->wusb_ca_mutex);
1126 kmem_free(wusb_cap->wusb_ca_pm, sizeof (wusb_ca_power_t));
1127 wusb_cap->wusb_ca_pm = NULL;
1128 mutex_exit(&wusb_cap->wusb_ca_mutex);
1129 }
1130
1131
1132 /*
1133 * wusb_ca_serialize_access:
1134 * Get the serial synchronization object before returning.
1135 *
1136 * Arguments:
1137 * wusb_cap - Pointer to wusb_ca state structure
1138 * waitsig - Set to:
1139 * WUSB_CA_SER_SIG - to wait such that a signal can interrupt
1140 * WUSB_CA_SER_NOSIG - to wait such that a signal cannot interrupt
1141 */
1142 static int
wusb_ca_serialize_access(wusb_ca_state_t * wusb_cap,boolean_t waitsig)1143 wusb_ca_serialize_access(wusb_ca_state_t *wusb_cap, boolean_t waitsig)
1144 {
1145 int rval = 1;
1146
1147 ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
1148
1149 while (wusb_cap->wusb_ca_serial_inuse) {
1150 if (waitsig == WUSB_CA_SER_SIG) {
1151 rval = cv_wait_sig(&wusb_cap->wusb_ca_serial_cv,
1152 &wusb_cap->wusb_ca_mutex);
1153 } else {
1154 cv_wait(&wusb_cap->wusb_ca_serial_cv,
1155 &wusb_cap->wusb_ca_mutex);
1156 }
1157 }
1158 wusb_cap->wusb_ca_serial_inuse = B_TRUE;
1159
1160 return (rval);
1161 }
1162
1163
1164 /*
1165 * wusb_ca_release_access:
1166 * Release the serial synchronization object.
1167 */
1168 static void
wusb_ca_release_access(wusb_ca_state_t * wusb_cap)1169 wusb_ca_release_access(wusb_ca_state_t *wusb_cap)
1170 {
1171 ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
1172 wusb_cap->wusb_ca_serial_inuse = B_FALSE;
1173 cv_broadcast(&wusb_cap->wusb_ca_serial_cv);
1174 }
1175
1176
1177 /*
1178 * wusb_ca_check_same_device:
1179 * Check if the device connected to the port is the same as
1180 * the previous device that was in the port. The previous device is
1181 * represented by the dip on record for the port. Print a message
1182 * if the device is different. Can block.
1183 *
1184 * return values:
1185 * USB_SUCCESS: same device
1186 * USB_INVALID_VERSION not same device
1187 * USB_FAILURE: Failure processing request
1188 */
1189 static int
wusb_ca_check_same_device(wusb_ca_state_t * wusb_cap)1190 wusb_ca_check_same_device(wusb_ca_state_t *wusb_cap)
1191 {
1192 usb_dev_descr_t *orig_usb_dev_descr;
1193 usb_dev_descr_t usb_dev_descr;
1194 mblk_t *pdata = NULL;
1195 int rval;
1196 char *buf;
1197 usb_cr_t completion_reason;
1198 usb_cb_flags_t cb_flags;
1199 boolean_t match = B_TRUE;
1200
1201 usb_ctrl_setup_t setup = {
1202 USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD |
1203 USB_DEV_REQ_RCPT_DEV,
1204 USB_REQ_GET_DESCR, /* bRequest */
1205 USB_DESCR_TYPE_SETUP_DEV, /* wValue */
1206 0, /* wIndex */
1207 USB_DEV_DESCR_SIZE, /* wLength */
1208 0 /* request attributes */
1209 };
1210
1211 ASSERT(!mutex_owned(&wusb_cap->wusb_ca_mutex));
1212
1213 orig_usb_dev_descr = wusb_cap->wusb_ca_reg->dev_descr;
1214
1215 /* get the "new" device descriptor */
1216 rval = usb_pipe_ctrl_xfer_wait(wusb_cap->wusb_ca_reg->dev_default_ph,
1217 &setup, &pdata, &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1218
1219 if (rval != USB_SUCCESS) {
1220 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1221 "wusb_ca_check_same_device: "
1222 "getting device descriptor failed "
1223 "rval=%d, cr=%d, cb=0x%x\n",
1224 rval, completion_reason, cb_flags);
1225 freemsg(pdata);
1226
1227 return (USB_FAILURE);
1228 }
1229
1230 ASSERT(pdata != NULL);
1231
1232 (void) usb_parse_data("2cs4c3s4c", pdata->b_rptr,
1233 (intptr_t)pdata->b_wptr - (intptr_t)pdata->b_rptr, &usb_dev_descr,
1234 sizeof (usb_dev_descr_t));
1235
1236 freemsg(pdata);
1237 pdata = NULL;
1238
1239 /* Always check the device descriptor length. */
1240 if (usb_dev_descr.bLength != USB_DEV_DESCR_SIZE) {
1241 match = B_FALSE;
1242
1243 /* Always check the device descriptor. */
1244 } else if (bcmp(orig_usb_dev_descr,
1245 (char *)&usb_dev_descr, USB_DEV_DESCR_SIZE) != 0) {
1246 match = B_FALSE;
1247 }
1248
1249 /* if requested & this device has a serial number check and compare */
1250 if ((match == B_TRUE) &&
1251 (wusb_cap->wusb_ca_reg->dev_serial != NULL)) {
1252 buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
1253 if (usb_get_string_descr(wusb_cap->wusb_ca_dip, USB_LANG_ID,
1254 usb_dev_descr.iSerialNumber, buf,
1255 USB_MAXSTRINGLEN) == USB_SUCCESS) {
1256 match =
1257 (strcmp(buf,
1258 wusb_cap->wusb_ca_reg->dev_serial) == 0);
1259 }
1260 kmem_free(buf, USB_MAXSTRINGLEN);
1261 }
1262
1263 if (match == B_FALSE) {
1264 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1265 "Device is not identical to the "
1266 "previous one this port.\n"
1267 "Please disconnect and reconnect");
1268
1269 return (USB_INVALID_VERSION);
1270 }
1271
1272 return (USB_SUCCESS);
1273 }
1274
1275
1276 /* get association info */
1277 int
wusb_cbaf_get_asso_info(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1278 wusb_cbaf_get_asso_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1279 {
1280 usb_pipe_handle_t pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1281 usb_ctrl_setup_t setup;
1282 usb_cr_t completion_reason;
1283 usb_cb_flags_t cb_flags;
1284 wusb_cbaf_asso_info_t ca_info;
1285 mblk_t *pdata = NULL;
1286 int rval;
1287
1288 setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1289 USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1290 setup.bRequest = WUSB_CBAF_GET_ASSOCIATION_INFORMATION;
1291 setup.wValue = 0;
1292 setup.wIndex = 0;
1293 setup.wLength = WUSB_ASSO_INFO_SIZE;
1294 setup.attrs = USB_ATTRS_NONE;
1295
1296 rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1297 &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1298
1299 if (rval != USB_SUCCESS) {
1300 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1301 "cr = %d cb_flags = %d", completion_reason, cb_flags);
1302
1303 return (EIO);
1304 }
1305 if (pdata == NULL || msgsize(pdata) == 0) {
1306 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1307 "empty pdata");
1308
1309 return (EIO);
1310 }
1311
1312 rval = usb_parse_data("scs", pdata->b_rptr, WUSB_ASSO_INFO_SIZE,
1313 &ca_info, sizeof (ca_info));
1314 if (rval <= 0) {
1315 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1316 "parse data");
1317
1318 return (EIO);
1319 }
1320
1321 rval = ddi_copyout(&ca_info, (void *)arg, sizeof (ca_info), flag);
1322 if (rval != 0) {
1323 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1324 "ddi_copyout");
1325
1326 return (EIO);
1327 }
1328
1329 freemsg(pdata);
1330
1331 return (0);
1332 }
1333
1334 /* get request array */
1335 int
wusb_cbaf_get_asso_reqs(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1336 wusb_cbaf_get_asso_reqs(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1337 {
1338 usb_pipe_handle_t pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1339 usb_ctrl_setup_t setup;
1340 usb_cr_t completion_reason;
1341 usb_cb_flags_t cb_flags;
1342 wusb_cbaf_asso_info_t ca_info;
1343 wusb_cbaf_asso_req_t *ca_reqs;
1344 mblk_t *pdata = NULL;
1345 uchar_t *data;
1346 int rval, reqs_size, i;
1347
1348 rval = ddi_copyin((void *)arg, &ca_info, sizeof (ca_info), flag);
1349 if (rval != 0) {
1350 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1351 "ddi_copyin");
1352
1353 return (EIO);
1354 }
1355
1356 setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1357 USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1358 setup.bRequest = WUSB_CBAF_GET_ASSOCIATION_INFORMATION;
1359 setup.wValue = 0;
1360 setup.wIndex = 0;
1361 setup.wLength = ca_info.Length;
1362 setup.attrs = USB_ATTRS_NONE;
1363
1364 rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1365 &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1366
1367 if (rval != USB_SUCCESS) {
1368 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1369 "cr = %d cb_flags = %d", completion_reason, cb_flags);
1370
1371 return (EIO);
1372 }
1373 if (pdata == NULL || msgsize(pdata) == 0) {
1374 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1375 "empty pdata");
1376
1377 return (EIO);
1378 }
1379
1380 reqs_size = sizeof (wusb_cbaf_asso_req_t) *
1381 ca_info.NumAssociationRequests;
1382 ca_reqs = (wusb_cbaf_asso_req_t *)kmem_zalloc(reqs_size, KM_SLEEP);
1383
1384 data = pdata->b_rptr + WUSB_ASSO_INFO_SIZE;
1385 for (i = 0; i < ca_info.NumAssociationRequests; i++) {
1386 rval = usb_parse_data("ccssl", data, WUSB_ASSO_REQUEST_SIZE,
1387 &(ca_reqs[i]), sizeof (wusb_cbaf_asso_req_t));
1388 if (rval <= 0) {
1389 USB_DPRINTF_L2(PRINT_MASK_ALL,
1390 wusb_cap->wusb_ca_log_hdl,
1391 "parse data");
1392
1393 return (EIO);
1394 }
1395 data += WUSB_ASSO_REQUEST_SIZE;
1396 }
1397
1398 rval = ddi_copyout(ca_reqs, (void *)(arg + sizeof (ca_info)),
1399 reqs_size, flag);
1400 if (rval != 0) {
1401 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1402 "ddi_copyout");
1403
1404 return (EIO);
1405 }
1406
1407 freemsg(pdata);
1408 kmem_free(ca_reqs, reqs_size);
1409
1410 return (0);
1411 }
1412
1413 /* set host info */
1414 int
wusb_cbaf_set_host_info(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1415 wusb_cbaf_set_host_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1416 {
1417 usb_pipe_handle_t pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1418 usb_ctrl_setup_t setup;
1419 usb_cr_t completion_reason;
1420 usb_cb_flags_t cb_flags;
1421 wusb_cbaf_host_info_t host_info;
1422 mblk_t *pdata;
1423 int rval;
1424
1425 rval = ddi_copyin((void *)arg, &host_info, sizeof (host_info), flag);
1426 if (rval != 0) {
1427 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1428 "ddi_copyin");
1429
1430 return (EIO);
1431 }
1432
1433 if ((pdata = trans_from_host_info(&host_info)) == NULL) {
1434 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1435 "trans host info");
1436
1437 return (EIO);
1438 }
1439
1440 setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1441 setup.bRequest = WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1442 setup.wValue = 0x101;
1443 setup.wIndex = 0;
1444 setup.wLength = WUSB_HOST_INFO_SIZE;
1445 setup.attrs = USB_ATTRS_NONE;
1446
1447 rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1448 &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1449
1450 freemsg(pdata);
1451
1452 if (rval != USB_SUCCESS) {
1453 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1454 "cr = %d cb_flags = 0x%03x", completion_reason, cb_flags);
1455
1456 return (EIO);
1457 }
1458
1459 return (0);
1460 }
1461
1462 /* get device info */
1463 int
wusb_cbaf_get_device_info(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1464 wusb_cbaf_get_device_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1465 {
1466 usb_pipe_handle_t pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1467 usb_ctrl_setup_t setup;
1468 usb_cr_t completion_reason;
1469 usb_cb_flags_t cb_flags;
1470 wusb_cbaf_device_info_t device_info;
1471 mblk_t *pdata = NULL;
1472 int rval;
1473
1474 setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1475 USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1476 setup.bRequest = WUSB_CBAF_GET_ASSOCIATION_REQUEST;
1477 setup.wValue = 0x200;
1478 setup.wIndex = 0;
1479 setup.wLength = WUSB_DEVICE_INFO_SIZE;
1480 setup.attrs = USB_ATTRS_NONE;
1481
1482 rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1483 &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1484
1485 if (rval != USB_SUCCESS) {
1486 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1487 "cr = %d cb_flags = %d", completion_reason, cb_flags);
1488
1489 return (EIO);
1490 }
1491 if (pdata == NULL || msgsize(pdata) == 0) {
1492 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1493 "empty pdata");
1494
1495 return (EIO);
1496 }
1497
1498 if (trans_to_device_info(wusb_cap, pdata, &device_info) != 0) {
1499 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1500 "trans to device_info");
1501
1502 return (EIO);
1503 }
1504
1505 rval = ddi_copyout(&device_info, (void *)arg,
1506 sizeof (device_info), flag);
1507 if (rval != 0) {
1508 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1509 "ddi_copyout");
1510
1511 return (EIO);
1512 }
1513
1514 freemsg(pdata);
1515
1516 return (0);
1517 }
1518
1519 /* set connection to device */
1520 int
wusb_cbaf_set_connection(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1521 wusb_cbaf_set_connection(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1522 {
1523 usb_pipe_handle_t pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1524 usb_ctrl_setup_t setup;
1525 usb_cr_t completion_reason;
1526 usb_cb_flags_t cb_flags;
1527 wusb_cbaf_cc_data_t cc_data;
1528 mblk_t *pdata = NULL;
1529 int rval;
1530
1531 rval = ddi_copyin((void *)arg, &cc_data, sizeof (cc_data), flag);
1532 if (rval != 0) {
1533 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1534 "ddi_copyin");
1535
1536 return (EIO);
1537 }
1538
1539 if ((pdata = trans_from_cc_data(&cc_data)) == NULL) {
1540 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1541 "trans cc data");
1542
1543 return (EIO);
1544 }
1545
1546 setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1547 setup.bRequest = WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1548 setup.wValue = 0x201;
1549 setup.wIndex = 0;
1550 setup.wLength = WUSB_CC_DATA_SIZE;
1551 setup.attrs = USB_ATTRS_NONE;
1552
1553 rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1554 &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1555
1556 freemsg(pdata);
1557
1558 if (rval != USB_SUCCESS) {
1559 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1560 "cr = %d cb_flags = %d", completion_reason, cb_flags);
1561
1562 return (EIO);
1563 }
1564
1565 return (0);
1566 }
1567
1568 /* set failure */
1569 int
wusb_cbaf_set_failure(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1570 wusb_cbaf_set_failure(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1571 {
1572 usb_pipe_handle_t pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1573 usb_ctrl_setup_t setup;
1574 usb_cr_t completion_reason;
1575 usb_cb_flags_t cb_flags;
1576 wusb_cbaf_cc_fail_t cc_fail;
1577 mblk_t *pdata = NULL;
1578 int rval;
1579
1580 rval = ddi_copyin((void *)arg, &cc_fail, sizeof (cc_fail), flag);
1581 if (rval != 0) {
1582 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1583 "ddi_copyin");
1584
1585 return (EIO);
1586 }
1587
1588 if ((pdata = trans_from_cc_fail(&cc_fail)) == NULL) {
1589 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1590 "trans cc fail");
1591
1592 return (EIO);
1593 }
1594
1595 setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1596 setup.bRequest = WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1597 setup.wValue = 0x201;
1598 setup.wIndex = 0;
1599 setup.wLength = WUSB_CC_DATA_SIZE;
1600 setup.attrs = USB_ATTRS_NONE;
1601
1602 rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1603 &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1604
1605 freemsg(pdata);
1606
1607 if (rval != USB_SUCCESS) {
1608 USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1609 "cr = %d cb_flags = %d", completion_reason, cb_flags);
1610
1611 return (EIO);
1612 }
1613
1614 return (0);
1615 }
1616
1617 #define DRAW_BYTE(x, sh) (((x) >> (sh * 8)) & 0xff)
1618
1619 static mblk_t *
trans_from_host_info(wusb_cbaf_host_info_t * host_info)1620 trans_from_host_info(wusb_cbaf_host_info_t *host_info)
1621 {
1622 mblk_t *pdata;
1623
1624 if ((pdata = allocb(WUSB_HOST_INFO_SIZE, BPRI_HI)) == NULL) {
1625
1626 return (NULL);
1627 }
1628
1629 bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1630 pdata->b_wptr += 4;
1631 *pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationTypeId, 0);
1632 *pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationTypeId, 1);
1633
1634 bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1635 pdata->b_wptr += 4;
1636 *pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationSubTypeId, 0);
1637 *pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationSubTypeId, 1);
1638
1639 bcopy(fieldCHID, pdata->b_wptr, 4);
1640 pdata->b_wptr += 4;
1641 bcopy(host_info->CHID, pdata->b_wptr, 16);
1642 pdata->b_wptr += 16;
1643
1644 bcopy(fieldLangID, pdata->b_wptr, 4);
1645 pdata->b_wptr += 4;
1646 *pdata->b_wptr++ = DRAW_BYTE(host_info->LangID, 0);
1647 *pdata->b_wptr++ = DRAW_BYTE(host_info->LangID, 1);
1648
1649 bcopy(fieldHostFriendlyName, pdata->b_wptr, 4);
1650 pdata->b_wptr += 4;
1651 bcopy(host_info->HostFriendlyName, pdata->b_wptr, 64);
1652 pdata->b_wptr += 64;
1653
1654 return (pdata);
1655 }
1656
1657 static mblk_t *
trans_from_cc_data(wusb_cbaf_cc_data_t * cc_data)1658 trans_from_cc_data(wusb_cbaf_cc_data_t *cc_data)
1659 {
1660 mblk_t *pdata;
1661
1662 if ((pdata = allocb(WUSB_CC_DATA_SIZE, BPRI_HI)) == NULL) {
1663
1664 return (NULL);
1665 }
1666
1667 bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1668 pdata->b_wptr += 4;
1669 *pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationTypeId, 0);
1670 *pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationTypeId, 1);
1671
1672 bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1673 pdata->b_wptr += 4;
1674 *pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationSubTypeId, 0);
1675 *pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationSubTypeId, 1);
1676
1677 bcopy(fieldLength, pdata->b_wptr, 4);
1678 pdata->b_wptr += 4;
1679 *pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 0);
1680 *pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 1);
1681 *pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 2);
1682 *pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 3);
1683
1684 bcopy(fieldConnectionContext, pdata->b_wptr, 4);
1685 pdata->b_wptr += 4;
1686 bcopy(&(cc_data->CC), pdata->b_wptr, 48);
1687 pdata->b_wptr += 48;
1688
1689 bcopy(fieldBandGroups, pdata->b_wptr, 4);
1690 pdata->b_wptr += 4;
1691 *pdata->b_wptr++ = DRAW_BYTE(cc_data->BandGroups, 0);
1692 *pdata->b_wptr++ = DRAW_BYTE(cc_data->BandGroups, 1);
1693
1694 return (pdata);
1695 }
1696
1697 static mblk_t *
trans_from_cc_fail(wusb_cbaf_cc_fail_t * cc_fail)1698 trans_from_cc_fail(wusb_cbaf_cc_fail_t *cc_fail)
1699 {
1700 mblk_t *pdata;
1701
1702 if ((pdata = allocb(WUSB_CC_FAILURE_SIZE, BPRI_HI)) == NULL) {
1703
1704 return (NULL);
1705 }
1706
1707 bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1708 pdata->b_wptr += 4;
1709 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationTypeId, 0);
1710 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationTypeId, 1);
1711
1712 bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1713 pdata->b_wptr += 4;
1714 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationSubTypeId, 0);
1715 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationSubTypeId, 1);
1716
1717 bcopy(fieldLength, pdata->b_wptr, 4);
1718 pdata->b_wptr += 4;
1719 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 0);
1720 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 1);
1721 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 2);
1722 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 3);
1723
1724 bcopy(fieldAssociationStatus, pdata->b_wptr, 4);
1725 pdata->b_wptr += 4;
1726 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 0);
1727 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 1);
1728 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 2);
1729 *pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 3);
1730
1731 return (pdata);
1732 }
1733
1734 static int
trans_to_device_info(wusb_ca_state_t * wusb_cap,mblk_t * pdata,wusb_cbaf_device_info_t * device_info)1735 trans_to_device_info(wusb_ca_state_t *wusb_cap,
1736 mblk_t *pdata, wusb_cbaf_device_info_t *device_info)
1737 {
1738 int i, plen;
1739 void *paddr;
1740 char *mode;
1741 uchar_t *ptr = (uchar_t *)pdata->b_rptr;
1742 wusb_cbaf_info_item_t item;
1743
1744 for (i = 0; i < 5; i++) {
1745 if (((int)usb_parse_data("ss", ptr, 4, &item,
1746 sizeof (item))) <= 0) {
1747 USB_DPRINTF_L2(PRINT_MASK_ALL,
1748 wusb_cap->wusb_ca_log_hdl,
1749 "parse item[%d] failed", i);
1750
1751 return (-1);
1752 }
1753 ptr += 4;
1754
1755 switch (item.typeID) {
1756 case attrLength:
1757 mode = "l";
1758 paddr = &(device_info->Length);
1759 plen = sizeof (uint32_t);
1760
1761 break;
1762 case attrCDID:
1763 mode = "16c";
1764 paddr = &(device_info->CDID);
1765 plen = 16 * sizeof (uint8_t);
1766
1767 break;
1768 case attrBandGroups:
1769 mode = "s";
1770 paddr = &(device_info->BandGroups);
1771 plen = sizeof (uint16_t);
1772
1773 break;
1774 case attrLangID:
1775 mode = "s";
1776 paddr = &(device_info->LangID);
1777 plen = sizeof (uint16_t);
1778
1779 break;
1780 case attrDeviceFriendlyName:
1781 mode = "l";
1782 paddr = &(device_info->DeviceFriendlyName);
1783 plen = 64 * sizeof (char);
1784
1785 break;
1786 default:
1787 USB_DPRINTF_L2(PRINT_MASK_ALL,
1788 wusb_cap->wusb_ca_log_hdl,
1789 "item[%d]: 0x%04x", i, item.typeID);
1790
1791 return (-1);
1792 }
1793
1794 if (((int)usb_parse_data(mode, ptr, item.length,
1795 paddr, plen)) <= 0) {
1796 USB_DPRINTF_L2(PRINT_MASK_ALL,
1797 wusb_cap->wusb_ca_log_hdl,
1798 "item[%d]: 0x%04x", i, item.typeID);
1799
1800 return (-1);
1801 }
1802 ptr += item.length;
1803 }
1804
1805 return (0);
1806 }
1807