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 * Audio Streams Interface Driver:
28 *
29 * usb_as is responsible for (1) Processing audio data messages during
30 * play and record and management of isoc pipe, (2) Selecting correct
31 * alternate that matches a set of parameters and management of control pipe.
32 * This driver is opened by usb_ac and interacts with usb_ac synchronously
33 * using ioctls. If the processing involves an async USBA command, the ioctl
34 * returns after completion of the command.
35 *
36 * Note: When there is a play/record, usb_as calls framework routines
37 * directly for data (play) or sends data to mixer (record).
38 *
39 * Serialization: A competing thread can't be allowed to interfere with
40 * (1) pipe, (2) streams state.
41 * So we need some kind of serialization among the asynchronous
42 * threads that can run in the driver. The serialization is mostly
43 * needed to avoid races among open/close/events/power entry points
44 * etc. Once a routine grabs access, if checks if the resource (pipe or
45 * stream or dev state) is still accessible. If so, it proceeds with
46 * its job and until it completes, no other thread requiring the same
47 * resource can run.
48 *
49 * PM Model in usb_as: Raise power during attach and lower power in detach.
50 * If device is not fully powered, synchronous raise power in wsrv entry points.
51 */
52 #include <sys/usb/usba/usbai_version.h>
53 #include <sys/usb/usba.h>
54 #include <sys/ddi.h>
55 #include <sys/sunddi.h>
56
57 #include <sys/audio/audio_driver.h>
58
59 #include <sys/usb/clients/audio/usb_audio.h>
60 #include <sys/usb/clients/audio/usb_mixer.h>
61 #include <sys/usb/clients/audio/usb_as/usb_as.h>
62 #include <sys/usb/clients/audio/usb_ac/usb_ac.h>
63
64
65 /* debug support */
66 uint_t usb_as_errlevel = USB_LOG_L4;
67 uint_t usb_as_errmask = (uint_t)-1;
68 uint_t usb_as_instance_debug = (uint_t)-1;
69
70 /*
71 * Module linkage routines for the kernel
72 */
73 static int usb_as_attach(dev_info_t *, ddi_attach_cmd_t);
74 static int usb_as_detach(dev_info_t *, ddi_detach_cmd_t);
75 static int usb_as_power(dev_info_t *, int, int);
76 static int usb_as_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
77
78 static int usb_as_open(dev_t *, int, int, cred_t *);
79 static int usb_as_close(dev_t, int, int, cred_t *);
80
81
82 /* support functions */
83 static void usb_as_cleanup(dev_info_t *, usb_as_state_t *);
84
85 static int usb_as_handle_descriptors(usb_as_state_t *);
86 static void usb_as_prepare_registration_data(usb_as_state_t *);
87 static int usb_as_valid_format(usb_as_state_t *, uint_t);
88 static void usb_as_free_alts(usb_as_state_t *);
89
90 static void usb_as_create_pm_components(dev_info_t *, usb_as_state_t *);
91 static int usb_as_disconnect_event_cb(dev_info_t *);
92 static int usb_as_reconnect_event_cb(dev_info_t *);
93 static int usb_as_cpr_suspend(dev_info_t *);
94 static void usb_as_cpr_resume(dev_info_t *);
95
96 static int usb_as_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
97
98 static int usb_as_pwrlvl0(usb_as_state_t *);
99 static int usb_as_pwrlvl1(usb_as_state_t *);
100 static int usb_as_pwrlvl2(usb_as_state_t *);
101 static int usb_as_pwrlvl3(usb_as_state_t *);
102 static void usb_as_pm_busy_component(usb_as_state_t *);
103 static void usb_as_pm_idle_component(usb_as_state_t *);
104
105 static void usb_as_restore_device_state(dev_info_t *, usb_as_state_t *);
106 static int usb_as_setup(usb_as_state_t *);
107 static void usb_as_teardown(usb_as_state_t *);
108 static int usb_as_start_play(usb_as_state_t *, usb_audio_play_req_t *);
109 static void usb_as_continue_play(usb_as_state_t *);
110 static void usb_as_pause_play(usb_as_state_t *);
111
112 static int usb_as_set_format(usb_as_state_t *, usb_audio_formats_t *);
113 static int usb_as_set_sample_freq(usb_as_state_t *, int);
114 static int usb_as_send_ctrl_cmd(usb_as_state_t *, uchar_t, uchar_t,
115 ushort_t, ushort_t, ushort_t, mblk_t *, boolean_t);
116
117 static int usb_as_start_record(usb_as_state_t *, void *);
118 static int usb_as_stop_record(usb_as_state_t *);
119 static void usb_as_play_cb(usb_pipe_handle_t, usb_isoc_req_t *);
120 static void usb_as_record_cb(usb_pipe_handle_t, usb_isoc_req_t *);
121 static void usb_as_play_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *);
122 static void usb_as_record_exc_cb(usb_pipe_handle_t, usb_isoc_req_t *);
123 static int usb_as_get_pktsize(usb_as_state_t *, usb_frame_number_t);
124 static void usb_as_handle_shutdown(usb_as_state_t *);
125 static int usb_as_play_isoc_data(usb_as_state_t *,
126 usb_audio_play_req_t *);
127
128 /* anchor for soft state structures */
129 static void *usb_as_statep;
130
131
132 /*
133 * DDI Structures
134 */
135
136 /* Entry points structure */
137 static struct cb_ops usb_as_cb_ops = {
138 usb_as_open, /* cb_open */
139 usb_as_close, /* cb_close */
140 nodev, /* cb_strategy */
141 nodev, /* cb_print */
142 nodev, /* cb_dump */
143 nodev, /* cb_read */
144 nodev, /* cb_write */
145 usb_as_ioctl, /* cb_ioctl */
146 nodev, /* cb_devmap */
147 nodev, /* cb_mmap */
148 nodev, /* cb_segmap */
149 nochpoll, /* cb_chpoll */
150 ddi_prop_op, /* cb_prop_op */
151 NULL, /* cb_str */
152 D_MP | D_64BIT, /* cb_flag */
153 CB_REV, /* cb_rev */
154 nodev, /* cb_aread */
155 nodev, /* cb_arwite */
156 };
157
158 /* Device operations structure */
159 static struct dev_ops usb_as_dev_ops = {
160 DEVO_REV, /* devo_rev */
161 0, /* devo_refcnt */
162 usb_as_getinfo, /* devo_getinfo */
163 nulldev, /* devo_identify - obsolete */
164 nulldev, /* devo_probe - not needed */
165 usb_as_attach, /* devo_attach */
166 usb_as_detach, /* devo_detach */
167 nodev, /* devo_reset */
168 &usb_as_cb_ops, /* devi_cb_ops */
169 NULL, /* devo_busb_as_ops */
170 usb_as_power, /* devo_power */
171 ddi_quiesce_not_needed, /* devo_quiesce */
172 };
173
174 /* Linkage structure for loadable drivers */
175 static struct modldrv usb_as_modldrv = {
176 &mod_driverops, /* drv_modops */
177 "USB Audio Streaming Driver", /* drv_linkinfo */
178 &usb_as_dev_ops /* drv_dev_ops */
179 };
180
181 /* Module linkage structure */
182 static struct modlinkage usb_as_modlinkage = {
183 MODREV_1, /* ml_rev */
184 (void *)&usb_as_modldrv, /* ml_linkage */
185 NULL /* NULL terminates the list */
186 };
187
188
189 static usb_event_t usb_as_events = {
190 usb_as_disconnect_event_cb,
191 usb_as_reconnect_event_cb,
192 NULL, NULL
193 };
194
195 /*
196 * Mixer registration Management
197 * use defaults as much as possible
198 */
199
200 _NOTE(SCHEME_PROTECTS_DATA("unique per call", mblk_t))
201 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_isoc_req_t))
202 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_isoc_pkt_descr))
203
204 int
_init(void)205 _init(void)
206 {
207 int rval;
208
209 /* initialize the soft state */
210 if ((rval = ddi_soft_state_init(&usb_as_statep,
211 sizeof (usb_as_state_t), 1)) != DDI_SUCCESS) {
212
213 return (rval);
214 }
215
216 if ((rval = mod_install(&usb_as_modlinkage)) != 0) {
217 ddi_soft_state_fini(&usb_as_statep);
218 }
219
220 return (rval);
221 }
222
223
224 int
_fini(void)225 _fini(void)
226 {
227 int rval;
228
229 if ((rval = mod_remove(&usb_as_modlinkage)) == 0) {
230 /* Free the soft state internal structures */
231 ddi_soft_state_fini(&usb_as_statep);
232 }
233
234 return (rval);
235 }
236
237
238 int
_info(struct modinfo * modinfop)239 _info(struct modinfo *modinfop)
240 {
241 return (mod_info(&usb_as_modlinkage, modinfop));
242 }
243
244
245 /*ARGSUSED*/
246 static int
usb_as_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)247 usb_as_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
248 void *arg, void **result)
249 {
250 usb_as_state_t *uasp = NULL;
251 int error = DDI_FAILURE;
252 int instance = USB_AS_MINOR_TO_INSTANCE(
253 getminor((dev_t)arg));
254
255 switch (infocmd) {
256 case DDI_INFO_DEVT2DEVINFO:
257
258 if ((uasp = ddi_get_soft_state(usb_as_statep,
259 instance)) != NULL) {
260 *result = uasp->usb_as_dip;
261 if (*result != NULL) {
262 error = DDI_SUCCESS;
263 }
264 } else {
265 *result = NULL;
266 }
267 break;
268 case DDI_INFO_DEVT2INSTANCE:
269 *result = (void *)(uintptr_t)instance;
270 error = DDI_SUCCESS;
271 break;
272 default:
273 break;
274 }
275
276 return (error);
277 }
278
279
280 static int
usb_as_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)281 usb_as_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
282 {
283 int instance = ddi_get_instance(dip);
284 usb_as_state_t *uasp;
285
286 switch (cmd) {
287 case DDI_ATTACH:
288
289 break;
290 case DDI_RESUME:
291 usb_as_cpr_resume(dip);
292
293 return (DDI_SUCCESS);
294 default:
295
296 return (DDI_FAILURE);
297 }
298
299 /*
300 * Allocate soft state information.
301 */
302 if (ddi_soft_state_zalloc(usb_as_statep, instance) != DDI_SUCCESS) {
303
304 return (DDI_FAILURE);
305 }
306
307 /*
308 * get soft state space and initialize
309 */
310 uasp = (usb_as_state_t *)ddi_get_soft_state(usb_as_statep, instance);
311 if (uasp == NULL) {
312
313 return (DDI_FAILURE);
314 }
315
316 uasp->usb_as_log_handle = usb_alloc_log_hdl(dip, "as",
317 &usb_as_errlevel,
318 &usb_as_errmask, &usb_as_instance_debug, 0);
319
320 uasp->usb_as_instance = instance;
321 uasp->usb_as_dip = dip;
322
323 (void) snprintf(uasp->dstr, sizeof (uasp->dstr), "%s#%d",
324 ddi_driver_name(dip), instance);
325
326 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
327 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
328 "usb_client_attach failed");
329
330 usb_free_log_hdl(uasp->usb_as_log_handle);
331 ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance);
332
333 return (DDI_FAILURE);
334 }
335
336 if (usb_get_dev_data(dip, &uasp->usb_as_dev_data,
337 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
338 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
339 "usb_get_dev_data failed");
340 usb_client_detach(dip, NULL);
341 usb_free_log_hdl(uasp->usb_as_log_handle);
342 ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance);
343
344 return (DDI_FAILURE);
345 }
346
347 /* initialize mutex */
348 mutex_init(&uasp->usb_as_mutex, NULL, MUTEX_DRIVER,
349 uasp->usb_as_dev_data->dev_iblock_cookie);
350
351 cv_init(&uasp->usb_as_pipe_cv, NULL, CV_DRIVER, NULL);
352
353 uasp->usb_as_ser_acc = usb_init_serialization(dip,
354 USB_INIT_SER_CHECK_SAME_THREAD);
355
356 uasp->usb_as_default_ph = uasp->usb_as_dev_data->dev_default_ph;
357 uasp->usb_as_isoc_pp.pp_max_async_reqs = 1;
358
359 /* parse all descriptors */
360 if (usb_as_handle_descriptors(uasp) != USB_SUCCESS) {
361
362 goto fail;
363 }
364
365 usb_free_descr_tree(dip, uasp->usb_as_dev_data);
366
367 if ((ddi_create_minor_node(dip, "usb_as", S_IFCHR,
368 USB_AS_CONSTRUCT_MINOR(instance),
369 NULL, 0)) != DDI_SUCCESS) {
370 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
371 "usb_as_attach: couldn't create minor node");
372
373 goto fail;
374 }
375
376 /* we are online */
377 uasp->usb_as_dev_state = USB_DEV_ONLINE;
378
379 /* create components to power manage this device */
380 usb_as_create_pm_components(dip, uasp);
381
382 /* Register for events */
383 if (usb_register_event_cbs(dip, &usb_as_events, 0) != USB_SUCCESS) {
384 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
385 "usb_as_attach: couldn't register for events");
386
387 goto fail;
388 }
389
390 /* report device */
391 ddi_report_dev(dip);
392
393 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
394 "usb_as_attach: End");
395
396 return (DDI_SUCCESS);
397
398 fail:
399 if (uasp) {
400 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
401 "attach failed");
402 usb_as_cleanup(dip, uasp);
403 }
404
405 return (DDI_FAILURE);
406 }
407
408
409 /*ARGSUSED*/
410 static int
usb_as_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)411 usb_as_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
412 {
413 int instance = ddi_get_instance(dip);
414 usb_as_state_t *uasp;
415 int rval;
416
417 uasp = ddi_get_soft_state(usb_as_statep, instance);
418
419 switch (cmd) {
420 case DDI_DETACH:
421 usb_as_cleanup(dip, uasp);
422
423 return (DDI_SUCCESS);
424 case DDI_SUSPEND:
425 rval = usb_as_cpr_suspend(dip);
426
427 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
428 default:
429
430 return (DDI_FAILURE);
431 }
432 }
433
434
435 static void
usb_as_cleanup(dev_info_t * dip,usb_as_state_t * uasp)436 usb_as_cleanup(dev_info_t *dip, usb_as_state_t *uasp)
437 {
438 usb_as_power_t *uaspm;
439
440 if (uasp == NULL) {
441
442 return;
443 }
444
445 uaspm = uasp->usb_as_pm;
446
447 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
448 "usb_as_cleanup: uaspm=0x%p", (void *)uaspm);
449
450 if (uasp->usb_as_isoc_ph) {
451 usb_pipe_close(dip, uasp->usb_as_isoc_ph,
452 USB_FLAGS_SLEEP, NULL, NULL);
453 }
454 /*
455 * Disable the event callbacks first, after this point, event
456 * callbacks will never get called. Note we shouldn't hold
457 * mutex while unregistering events because there may be a
458 * competing event callback thread. Event callbacks are done
459 * with ndi mutex held and this can cause a potential deadlock.
460 */
461 usb_unregister_event_cbs(dip, &usb_as_events);
462
463 mutex_enter(&uasp->usb_as_mutex);
464
465 if (uaspm && (uasp->usb_as_dev_state != USB_DEV_DISCONNECTED)) {
466 if (uaspm->aspm_wakeup_enabled) {
467 mutex_exit(&uasp->usb_as_mutex);
468
469 /*
470 * We need to raise power first because
471 * we need to send down a command to disable
472 * remote wakeup
473 */
474 usb_as_pm_busy_component(uasp);
475 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
476
477 if (usb_handle_remote_wakeup(dip,
478 USB_REMOTE_WAKEUP_DISABLE)) {
479 USB_DPRINTF_L2(PRINT_MASK_ALL,
480 uasp->usb_as_log_handle,
481 "disable remote wake up failed");
482 }
483 usb_as_pm_idle_component(uasp);
484 } else {
485 mutex_exit(&uasp->usb_as_mutex);
486 }
487
488 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
489
490 mutex_enter(&uasp->usb_as_mutex);
491 }
492
493 if (uaspm) {
494 kmem_free(uaspm, sizeof (usb_as_power_t));
495 uasp->usb_as_pm = NULL;
496 }
497
498 usb_client_detach(dip, uasp->usb_as_dev_data);
499
500 usb_as_free_alts(uasp);
501
502 mutex_exit(&uasp->usb_as_mutex);
503 mutex_destroy(&uasp->usb_as_mutex);
504
505 usb_fini_serialization(uasp->usb_as_ser_acc);
506
507 ddi_remove_minor_node(dip, NULL);
508 usb_free_log_hdl(uasp->usb_as_log_handle);
509 ddi_soft_state_free(usb_as_statep, uasp->usb_as_instance);
510
511 ddi_prop_remove_all(dip);
512 }
513
514
515 /*
516 * usb_as_open:
517 * Open entry point for plumbing only
518 */
519 /*ARGSUSED*/
520 static int
usb_as_open(dev_t * devp,int flag,int otyp,cred_t * credp)521 usb_as_open(dev_t *devp, int flag, int otyp, cred_t *credp)
522 {
523 int inst = USB_AS_MINOR_TO_INSTANCE(getminor(*devp));
524 usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst);
525
526 if (uasp == NULL) {
527
528 return (ENXIO);
529 }
530
531 /* Do mux plumbing stuff */
532 USB_DPRINTF_L4(PRINT_MASK_OPEN, uasp->usb_as_log_handle,
533 "usb_as_open: start");
534
535 mutex_enter(&uasp->usb_as_mutex);
536
537 if (uasp->usb_as_flag == USB_AS_OPEN || credp != kcred) {
538 USB_DPRINTF_L2(PRINT_MASK_OPEN, uasp->usb_as_log_handle,
539 "usb_as_open:multiple opens or opens from userspace"
540 " not supported");
541
542 mutex_exit(&uasp->usb_as_mutex);
543
544 return (ENXIO);
545 }
546
547 /* fail open on a disconnected device */
548 if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) {
549 USB_DPRINTF_L2(PRINT_MASK_OPEN, uasp->usb_as_log_handle,
550 "usb_as_open: disconnected");
551 mutex_exit(&uasp->usb_as_mutex);
552
553 return (ENODEV);
554 }
555
556 /* Initialize state */
557 uasp->usb_as_flag = USB_AS_OPEN;
558 mutex_exit(&uasp->usb_as_mutex);
559
560 /*
561 * go to full power, and remain pm_busy till close
562 */
563 usb_as_pm_busy_component(uasp);
564 (void) pm_raise_power(uasp->usb_as_dip, 0, USB_DEV_OS_FULL_PWR);
565
566 USB_DPRINTF_L4(PRINT_MASK_OPEN, uasp->usb_as_log_handle,
567 "usb_as_open:done");
568
569 return (0);
570 }
571
572
573 /*
574 * usb_as_close:
575 * Close entry point for plumbing
576 */
577 /*ARGSUSED*/
578 static int
usb_as_close(dev_t dev,int flag,int otyp,cred_t * credp)579 usb_as_close(dev_t dev, int flag, int otyp, cred_t *credp)
580 {
581 int inst = USB_AS_MINOR_TO_INSTANCE(getminor(dev));
582 usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst);
583
584 USB_DPRINTF_L4(PRINT_MASK_CLOSE, uasp->usb_as_log_handle,
585 "usb_as_close: inst=%d", inst);
586
587 mutex_enter(&uasp->usb_as_mutex);
588 uasp->usb_as_flag = USB_AS_DISMANTLING;
589 mutex_exit(&uasp->usb_as_mutex);
590
591 /*
592 * Avoid races with other routines.
593 * For example, if a control transfer is going on, wait
594 * for that to be completed
595 * At this point default pipe cannot be open.
596 */
597 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
598
599 usb_release_access(uasp->usb_as_ser_acc);
600
601 /* we can now power down */
602 usb_as_pm_idle_component(uasp);
603
604 mutex_enter(&uasp->usb_as_mutex);
605 uasp->usb_as_flag = 0;
606 mutex_exit(&uasp->usb_as_mutex);
607
608 return (0);
609 }
610
611
612 /*
613 *
614 */
615 /*ARGSUSED*/
616 static int
usb_as_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)617 usb_as_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
618 int *rvalp)
619 {
620 int inst = USB_AS_MINOR_TO_INSTANCE(getminor(dev));
621 usb_as_state_t *uasp = ddi_get_soft_state(usb_as_statep, inst);
622 int rv = USB_SUCCESS;
623
624 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
625 "usb_as_ioctl: Begin inst=%d, cmd=0x%x, arg=0x%p",
626 inst, cmd, (void *)arg);
627
628 if (!(mode & FKIOCTL)) {
629 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
630 "usb_as_ioctl: inst=%d, user space not supported", inst);
631 return (ENXIO);
632 }
633
634 mutex_enter(&uasp->usb_as_mutex);
635
636 switch (cmd) {
637 case USB_AUDIO_MIXER_REGISTRATION:
638 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
639 "usb_as_ioctl(mixer reg): inst=%d", inst);
640
641 /*
642 * Copy the usb_as_reg structure to the structure
643 * that usb_ac passed. Note that this is a structure
644 * assignment and not a pointer assignment!
645 */
646 *(usb_as_registration_t *)arg = uasp->usb_as_reg;
647
648 break;
649 case USB_AUDIO_SET_FORMAT:
650 rv = usb_as_set_format(uasp, (usb_audio_formats_t *)arg);
651 break;
652 case USB_AUDIO_SET_SAMPLE_FREQ:
653 rv = usb_as_set_sample_freq(uasp, *(int *)arg);
654 break;
655 case USB_AUDIO_SETUP:
656 rv = usb_as_setup(uasp);
657 break;
658 case USB_AUDIO_TEARDOWN:
659 usb_as_teardown(uasp);
660 break;
661 case USB_AUDIO_START_PLAY:
662 rv = usb_as_start_play(uasp, (usb_audio_play_req_t *)arg);
663 break;
664 case USB_AUDIO_STOP_PLAY:
665 case USB_AUDIO_PAUSE_PLAY:
666 usb_as_pause_play(uasp);
667 break;
668 case USB_AUDIO_START_RECORD:
669 rv = usb_as_start_record(uasp, (void *)arg);
670 break;
671 case USB_AUDIO_STOP_RECORD:
672 rv = usb_as_stop_record(uasp);
673 break;
674 default:
675 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
676 "usb_as_ioctl: unknown IOCTL, cmd=%d", cmd);
677 break;
678 }
679
680 mutex_exit(&uasp->usb_as_mutex);
681
682 return (rv == USB_SUCCESS ? 0 : ENXIO);
683 }
684
685
686 /*
687 * usb_as_set_sample_freq:
688 * Sets the sample freq by sending a control command to interface
689 * Although not required for continuous sample rate devices, some
690 * devices such as plantronics devices do need this.
691 * On the other hand, the TI chip which does not support continuous
692 * sample rate stalls on this request
693 * Therefore, we ignore errors and carry on regardless
694 */
695 static int
usb_as_set_sample_freq(usb_as_state_t * uasp,int freq)696 usb_as_set_sample_freq(usb_as_state_t *uasp, int freq)
697 {
698 int alt, ep;
699 mblk_t *data;
700 int rval = USB_FAILURE;
701 boolean_t ignore_errors;
702
703 ASSERT(mutex_owned(&uasp->usb_as_mutex));
704
705 alt = uasp->usb_as_alternate;
706
707 uasp->usb_as_curr_sr = freq;
708
709 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
710 "usb_as_set_sample_freq: inst=%d cont_sr=%d freq=%d",
711 ddi_get_instance(uasp->usb_as_dip),
712 uasp->usb_as_alts[alt].alt_continuous_sr, freq);
713
714 ignore_errors = B_TRUE;
715
716 ep = uasp->usb_as_alts[alt].alt_ep->bEndpointAddress;
717
718 data = allocb(4, BPRI_HI);
719 if (data) {
720 *(data->b_wptr++) = (char)freq;
721 *(data->b_wptr++) = (char)(freq >> 8);
722 *(data->b_wptr++) = (char)(freq >> 16);
723
724 mutex_exit(&uasp->usb_as_mutex);
725
726 if ((rval = usb_as_send_ctrl_cmd(uasp,
727 USB_DEV_REQ_HOST_TO_DEV |
728 USB_DEV_REQ_TYPE_CLASS |
729 USB_DEV_REQ_RCPT_EP, /* bmRequestType */
730 USB_AUDIO_SET_CUR, /* bRequest */
731 USB_AUDIO_SAMPLING_FREQ_CONTROL << 8, /* wValue */
732 ep, /* wIndex */
733 3, /* wLength */
734 data,
735 ignore_errors)) != USB_SUCCESS) {
736 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
737 "usb_as_set_sample_freq: set sample freq failed");
738 }
739 mutex_enter(&uasp->usb_as_mutex);
740 }
741 freemsg(data);
742
743 return (rval);
744 }
745
746
747 /*
748 * usb_as_set_format:
749 * Matches channel, encoding and precision and find out
750 * the right alternate. Sets alternate interface and returns it.
751 */
752 static int
usb_as_set_format(usb_as_state_t * uasp,usb_audio_formats_t * format)753 usb_as_set_format(usb_as_state_t *uasp, usb_audio_formats_t *format)
754 {
755 int n;
756 usb_as_registration_t *reg;
757 int alt, rval;
758 uint_t interface;
759
760 ASSERT(mutex_owned(&uasp->usb_as_mutex));
761
762 if (uasp->usb_as_request_count) {
763 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
764 "usb_as_set_format: failing inst=%d, rq_cnt=%d",
765 ddi_get_instance(uasp->usb_as_dip),
766 uasp->usb_as_request_count);
767
768 return (USB_FAILURE);
769 }
770
771 reg = &uasp->usb_as_reg;
772 interface = uasp->usb_as_ifno;
773
774 uasp->usb_as_curr_format = *format;
775
776 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
777 "usb_as_set_format: inst=%d, reg=0x%p, format=0x%p",
778 ddi_get_instance(uasp->usb_as_dip), (void *)reg, (void *)format);
779
780 for (n = 0; n < reg->reg_n_formats; n++) {
781 if ((format->fmt_chns == reg->reg_formats[n].fmt_chns) &&
782 (format->fmt_precision == reg->reg_formats[n].
783 fmt_precision) && (format->fmt_encoding ==
784 reg->reg_formats[n].fmt_encoding)) {
785 int i;
786 int n_srs = reg->reg_formats[n].fmt_n_srs;
787 uint_t *srs = reg->reg_formats[n].fmt_srs;
788
789 /* match sample rate */
790 for (i = 0; i < n_srs; i++) {
791 if (format->fmt_srs[0] == srs[i]) {
792
793 break;
794 }
795 }
796
797 if (i == n_srs) {
798
799 continue;
800 }
801
802 /*
803 * Found the alternate
804 */
805 uasp->usb_as_alternate = alt =
806 reg->reg_formats[n].fmt_alt;
807 break;
808 }
809 }
810
811 if (n >= reg->reg_n_formats) {
812 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
813 "usb_as_set_format: Didn't find a matching alt");
814
815 return (USB_FAILURE);
816 }
817
818
819 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle,
820 "usb_as_set_format: interface=%d alternate=%d",
821 interface, alt);
822
823 mutex_exit(&uasp->usb_as_mutex);
824
825 rval = usb_as_send_ctrl_cmd(uasp,
826 /* bmRequestType */
827 USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
828 USB_REQ_SET_IF, /* bRequest */
829 alt, /* wValue */
830 interface, /* wIndex */
831 0, /* wLength */
832 NULL, B_FALSE);
833
834 mutex_enter(&uasp->usb_as_mutex);
835
836 if (rval != USB_SUCCESS) {
837 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
838 "usb_as_set_format: set_alternate failed");
839 } else {
840 format->fmt_alt = (uchar_t)alt;
841 }
842
843 return (rval);
844 }
845
846
847 /*
848 * usb_as_setup:
849 * Open isoc pipe. Will hang around till bandwidth
850 * is available.
851 */
852 static int
usb_as_setup(usb_as_state_t * uasp)853 usb_as_setup(usb_as_state_t *uasp)
854 {
855 int alt = uasp->usb_as_alternate;
856 usb_ep_descr_t *ep = (usb_ep_descr_t *)uasp->usb_as_alts[alt].alt_ep;
857 int rval;
858
859
860 ASSERT(mutex_owned(&uasp->usb_as_mutex));
861
862 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
863 "usb_as_setup: Begin usb_as_setup, inst=%d",
864 ddi_get_instance(uasp->usb_as_dip));
865
866
867 /* Set record packet size to max packet size */
868 if (uasp->usb_as_alts[alt].alt_mode == USB_AUDIO_RECORD) {
869 uasp->usb_as_record_pkt_size = ep->wMaxPacketSize;
870 } else {
871 uasp->usb_as_record_pkt_size = 0;
872 }
873
874 if (uasp->usb_as_isoc_ph != NULL) {
875 while (uasp->usb_as_request_count) {
876 cv_wait(&uasp->usb_as_pipe_cv,
877 &uasp->usb_as_mutex);
878 }
879
880 /* close the isoc pipe which is opened before */
881 mutex_exit(&uasp->usb_as_mutex);
882 usb_pipe_close(uasp->usb_as_dip, uasp->usb_as_isoc_ph,
883 USB_FLAGS_SLEEP, NULL, (usb_opaque_t)NULL);
884
885 mutex_enter(&uasp->usb_as_mutex);
886 uasp->usb_as_isoc_ph = NULL;
887 }
888
889 ASSERT(uasp->usb_as_request_count == 0);
890 mutex_exit(&uasp->usb_as_mutex);
891
892 /* open isoc pipe, may fail if there is no bandwidth */
893 rval = usb_pipe_open(uasp->usb_as_dip, ep, &uasp->usb_as_isoc_pp,
894 USB_FLAGS_SLEEP, &uasp->usb_as_isoc_ph);
895
896 if (rval != USB_SUCCESS) {
897 switch (rval) {
898 case USB_NO_BANDWIDTH:
899 USB_DPRINTF_L0(PRINT_MASK_ALL, uasp->usb_as_log_handle,
900 "no bandwidth available");
901 break;
902 case USB_NOT_SUPPORTED:
903 USB_DPRINTF_L0(PRINT_MASK_ALL, uasp->usb_as_log_handle,
904 "Operating a full/high speed audio device on a "
905 "high speed port is not supported");
906 break;
907 default:
908 USB_DPRINTF_L2(PRINT_MASK_ALL,
909 uasp->usb_as_log_handle,
910 "usb_as_setup: isoc pipe open failed (%d)",
911 rval);
912 }
913
914 mutex_enter(&uasp->usb_as_mutex);
915
916 return (USB_FAILURE);
917 }
918
919 (void) usb_pipe_set_private(uasp->usb_as_isoc_ph, (usb_opaque_t)uasp);
920
921 mutex_enter(&uasp->usb_as_mutex);
922 uasp->usb_as_audio_state = USB_AS_IDLE;
923 uasp->usb_as_setup_cnt++;
924
925 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
926 "usb_as_setup: End");
927
928 return (USB_SUCCESS);
929 }
930
931
932 /*
933 * usb_as_teardown
934 *
935 */
936 static void
usb_as_teardown(usb_as_state_t * uasp)937 usb_as_teardown(usb_as_state_t *uasp)
938 {
939 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
940 "usb_as_teardown: Begin inst=%d",
941 ddi_get_instance(uasp->usb_as_dip));
942
943 ASSERT(mutex_owned(&uasp->usb_as_mutex));
944
945 uasp->usb_as_audio_state = USB_AS_IDLE;
946
947 ASSERT(uasp->usb_as_isoc_ph);
948 /* reset setup flag */
949 uasp->usb_as_setup_cnt--;
950
951
952 ASSERT(uasp->usb_as_setup_cnt == 0);
953
954 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
955 "usb_as_teardown: End");
956 }
957
958
959 /*
960 * usb_as_start_play
961 */
962 static int
usb_as_start_play(usb_as_state_t * uasp,usb_audio_play_req_t * play_req)963 usb_as_start_play(usb_as_state_t *uasp, usb_audio_play_req_t *play_req)
964 {
965 int n_requests;
966 int rval = USB_FAILURE;
967
968 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
969 "usb_as_start_play: Begin inst=%d, req_cnt=%d",
970 ddi_get_instance(uasp->usb_as_dip), uasp->usb_as_request_count);
971
972 ASSERT(mutex_owned(&uasp->usb_as_mutex));
973
974 uasp->usb_as_request_samples = play_req->up_samples;
975 uasp->usb_as_ahdl = play_req->up_handle;
976 uasp->usb_as_audio_state = USB_AS_ACTIVE;
977
978 if ((uasp->usb_as_request_count >= USB_AS_MAX_REQUEST_COUNT) ||
979 (uasp->usb_as_audio_state == USB_AS_IDLE) ||
980 (uasp->usb_as_audio_state == USB_AS_PLAY_PAUSED)) {
981 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
982 "nothing to do or paused or idle (%d)",
983 uasp->usb_as_audio_state);
984 rval = USB_SUCCESS;
985 } else {
986 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
987 "usb_as_start_play: samples=%d requestcount=%d ",
988 uasp->usb_as_request_samples, uasp->usb_as_request_count);
989
990 /* queue up as many requests as allowed */
991 for (n_requests = uasp->usb_as_request_count;
992 n_requests < USB_AS_MAX_REQUEST_COUNT; n_requests++) {
993 if ((rval = usb_as_play_isoc_data(uasp, play_req)) !=
994 USB_SUCCESS) {
995 break;
996 }
997 }
998 }
999
1000 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1001 "usb_as_start_play: End");
1002
1003 return (rval);
1004 }
1005
1006
1007 /*
1008 * usb_as_continue_play:
1009 * this function is called from the play callbacks
1010 */
1011 static void
usb_as_continue_play(usb_as_state_t * uasp)1012 usb_as_continue_play(usb_as_state_t *uasp)
1013 {
1014 int n_requests;
1015
1016 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1017 "usb_as_contine_play: Begin req_cnt=%d",
1018 uasp->usb_as_request_count);
1019
1020 ASSERT(mutex_owned(&uasp->usb_as_mutex));
1021
1022 if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED) {
1023 usb_as_handle_shutdown(uasp);
1024
1025 return;
1026 }
1027
1028 if ((uasp->usb_as_request_count >= USB_AS_MAX_REQUEST_COUNT) ||
1029 (uasp->usb_as_audio_state == USB_AS_IDLE) ||
1030 (uasp->usb_as_audio_state == USB_AS_PLAY_PAUSED)) {
1031 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1032 "usb_as_continue_play: nothing to do (audio_state=%d)",
1033 uasp->usb_as_audio_state);
1034 } else {
1035 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1036 "usb_as_continue_play: samples=%d requestcount=%d ",
1037 uasp->usb_as_request_samples, uasp->usb_as_request_count);
1038
1039 /* queue up as many requests as allowed */
1040 for (n_requests = uasp->usb_as_request_count;
1041 n_requests < USB_AS_MAX_REQUEST_COUNT; n_requests++) {
1042 if (usb_as_play_isoc_data(uasp, NULL) !=
1043 USB_SUCCESS) {
1044
1045 break;
1046 }
1047 }
1048 }
1049
1050 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1051 "usb_as_continue_play: End");
1052 }
1053
1054
1055 static void
usb_as_handle_shutdown(usb_as_state_t * uasp)1056 usb_as_handle_shutdown(usb_as_state_t *uasp)
1057 {
1058 void *ahdl;
1059
1060 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1061 "usb_as_handle_shutdown, inst=%d",
1062 ddi_get_instance(uasp->usb_as_dip));
1063
1064 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1065 "usb_as_handle_shutdown: am_play_shutdown");
1066
1067 uasp->usb_as_audio_state = USB_AS_IDLE;
1068 uasp->usb_as_pkt_count = 0;
1069 ahdl = uasp->usb_as_ahdl;
1070
1071 mutex_exit(&uasp->usb_as_mutex);
1072 usb_ac_stop_play(ahdl, NULL);
1073 mutex_enter(&uasp->usb_as_mutex);
1074 }
1075
1076
1077 static int
usb_as_play_isoc_data(usb_as_state_t * uasp,usb_audio_play_req_t * play_req)1078 usb_as_play_isoc_data(usb_as_state_t *uasp, usb_audio_play_req_t *play_req)
1079 {
1080 int rval = USB_FAILURE;
1081
1082 usb_isoc_req_t *isoc_req = NULL;
1083 usb_audio_formats_t *format = &uasp->usb_as_curr_format;
1084 mblk_t *data = NULL;
1085 void * ahdl = uasp->usb_as_ahdl;
1086 int precision;
1087 int pkt, frame, n, n_pkts, count;
1088 size_t bufsize;
1089 int pkt_len[USB_AS_N_FRAMES];
1090
1091 ASSERT(mutex_owned(&uasp->usb_as_mutex));
1092
1093 precision = format->fmt_precision >> 3;
1094
1095 frame = uasp->usb_as_pkt_count;
1096
1097 /*
1098 * calculate total bufsize by determining the pkt size for
1099 * each frame
1100 */
1101 for (bufsize = pkt = 0; pkt < USB_AS_N_FRAMES; pkt++) {
1102 pkt_len[pkt] = usb_as_get_pktsize(uasp, frame++);
1103 bufsize += pkt_len[pkt];
1104 }
1105
1106 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1107 "usb_as_play_isoc_data: Begin bufsize=0x%lx, inst=%d", bufsize,
1108 ddi_get_instance(uasp->usb_as_dip));
1109
1110 mutex_exit(&uasp->usb_as_mutex);
1111
1112 if ((data = allocb(bufsize, BPRI_HI)) == NULL) {
1113 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1114 "usb_as_play_isoc_data: allocb failed");
1115 mutex_enter(&uasp->usb_as_mutex);
1116
1117 goto done;
1118 }
1119
1120 /*
1121 * restriction of Boomer: cannot call usb_ac_get_audio() in the context
1122 * of start so we play a fragment of silence at first
1123 */
1124 if (play_req != NULL) {
1125 bzero(data->b_wptr, bufsize);
1126 count = bufsize / precision;
1127
1128 } else if ((count = usb_ac_get_audio(ahdl, (void *)data->b_wptr,
1129 bufsize / precision)) == 0) {
1130 mutex_enter(&uasp->usb_as_mutex);
1131 if (uasp->usb_as_request_count == 0) {
1132 usb_as_handle_shutdown(uasp);
1133
1134 /* Don't return failure for 0 bytes of data sent */
1135 if (play_req) {
1136 /*
1137 * Since we set rval to SUCCESS
1138 * we treat it as a special case
1139 * and free data here
1140 */
1141 rval = USB_SUCCESS;
1142 freemsg(data);
1143 data = NULL;
1144
1145 goto done;
1146 }
1147 } else {
1148 USB_DPRINTF_L2(PRINT_MASK_ALL,
1149 uasp->usb_as_log_handle,
1150 "usb_as_play_isoc_data: no audio bytes, "
1151 "rcnt=0x%x ", uasp->usb_as_request_count);
1152 }
1153 rval = USB_FAILURE;
1154
1155 goto done;
1156 }
1157
1158 bufsize = n = count * precision;
1159 data->b_wptr += n;
1160
1161 /* calculate how many frames we can actually fill */
1162 for (n_pkts = 0; (n_pkts < USB_AS_N_FRAMES) && (n > 0); n_pkts++) {
1163 if (n < pkt_len[n_pkts]) {
1164 pkt_len[n_pkts] = n;
1165 }
1166 n -= pkt_len[n_pkts];
1167 }
1168
1169 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1170 "usb_as_play_isoc_data: n_pkts=%d, bufsize=%ld, n=%d",
1171 n_pkts, bufsize, count * precision);
1172
1173 /* allocate an isoc request packet */
1174 if ((isoc_req = usb_alloc_isoc_req(uasp->usb_as_dip,
1175 n_pkts, 0, 0)) == NULL) {
1176 mutex_enter(&uasp->usb_as_mutex);
1177
1178 goto done;
1179 }
1180
1181
1182
1183 /* initialize the packet descriptor */
1184 for (pkt = 0; pkt < n_pkts; pkt++) {
1185 isoc_req->isoc_pkt_descr[pkt].isoc_pkt_length =
1186 pkt_len[pkt];
1187 }
1188
1189 isoc_req->isoc_data = data;
1190 isoc_req->isoc_pkts_count = (ushort_t)n_pkts;
1191 isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP |
1192 USB_ATTRS_AUTOCLEARING;
1193 isoc_req->isoc_cb = usb_as_play_cb;
1194 isoc_req->isoc_exc_cb = usb_as_play_exc_cb;
1195 isoc_req->isoc_client_private = (usb_opaque_t)uasp;
1196
1197 mutex_enter(&uasp->usb_as_mutex);
1198
1199 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1200 "usb_as_play_isoc_data: rq=0x%p data=0x%p cnt=0x%x "
1201 "pkt=0x%p rqcnt=%d ", (void *)isoc_req, (void *)data, count,
1202 (void *)isoc_req->isoc_pkt_descr, uasp->usb_as_request_count);
1203
1204 ASSERT(isoc_req->isoc_data != NULL);
1205
1206 uasp->usb_as_send_debug_count++;
1207 uasp->usb_as_request_count++;
1208 uasp->usb_as_pkt_count += n_pkts;
1209 mutex_exit(&uasp->usb_as_mutex);
1210
1211 if ((rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph,
1212 isoc_req, 0)) != USB_SUCCESS) {
1213
1214 mutex_enter(&uasp->usb_as_mutex);
1215 uasp->usb_as_request_count--;
1216 cv_signal(&uasp->usb_as_pipe_cv);
1217 uasp->usb_as_send_debug_count--;
1218 uasp->usb_as_pkt_count -= n_pkts;
1219
1220 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1221 "usb_as_play_isoc_data: rval=%d", rval);
1222
1223 rval = USB_FAILURE;
1224
1225 } else {
1226 mutex_enter(&uasp->usb_as_mutex);
1227
1228 data = NULL;
1229 isoc_req = NULL;
1230 }
1231
1232 done:
1233 if (rval != USB_SUCCESS) {
1234 freemsg(data);
1235 if (isoc_req) {
1236 isoc_req->isoc_data = NULL;
1237 usb_free_isoc_req(isoc_req);
1238 }
1239 }
1240
1241 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1242 "usb_as_play_isoc_data: SEND CNT=%d, RCV COUNT=%d",
1243 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count);
1244
1245 return (rval);
1246 }
1247
1248
1249 static void
usb_as_pause_play(usb_as_state_t * uasp)1250 usb_as_pause_play(usb_as_state_t *uasp)
1251 {
1252 ASSERT(mutex_owned(&uasp->usb_as_mutex));
1253
1254 /* this will stop the isoc request in the play callback */
1255 uasp->usb_as_audio_state = USB_AS_PLAY_PAUSED;
1256 }
1257
1258
1259 /*ARGSUSED*/
1260 static void
usb_as_play_cb(usb_pipe_handle_t ph,usb_isoc_req_t * isoc_req)1261 usb_as_play_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req)
1262 {
1263 usb_as_state_t *uasp = (usb_as_state_t *)
1264 (isoc_req->isoc_client_private);
1265 int i;
1266
1267 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
1268 "usb_as_play_cb: Begin ph=0x%p, isoc_req=0x%p",
1269 (void *)ph, (void *)isoc_req);
1270
1271 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0);
1272
1273 for (i = 0; i < isoc_req->isoc_pkts_count; i++) {
1274 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status !=
1275 USB_CR_OK) {
1276 USB_DPRINTF_L2(PRINT_MASK_CB, uasp->usb_as_log_handle,
1277 "usb_as_play_cb: \tpkt%d: len=%d status=%s", i,
1278 isoc_req->isoc_pkt_descr[i].isoc_pkt_length,
1279 usb_str_cr(isoc_req->
1280 isoc_pkt_descr[i].isoc_pkt_status));
1281 }
1282 }
1283
1284 mutex_enter(&uasp->usb_as_mutex);
1285 if (isoc_req->isoc_error_count) {
1286 USB_DPRINTF_L2(PRINT_MASK_CB, uasp->usb_as_log_handle,
1287 "usb_as_play_cb: error_count = %d",
1288 isoc_req->isoc_error_count);
1289 }
1290
1291 usb_free_isoc_req(isoc_req);
1292 uasp->usb_as_request_count--;
1293 cv_signal(&uasp->usb_as_pipe_cv);
1294 uasp->usb_as_rcv_debug_count++;
1295 usb_as_continue_play(uasp);
1296
1297 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
1298 "usb_as_play_cb: SEND CNT=%d, RCV COUNT=%d",
1299 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count);
1300
1301 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
1302 "usb_as_play_cb: End, req_cnt=%d", uasp->usb_as_request_count);
1303
1304 mutex_exit(&uasp->usb_as_mutex);
1305 }
1306
1307
1308 static void
usb_as_play_exc_cb(usb_pipe_handle_t ph,usb_isoc_req_t * isoc_req)1309 usb_as_play_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req)
1310 {
1311 int i;
1312 usb_as_state_t *uasp = (usb_as_state_t *)
1313 (isoc_req->isoc_client_private);
1314 usb_cr_t cr = isoc_req->isoc_completion_reason;
1315 usb_cb_flags_t cb_flags = isoc_req->isoc_cb_flags;
1316
1317 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1318 "usb_as_play_exc_cb: ph=0x%p, rq=0x%p data=0x%p pkts=0x%x "
1319 "cr=%d, cb_flag=0x%x", (void *)ph, (void *)isoc_req,
1320 (void *)isoc_req->isoc_data, isoc_req->isoc_pkts_count,
1321 cr, cb_flags);
1322
1323 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0);
1324
1325 for (i = 0; i < isoc_req->isoc_pkts_count; i++) {
1326 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status ==
1327 USB_CR_OK) {
1328 USB_DPRINTF_L2(PRINT_MASK_ALL,
1329 uasp->usb_as_log_handle,
1330 "usb_as_play_exc_cb: \tpkt%d: len=%d status=%d",
1331 i,
1332 isoc_req->isoc_pkt_descr[i].isoc_pkt_length,
1333 isoc_req->isoc_pkt_descr[i].isoc_pkt_status);
1334 }
1335 }
1336
1337 usb_free_isoc_req(isoc_req);
1338
1339 mutex_enter(&uasp->usb_as_mutex);
1340 uasp->usb_as_rcv_debug_count++;
1341 uasp->usb_as_request_count--;
1342 cv_signal(&uasp->usb_as_pipe_cv);
1343 usb_as_handle_shutdown(uasp);
1344
1345 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1346 "usb_as_play_exc_cb: SEND CNT=%d, RCV COUNT=%d",
1347 uasp->usb_as_send_debug_count, uasp->usb_as_rcv_debug_count);
1348
1349 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1350 "usb_as_play_exc_cb: End request_count=%d",
1351 uasp->usb_as_request_count);
1352
1353 mutex_exit(&uasp->usb_as_mutex);
1354 }
1355
1356
1357 /*
1358 * usb_as_start_record
1359 */
1360 static int
usb_as_start_record(usb_as_state_t * uasp,void * ahdl)1361 usb_as_start_record(usb_as_state_t *uasp, void * ahdl)
1362 {
1363 int rval = USB_FAILURE;
1364 usb_isoc_req_t *isoc_req;
1365 ushort_t record_pkt_size = uasp->usb_as_record_pkt_size;
1366 ushort_t n_pkt = 1, pkt;
1367
1368 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1369 "usb_as_start_record: inst=%d",
1370 ddi_get_instance(uasp->usb_as_dip));
1371
1372 ASSERT(mutex_owned(&uasp->usb_as_mutex));
1373
1374 /*
1375 * A start_record should not happen when stop polling is
1376 * happening
1377 */
1378 ASSERT(uasp->usb_as_audio_state != USB_AS_STOP_POLLING_STARTED);
1379
1380 if (uasp->usb_as_audio_state == USB_AS_IDLE) {
1381
1382 uasp->usb_as_ahdl = ahdl;
1383 uasp->usb_as_audio_state = USB_AS_ACTIVE;
1384 mutex_exit(&uasp->usb_as_mutex);
1385
1386 if ((isoc_req = usb_alloc_isoc_req(uasp->usb_as_dip, n_pkt,
1387 n_pkt * record_pkt_size, 0)) != NULL) {
1388 /* Initialize the packet descriptor */
1389 for (pkt = 0; pkt < n_pkt; pkt++) {
1390 isoc_req->isoc_pkt_descr[pkt].
1391 isoc_pkt_length = record_pkt_size;
1392 }
1393
1394 isoc_req->isoc_pkts_count = n_pkt;
1395 isoc_req->isoc_pkts_length = record_pkt_size;
1396 isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP |
1397 USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
1398 isoc_req->isoc_cb = usb_as_record_cb;
1399 isoc_req->isoc_exc_cb = usb_as_record_exc_cb;
1400 isoc_req->isoc_client_private = (usb_opaque_t)uasp;
1401
1402 rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph,
1403 isoc_req, 0);
1404
1405 } else {
1406 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1407 "usb_as_start_record: Isoc req allocation failed");
1408 }
1409
1410 mutex_enter(&uasp->usb_as_mutex);
1411
1412 } else {
1413
1414 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1415 "usb_as_start_record: Record in progress");
1416
1417 rval = USB_SUCCESS;
1418 }
1419
1420 if (rval != USB_SUCCESS) {
1421 uasp->usb_as_audio_state = USB_AS_IDLE;
1422 if (isoc_req) {
1423 usb_free_isoc_req(isoc_req);
1424 isoc_req = NULL;
1425 }
1426 }
1427
1428 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1429 "usb_as_start_record: rval=%d", rval);
1430
1431 return (rval);
1432 }
1433
1434
1435 static int
usb_as_stop_record(usb_as_state_t * uasp)1436 usb_as_stop_record(usb_as_state_t *uasp)
1437 {
1438 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1439 "usb_as_stop_record: ");
1440 ASSERT(mutex_owned(&uasp->usb_as_mutex));
1441
1442 /* if we are disconnected, the pipe will be closed anyways */
1443 if (uasp->usb_as_dev_state == USB_DEV_DISCONNECTED)
1444 return (USB_SUCCESS);
1445
1446 switch (uasp->usb_as_audio_state) {
1447 case USB_AS_ACTIVE:
1448 mutex_exit(&uasp->usb_as_mutex);
1449
1450 /*
1451 * Stop polling. When the completion reason indicate that
1452 * polling is over, return response message up.
1453 */
1454 usb_pipe_stop_isoc_polling(uasp->usb_as_isoc_ph,
1455 USB_FLAGS_SLEEP);
1456 mutex_enter(&uasp->usb_as_mutex);
1457
1458 break;
1459 case USB_AS_STOP_POLLING_STARTED:
1460 /* A stop polling in progress, wait for completion and reply */
1461 break;
1462 default:
1463 break;
1464 }
1465
1466 return (USB_SUCCESS);
1467 }
1468
1469
1470 static void
usb_as_record_exc_cb(usb_pipe_handle_t ph,usb_isoc_req_t * isoc_req)1471 usb_as_record_exc_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req)
1472 {
1473 usb_as_state_t *uasp = (usb_as_state_t *)
1474 (isoc_req->isoc_client_private);
1475 usb_cr_t completion_reason;
1476 int rval;
1477
1478 completion_reason = isoc_req->isoc_completion_reason;
1479
1480 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1481 "usb_as_record_exc_cb: ph=0x%p, isoc_req=0x%p, cr=%d",
1482 (void *)ph, (void *)isoc_req, completion_reason);
1483
1484 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) == 0);
1485
1486 switch (completion_reason) {
1487 case USB_CR_STOPPED_POLLING:
1488 case USB_CR_PIPE_CLOSING:
1489 case USB_CR_PIPE_RESET:
1490
1491 break;
1492 case USB_CR_NO_RESOURCES:
1493 /*
1494 * keep the show going: Since we have the original
1495 * request, we just resubmit it
1496 */
1497 rval = usb_pipe_isoc_xfer(uasp->usb_as_isoc_ph, isoc_req, 0);
1498
1499 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1500 "usb_as_record_exc_cb: restart record rval=%d", rval);
1501
1502 return;
1503 default:
1504
1505 mutex_enter(&uasp->usb_as_mutex);
1506
1507 /* Do not start if one is already in progress */
1508 if (uasp->usb_as_audio_state != USB_AS_STOP_POLLING_STARTED) {
1509 uasp->usb_as_audio_state = USB_AS_STOP_POLLING_STARTED;
1510
1511 mutex_exit(&uasp->usb_as_mutex);
1512 (void) usb_pipe_stop_isoc_polling(ph,
1513 USB_FLAGS_NOSLEEP);
1514
1515 return;
1516 } else {
1517 mutex_exit(&uasp->usb_as_mutex);
1518 }
1519
1520 break;
1521 }
1522 usb_free_isoc_req(isoc_req);
1523
1524 mutex_enter(&uasp->usb_as_mutex);
1525 USB_DPRINTF_L3(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1526 "usb_as_record_exc_cb: state=%d cr=0x%x",
1527 uasp->usb_as_audio_state, completion_reason);
1528
1529 uasp->usb_as_audio_state = USB_AS_IDLE;
1530 mutex_exit(&uasp->usb_as_mutex);
1531 }
1532
1533
1534 /*ARGSUSED*/
1535 static void
usb_as_record_cb(usb_pipe_handle_t ph,usb_isoc_req_t * isoc_req)1536 usb_as_record_cb(usb_pipe_handle_t ph, usb_isoc_req_t *isoc_req)
1537 {
1538 usb_as_state_t *uasp = (usb_as_state_t *)isoc_req->isoc_client_private;
1539 int i, offset, sz;
1540 void * ahdl;
1541 usb_audio_formats_t *format = &uasp->usb_as_curr_format;
1542 int precision;
1543
1544 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
1545 "usb_as_record_cb: rq=0x%p data=0x%p pkts=0x%x",
1546 (void *)isoc_req, (void *)isoc_req->isoc_data,
1547 isoc_req->isoc_pkts_count);
1548
1549 USB_DPRINTF_L4(PRINT_MASK_CB, uasp->usb_as_log_handle,
1550 "\tfno=%" PRId64 ", n_pkts=%u, flag=0x%x, data=0x%p, cnt=%d",
1551 isoc_req->isoc_frame_no, isoc_req->isoc_pkts_count,
1552 isoc_req->isoc_attributes, (void *)isoc_req->isoc_data,
1553 isoc_req->isoc_error_count);
1554
1555 ASSERT((isoc_req->isoc_cb_flags & USB_CB_INTR_CONTEXT) != 0);
1556
1557 mutex_enter(&uasp->usb_as_mutex);
1558 ahdl = uasp->usb_as_ahdl;
1559 sz = uasp->usb_as_record_pkt_size;
1560 precision = format->fmt_precision >> 3;
1561
1562 if (uasp->usb_as_audio_state != USB_AS_IDLE) {
1563 for (offset = i = 0; i < isoc_req->isoc_pkts_count; i++) {
1564 USB_DPRINTF_L3(PRINT_MASK_CB, uasp->usb_as_log_handle,
1565 "\tpkt%d: "
1566 "offset=%d pktsize=%d len=%d status=%d resid=%d",
1567 i, offset, sz,
1568 isoc_req->isoc_pkt_descr[i].isoc_pkt_length,
1569 isoc_req->isoc_pkt_descr[i].isoc_pkt_status,
1570 isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length);
1571
1572 if (isoc_req->isoc_pkt_descr[i].isoc_pkt_status !=
1573 USB_CR_OK) {
1574 USB_DPRINTF_L2(PRINT_MASK_CB,
1575 uasp->usb_as_log_handle,
1576 "record: pkt=%d offset=0x%x status=%s",
1577 i, offset, usb_str_cr(isoc_req->
1578 isoc_pkt_descr[i].isoc_pkt_status));
1579 }
1580 mutex_exit(&uasp->usb_as_mutex);
1581
1582 usb_ac_send_audio(ahdl,
1583 isoc_req->isoc_data->b_rptr + offset,
1584 isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length /
1585 precision);
1586
1587 mutex_enter(&uasp->usb_as_mutex);
1588 offset += isoc_req->isoc_pkt_descr[i].isoc_pkt_length;
1589 }
1590 }
1591
1592 mutex_exit(&uasp->usb_as_mutex);
1593
1594 usb_free_isoc_req(isoc_req);
1595 }
1596
1597 /*
1598 * Since the int_rate is 1000, we have to do special arithmetic for
1599 * sample rates not multiple of 1K. For example,
1600 * if the sample rate is 48000(i.e multiple of 1K), we can send 48000/1000
1601 * = 48 samples every packet per channel. Since we have to support sample
1602 * rate like 11025, 22050 and 44100, we will have some extra samples
1603 * at the end that we need to spread among the 1000 cycles. So if we make
1604 * the pktsize as below for these sample rates, at the end of 1000 cycles,
1605 * we will be able to send all the data in the correct rate:
1606 *
1607 * 11025: 39 samples of 11, 1 of 12
1608 * 22050: 19 samples of 22, 1 of 23
1609 * 44100: 9 samples of 44, 1 of 45
1610 *
1611 * frameno is a simple counter maintained in the soft state structure.
1612 * So the pkt size is:
1613 * pkt_size = ((frameno % cycle) ? pkt : (pkt + extra));
1614 *
1615 */
1616
1617 static int
usb_as_get_pktsize(usb_as_state_t * uasp,usb_frame_number_t frameno)1618 usb_as_get_pktsize(usb_as_state_t *uasp, usb_frame_number_t frameno)
1619 {
1620 static uint_t sr = 0;
1621 static ushort_t pkt, cycle;
1622 static int extra;
1623 int pkt_size = 0;
1624 usb_audio_formats_t *format = &uasp->usb_as_curr_format;
1625
1626 if (sr != uasp->usb_as_curr_sr) {
1627 /* calculate once */
1628 sr = uasp->usb_as_curr_sr;
1629 pkt = (sr + 500) / 1000;
1630 extra = sr % 1000;
1631
1632 if (extra == 0) {
1633 /* sample rate is a multiple of 1000 */
1634 cycle = 1000;
1635 } else {
1636 /* find a common divisor of 1000 and extra */
1637 int m = 1000;
1638 int n = extra;
1639
1640 while (m != n) {
1641 if (m > n) {
1642 m = m - n;
1643 } else {
1644 n = n - m;
1645 }
1646 }
1647 cycle = (1000 / n);
1648 extra = ((extra >= 500) ? (extra - 1000) : extra) / n;
1649 }
1650 }
1651 pkt_size = (((frameno + 1) % cycle) ?
1652 pkt : (pkt + extra));
1653 pkt_size *= (format->fmt_precision >> 3)
1654 * format->fmt_chns;
1655
1656 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1657 "usb_as_get_pktsize: %d", pkt_size);
1658
1659 return (pkt_size);
1660 }
1661
1662
1663 /*
1664 * usb_as_send_ctrl_cmd:
1665 * Opens the pipe; sends a control command down
1666 */
1667 static int
usb_as_send_ctrl_cmd(usb_as_state_t * uasp,uchar_t bmRequestType,uchar_t bRequest,ushort_t wValue,ushort_t wIndex,ushort_t wLength,mblk_t * data,boolean_t ignore_errors)1668 usb_as_send_ctrl_cmd(usb_as_state_t *uasp,
1669 uchar_t bmRequestType, uchar_t bRequest,
1670 ushort_t wValue, ushort_t wIndex, ushort_t wLength,
1671 mblk_t *data, boolean_t ignore_errors)
1672 {
1673 usb_ctrl_setup_t setup;
1674 usb_cr_t cr;
1675 usb_cb_flags_t cf;
1676
1677 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1678 "usb_as_send_ctrl_cmd: Begin bmRequestType=%d,\n\t"
1679 "bRequest=%d, wValue=%d, wIndex=%d, wLength=%d, data=0x%p",
1680 bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
1681
1682 setup.bmRequestType = bmRequestType & ~USB_DEV_REQ_DEV_TO_HOST;
1683 setup.bRequest = bRequest;
1684 setup.wValue = wValue;
1685 setup.wIndex = wIndex;
1686 setup.wLength = wLength;
1687 setup.attrs = 0;
1688
1689 if (usb_pipe_ctrl_xfer_wait(uasp->usb_as_default_ph, &setup, &data,
1690 &cr, &cf, 0) != USB_SUCCESS) {
1691 USB_DPRINTF_L2(PRINT_MASK_ALL, uasp->usb_as_log_handle,
1692 "usb_as_send_ctrl_cmd: usba xfer failed (req=%d), "
1693 "completion reason: 0x%x, completion flags: 0x%x",
1694 bRequest, cr, cf);
1695
1696 return (ignore_errors ? USB_SUCCESS: USB_FAILURE);
1697 }
1698
1699 return (USB_SUCCESS);
1700 }
1701
1702
1703 /*
1704 * Power management
1705 */
1706
1707 /*ARGSUSED*/
1708 static void
usb_as_create_pm_components(dev_info_t * dip,usb_as_state_t * uasp)1709 usb_as_create_pm_components(dev_info_t *dip, usb_as_state_t *uasp)
1710 {
1711 usb_as_power_t *uaspm;
1712 uint_t pwr_states;
1713
1714 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
1715 "usb_as_create_pm_components: begin");
1716
1717 /* Allocate the state structure */
1718 uaspm = kmem_zalloc(sizeof (usb_as_power_t), KM_SLEEP);
1719 uasp->usb_as_pm = uaspm;
1720 uaspm->aspm_state = uasp;
1721 uaspm->aspm_capabilities = 0;
1722 uaspm->aspm_current_power = USB_DEV_OS_FULL_PWR;
1723
1724 USB_DPRINTF_L3(PRINT_MASK_PM, uasp->usb_as_log_handle,
1725 "usb_as_pm_components: remote Wakeup enabled");
1726 if (usb_create_pm_components(dip, &pwr_states) ==
1727 USB_SUCCESS) {
1728 if (usb_handle_remote_wakeup(dip,
1729 USB_REMOTE_WAKEUP_ENABLE) != USB_SUCCESS) {
1730 USB_DPRINTF_L2(PRINT_MASK_PM,
1731 uasp->usb_as_log_handle,
1732 "enable remote wakeup failed");
1733 } else {
1734 uaspm->aspm_wakeup_enabled = 1;
1735 }
1736 uaspm->aspm_pwr_states = (uint8_t)pwr_states;
1737 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1738 }
1739
1740 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
1741 "usb_as_create_pm_components: end");
1742 }
1743
1744
1745 /*
1746 * usb_as_power:
1747 * power entry point
1748 */
1749 static int
usb_as_power(dev_info_t * dip,int comp,int level)1750 usb_as_power(dev_info_t *dip, int comp, int level)
1751 {
1752 int instance = ddi_get_instance(dip);
1753 usb_as_state_t *uasp;
1754 usb_as_power_t *uaspm;
1755 int retval = USB_FAILURE;
1756
1757 uasp = ddi_get_soft_state(usb_as_statep, instance);
1758
1759 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
1760 "usb_as_power: comp=%d level=%d", comp, level);
1761
1762 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
1763
1764 mutex_enter(&uasp->usb_as_mutex);
1765 uaspm = uasp->usb_as_pm;
1766
1767 if (USB_DEV_PWRSTATE_OK(uaspm->aspm_pwr_states, level)) {
1768 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle,
1769 "usb_as_power: illegal level=%d pwr_states=%d",
1770 level, uaspm->aspm_pwr_states);
1771
1772 goto done;
1773 }
1774
1775 switch (level) {
1776 case USB_DEV_OS_PWR_OFF:
1777 retval = usb_as_pwrlvl0(uasp);
1778 break;
1779 case USB_DEV_OS_PWR_1:
1780 retval = usb_as_pwrlvl1(uasp);
1781 break;
1782 case USB_DEV_OS_PWR_2:
1783 retval = usb_as_pwrlvl2(uasp);
1784 break;
1785 case USB_DEV_OS_FULL_PWR:
1786 retval = usb_as_pwrlvl3(uasp);
1787 break;
1788 default:
1789 retval = USB_FAILURE;
1790 break;
1791 }
1792
1793 done:
1794
1795 usb_release_access(uasp->usb_as_ser_acc);
1796 mutex_exit(&uasp->usb_as_mutex);
1797
1798 return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1799 }
1800
1801
1802 /*
1803 * functions to handle power transition for various levels
1804 * These functions act as place holders to issue USB commands
1805 * to the devices to change their power levels
1806 * Level 0 = Device is powered off
1807 * Level 3 = Device if full powered
1808 * Level 1,2 = Intermediate power level of the device as implemented
1809 * by the hardware.
1810 * Note that Level 0 is OS power-off and Level 3 is OS full-power.
1811 */
1812 static int
usb_as_pwrlvl0(usb_as_state_t * uasp)1813 usb_as_pwrlvl0(usb_as_state_t *uasp)
1814 {
1815 usb_as_power_t *uaspm;
1816 int rval;
1817
1818 uaspm = uasp->usb_as_pm;
1819
1820 switch (uasp->usb_as_dev_state) {
1821 case USB_DEV_ONLINE:
1822 /* Deny the powerdown request if the device is busy */
1823 if (uaspm->aspm_pm_busy != 0) {
1824
1825 return (USB_FAILURE);
1826 }
1827
1828 if (uasp->usb_as_audio_state != USB_AS_IDLE) {
1829
1830 return (USB_FAILURE);
1831 }
1832
1833 /* Issue USB D3 command to the device here */
1834 rval = usb_set_device_pwrlvl3(uasp->usb_as_dip);
1835 ASSERT(rval == USB_SUCCESS);
1836
1837 uasp->usb_as_dev_state = USB_DEV_PWRED_DOWN;
1838 uaspm->aspm_current_power = USB_DEV_OS_PWR_OFF;
1839
1840 /* FALLTHRU */
1841 case USB_DEV_DISCONNECTED:
1842 case USB_DEV_SUSPENDED:
1843 /* allow a disconnected/cpr'ed device to go to low power */
1844
1845 return (USB_SUCCESS);
1846 case USB_DEV_PWRED_DOWN:
1847 default:
1848 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle,
1849 "usb_as_pwrlvl0: Illegal dev_state");
1850
1851 return (USB_FAILURE);
1852 }
1853 }
1854
1855
1856 /* ARGSUSED */
1857 static int
usb_as_pwrlvl1(usb_as_state_t * uasp)1858 usb_as_pwrlvl1(usb_as_state_t *uasp)
1859 {
1860 int rval;
1861
1862 /* Issue USB D2 command to the device here */
1863 rval = usb_set_device_pwrlvl2(uasp->usb_as_dip);
1864 ASSERT(rval == USB_SUCCESS);
1865
1866 return (USB_FAILURE);
1867 }
1868
1869
1870 /* ARGSUSED */
1871 static int
usb_as_pwrlvl2(usb_as_state_t * uasp)1872 usb_as_pwrlvl2(usb_as_state_t *uasp)
1873 {
1874 int rval;
1875
1876 rval = usb_set_device_pwrlvl1(uasp->usb_as_dip);
1877 ASSERT(rval == USB_SUCCESS);
1878
1879 return (USB_FAILURE);
1880 }
1881
1882
1883 static int
usb_as_pwrlvl3(usb_as_state_t * uasp)1884 usb_as_pwrlvl3(usb_as_state_t *uasp)
1885 {
1886 usb_as_power_t *uaspm;
1887 int rval;
1888
1889 uaspm = uasp->usb_as_pm;
1890
1891 switch (uasp->usb_as_dev_state) {
1892 case USB_DEV_PWRED_DOWN:
1893
1894 /* Issue USB D0 command to the device here */
1895 rval = usb_set_device_pwrlvl0(uasp->usb_as_dip);
1896 ASSERT(rval == USB_SUCCESS);
1897
1898 uasp->usb_as_dev_state = USB_DEV_ONLINE;
1899 uaspm->aspm_current_power = USB_DEV_OS_FULL_PWR;
1900
1901 /* FALLTHRU */
1902 case USB_DEV_ONLINE:
1903 /* we are already in full power */
1904
1905 /* fall thru */
1906 case USB_DEV_DISCONNECTED:
1907 case USB_DEV_SUSPENDED:
1908 /* allow power change on a disconnected/cpr'ed device */
1909
1910 return (USB_SUCCESS);
1911 default:
1912 USB_DPRINTF_L2(PRINT_MASK_PM, uasp->usb_as_log_handle,
1913 "usb_as_pwrlvl3: Illegal dev_state");
1914
1915 return (DDI_FAILURE);
1916 }
1917 }
1918
1919
1920 /*
1921 * Descriptor Management
1922 *
1923 * usb_as_handle_descriptors:
1924 * read and parse all descriptors and build up usb_as_alts list
1925 *
1926 * the order is as follows:
1927 * interface, general, format, endpoint, CV endpoint
1928 */
1929 static int
usb_as_handle_descriptors(usb_as_state_t * uasp)1930 usb_as_handle_descriptors(usb_as_state_t *uasp)
1931 {
1932 usb_client_dev_data_t *dev_data = uasp->usb_as_dev_data;
1933 int interface = dev_data->dev_curr_if;
1934 uint_t alternate;
1935 uint_t n_alternates;
1936 int len, i, j, n, n_srs, sr, index;
1937 int rval = USB_SUCCESS;
1938 usb_if_descr_t *if_descr;
1939 usb_audio_as_if_descr_t *general;
1940 usb_audio_type1_format_descr_t *format;
1941 uint_t *sample_rates;
1942 usb_ep_descr_t *ep;
1943 usb_audio_as_isoc_ep_descr_t *cs_ep;
1944 usb_if_data_t *if_data;
1945 usb_alt_if_data_t *altif_data;
1946 usb_ep_data_t *ep_data;
1947
1948 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
1949 "usb_as_handle_descriptors: cfg=%ld interface=%d",
1950 (long)(dev_data->dev_curr_cfg - &dev_data->dev_cfg[0]),
1951 dev_data->dev_curr_if);
1952
1953 if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if];
1954 uasp->usb_as_ifno = interface;
1955
1956 /*
1957 * find the number of alternates for this interface
1958 * and allocate an array to store the descriptors for
1959 * each alternate
1960 */
1961 uasp->usb_as_n_alternates = n_alternates = if_data->if_n_alt;
1962 uasp->usb_as_alts = kmem_zalloc((n_alternates) *
1963 sizeof (usb_as_alt_descr_t), KM_SLEEP);
1964
1965 /*
1966 * for each alternate read descriptors
1967 */
1968 for (alternate = 0; alternate < n_alternates; alternate++) {
1969 altif_data = &if_data->if_alt[alternate];
1970
1971 uasp->usb_as_alts[alternate].alt_if =
1972 kmem_zalloc(sizeof (usb_if_descr_t), KM_SLEEP);
1973 if_descr = &altif_data->altif_descr;
1974
1975 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
1976 "interface (%d.%d):\n\t"
1977 "l = 0x%x type = 0x%x n = 0x%x alt = 0x%x #ep = 0x%x\n\t"
1978 "iclass = 0x%x subclass = 0x%x proto = 0x%x string = 0x%x",
1979 interface, alternate,
1980 if_descr->bLength, if_descr->bDescriptorType,
1981 if_descr->bInterfaceNumber, if_descr->bAlternateSetting,
1982 if_descr->bNumEndpoints, if_descr->bInterfaceClass,
1983 if_descr->bInterfaceSubClass,
1984 if_descr->bInterfaceProtocol, if_descr->iInterface);
1985
1986 *(uasp->usb_as_alts[alternate].alt_if) = *if_descr;
1987
1988 /* read the general descriptor */
1989 index = 0;
1990
1991 if (altif_data->altif_cvs == NULL) {
1992
1993 continue;
1994 }
1995
1996 general = kmem_zalloc(sizeof (*general), KM_SLEEP);
1997
1998 len = usb_parse_data(AS_IF_DESCR_FORMAT,
1999 altif_data->altif_cvs[index].cvs_buf,
2000 altif_data->altif_cvs[index].cvs_buf_len,
2001 (void *)general, sizeof (*general));
2002
2003 /* is this a sane header descriptor */
2004 if (!((len >= AS_IF_DESCR_SIZE) &&
2005 (general->bDescriptorType == USB_AUDIO_CS_INTERFACE) &&
2006 (general->bDescriptorSubType == USB_AUDIO_AS_GENERAL))) {
2007 USB_DPRINTF_L2(PRINT_MASK_ATTA,
2008 uasp->usb_as_log_handle,
2009 "invalid general cs interface descr");
2010
2011 kmem_free(general, sizeof (*general));
2012
2013 continue;
2014 }
2015
2016 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2017 "general (%d.%d): type=0x%x subtype=0x%x termlink=0x%x\n\t"
2018 "delay=0x%x format=0x%x",
2019 interface, alternate,
2020 general->bDescriptorType, general->bDescriptorSubType,
2021 general->bTerminalLink, general->bDelay,
2022 general->wFormatTag);
2023
2024 uasp->usb_as_alts[alternate].alt_general = general;
2025
2026 /*
2027 * there should be one format descriptor of unknown size.
2028 * the format descriptor contains just bytes, no need to
2029 * parse
2030 */
2031 index++;
2032 len = altif_data->altif_cvs[index].cvs_buf_len;
2033 format = kmem_zalloc(len, KM_SLEEP);
2034 bcopy(altif_data->altif_cvs[index].cvs_buf, format, len);
2035
2036 /* is this a sane format descriptor */
2037 if (!((format->blength >= AUDIO_TYPE1_FORMAT_SIZE) &&
2038 format->bDescriptorSubType == USB_AUDIO_AS_FORMAT_TYPE)) {
2039 USB_DPRINTF_L2(PRINT_MASK_ATTA,
2040 uasp->usb_as_log_handle,
2041 "invalid format cs interface descr");
2042
2043 kmem_free(format, len);
2044
2045 continue;
2046 }
2047
2048 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2049 "format (%d.%d): len = %d "
2050 "type = 0x%x subtype = 0x%x format = 0x%x\n\t"
2051 "#channels = 0x%x subframe = 0x%x resolution = 0x%x\n\t"
2052 "sample freq type = 0x%x",
2053 interface, alternate, len,
2054 format->bDescriptorType,
2055 format->bDescriptorSubType,
2056 format->bFormatType,
2057 format->bNrChannels,
2058 format->bSubFrameSize,
2059 format->bBitResolution,
2060 format->bSamFreqType);
2061
2062 if (format->bSamFreqType == 0) {
2063 /* continuous sample rate limits */
2064 n_srs = 2;
2065 uasp->usb_as_alts[alternate].alt_continuous_sr++;
2066 } else {
2067 n_srs = format->bSamFreqType;
2068 }
2069
2070 sample_rates =
2071 kmem_zalloc(n_srs * (sizeof (uint_t)), KM_SLEEP);
2072
2073 /* go thru all sample rates (3 bytes) each */
2074 for (i = 0, j = 0, n = 0; n < n_srs; i += 3, n++) {
2075 sr = (format->bSamFreqs[i+2] << 16) |
2076 (format->bSamFreqs[i+1] << 8) |
2077 format->bSamFreqs[i];
2078 USB_DPRINTF_L3(PRINT_MASK_ATTA,
2079 uasp->usb_as_log_handle,
2080 "sr = %d", sr);
2081 sample_rates[n] = sr;
2082 if (sr != 0) {
2083 j++;
2084 }
2085 }
2086
2087 if (j == 0) {
2088 USB_DPRINTF_L2(PRINT_MASK_ATTA,
2089 uasp->usb_as_log_handle,
2090 "format cs interface descr has no valid rates");
2091
2092 kmem_free(format, len);
2093 kmem_free(sample_rates, n_srs * (sizeof (uint_t)));
2094
2095 continue;
2096 }
2097
2098 uasp->usb_as_alts[alternate].alt_format_len = (uchar_t)len;
2099
2100 uasp->usb_as_alts[alternate].alt_format = format;
2101
2102 uasp->usb_as_alts[alternate].alt_n_sample_rates =
2103 (uchar_t)n_srs;
2104
2105 uasp->usb_as_alts[alternate].alt_sample_rates =
2106 sample_rates;
2107
2108 if ((ep_data = usb_lookup_ep_data(uasp->usb_as_dip,
2109 dev_data, interface, alternate, 0,
2110 USB_EP_ATTR_ISOCH, USB_EP_DIR_IN)) == NULL) {
2111 if ((ep_data = usb_lookup_ep_data(uasp->usb_as_dip,
2112 dev_data, interface, alternate, 0,
2113 USB_EP_ATTR_ISOCH, USB_EP_DIR_OUT)) == NULL) {
2114
2115 USB_DPRINTF_L2(PRINT_MASK_ATTA,
2116 uasp->usb_as_log_handle,
2117 "no endpoint descriptor found");
2118
2119 continue;
2120 }
2121 }
2122 ep = &ep_data->ep_descr;
2123
2124 uasp->usb_as_alts[alternate].alt_ep =
2125 kmem_zalloc(sizeof (usb_ep_descr_t), KM_SLEEP);
2126 *(uasp->usb_as_alts[alternate].alt_ep) = *ep;
2127
2128 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2129 "endpoint (%d.%d):\n\t"
2130 "len = 0x%x type = 0x%x add = 0x%x "
2131 "attr = 0x%x mps = 0x%x\n\t"
2132 "int = 0x%x",
2133 interface, alternate,
2134 ep->bLength, ep->bDescriptorType, ep->bEndpointAddress,
2135 ep->bmAttributes, ep->wMaxPacketSize, ep->bInterval);
2136
2137 uasp->usb_as_alts[alternate].alt_mode =
2138 (ep->bEndpointAddress & USB_EP_DIR_IN) ?
2139 USB_AUDIO_RECORD : USB_AUDIO_PLAY;
2140
2141 if (ep_data->ep_n_cvs == 0) {
2142 USB_DPRINTF_L2(PRINT_MASK_ATTA,
2143 uasp->usb_as_log_handle,
2144 "no cv ep descriptor");
2145
2146 continue;
2147 }
2148
2149 cs_ep = kmem_zalloc(sizeof (*cs_ep), KM_SLEEP);
2150 len = usb_parse_data(AS_ISOC_EP_DESCR_FORMAT,
2151 ep_data->ep_cvs[0].cvs_buf,
2152 ep_data->ep_cvs[0].cvs_buf_len,
2153 (void *)cs_ep, sizeof (*cs_ep));
2154
2155 if ((len < AS_ISOC_EP_DESCR_SIZE) ||
2156 (cs_ep->bDescriptorType != USB_AUDIO_CS_ENDPOINT)) {
2157 USB_DPRINTF_L2(PRINT_MASK_ATTA,
2158 uasp->usb_as_log_handle,
2159 "cs endpoint descriptor invalid (%d)", len);
2160 kmem_free(cs_ep, sizeof (*cs_ep));
2161
2162 continue;
2163 }
2164
2165 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2166 "cs isoc endpoint (%d.%d):\n\t"
2167 "type=0x%x sub=0x%x attr=0x%x units=0x%x delay=%x",
2168 interface, alternate,
2169 cs_ep->bDescriptorType,
2170 cs_ep->bDescriptorSubType,
2171 cs_ep->bmAttributes,
2172 cs_ep->bLockDelayUnits,
2173 cs_ep->wLockDelay);
2174
2175 uasp->usb_as_alts[alternate].alt_cs_ep = cs_ep;
2176
2177 /* we are done */
2178 uasp->usb_as_alts[alternate].alt_valid++;
2179 }
2180
2181 done:
2182 usb_as_prepare_registration_data(uasp);
2183
2184 return (rval);
2185 }
2186
2187
2188 /*
2189 * usb_as_free_alts:
2190 * cleanup alternate list and deallocate all descriptors
2191 */
2192 static void
usb_as_free_alts(usb_as_state_t * uasp)2193 usb_as_free_alts(usb_as_state_t *uasp)
2194 {
2195 int alt;
2196 usb_as_alt_descr_t *altp;
2197
2198 if (uasp->usb_as_alts) {
2199 for (alt = 0; alt < uasp->usb_as_n_alternates; alt++) {
2200 altp = &uasp->usb_as_alts[alt];
2201 if (altp) {
2202 if (altp->alt_sample_rates) {
2203 kmem_free(altp->alt_sample_rates,
2204 altp->alt_n_sample_rates *
2205 sizeof (uint_t));
2206 }
2207 if (altp->alt_if) {
2208 kmem_free(altp->alt_if,
2209 sizeof (usb_if_descr_t));
2210 }
2211 if (altp->alt_general) {
2212 kmem_free(altp->alt_general,
2213 sizeof (usb_audio_as_if_descr_t));
2214 }
2215 if (altp->alt_format) {
2216 kmem_free(altp->alt_format,
2217 altp->alt_format_len);
2218 }
2219 if (altp->alt_ep) {
2220 kmem_free(altp->alt_ep,
2221 sizeof (usb_ep_descr_t));
2222 }
2223 if (altp->alt_cs_ep) {
2224 kmem_free(altp->alt_cs_ep,
2225 sizeof (*altp->alt_cs_ep));
2226 }
2227 }
2228 }
2229 kmem_free(uasp->usb_as_alts, (uasp->usb_as_n_alternates) *
2230 sizeof (usb_as_alt_descr_t));
2231 }
2232 }
2233
2234
2235 /*
2236 * usb_as_prepare_registration_data
2237 */
2238 static void
usb_as_prepare_registration_data(usb_as_state_t * uasp)2239 usb_as_prepare_registration_data(usb_as_state_t *uasp)
2240 {
2241 usb_as_registration_t *reg = &uasp->usb_as_reg;
2242 usb_audio_type1_format_descr_t *format;
2243 uchar_t n_alternates = uasp->usb_as_n_alternates;
2244 int alt, n;
2245
2246 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2247 "usb_as_prepare_registration_data:");
2248
2249 /* there has to be at least two alternates, ie 0 and 1 */
2250 if (n_alternates < 2) {
2251 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2252 "not enough alternates %d", n_alternates);
2253
2254 return;
2255 }
2256
2257 reg->reg_ifno = uasp->usb_as_ifno;
2258
2259 /* all endpoints need to have the same direction */
2260 for (alt = 1; alt < n_alternates; alt++) {
2261 if (!uasp->usb_as_alts[alt].alt_valid) {
2262 continue;
2263 }
2264 if (reg->reg_mode && uasp->usb_as_alts[alt].alt_mode !=
2265 reg->reg_mode) {
2266 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2267 "alternates have different direction");
2268
2269 return;
2270 }
2271 reg->reg_mode = uasp->usb_as_alts[alt].alt_mode;
2272 }
2273
2274 /*
2275 * we assume that alternate 0 is not interesting (no bandwidth),
2276 * we check all formats and use the formats that we can support
2277 */
2278 for (alt = 1, n = 0; alt < n_alternates; alt++) {
2279 if (!uasp->usb_as_alts[alt].alt_valid) {
2280 continue;
2281 }
2282
2283 format = uasp->usb_as_alts[alt].alt_format;
2284 if (uasp->usb_as_alts[alt].alt_valid &&
2285 (n < USB_AS_N_FORMATS) &&
2286 (usb_as_valid_format(uasp, alt) == USB_SUCCESS)) {
2287 reg->reg_formats[n].fmt_termlink =
2288 uasp->usb_as_alts[alt].alt_general->
2289 bTerminalLink;
2290 reg->reg_formats[n].fmt_alt = (uchar_t)alt;
2291 reg->reg_formats[n].fmt_chns =
2292 format->bNrChannels;
2293 reg->reg_formats[n].fmt_precision =
2294 format->bBitResolution;
2295 reg->reg_formats[n].fmt_encoding =
2296 format->bFormatType;
2297 reg->reg_formats[n].fmt_n_srs =
2298 uasp->usb_as_alts[alt].alt_n_sample_rates;
2299 reg->reg_formats[n++].fmt_srs =
2300 uasp->usb_as_alts[alt].alt_sample_rates;
2301 }
2302 }
2303
2304 reg->reg_n_formats = (uchar_t)n;
2305
2306 if (n == 0) {
2307 /* no valid formats */
2308 USB_DPRINTF_L2(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2309 "zero valid formats");
2310
2311 return;
2312 }
2313
2314 /* dump what we have so far */
2315 for (n = 0; n < reg->reg_n_formats; n++) {
2316 USB_DPRINTF_L3(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2317 "regformats[%d]: termlink = %d, alt=%d chns=%d"
2318 " prec=%d enc=%d", n,
2319 reg->reg_formats[n].fmt_termlink,
2320 reg->reg_formats[n].fmt_alt,
2321 reg->reg_formats[n].fmt_chns,
2322 reg->reg_formats[n].fmt_precision,
2323 reg->reg_formats[n].fmt_encoding);
2324 }
2325
2326 reg->reg_valid++;
2327 }
2328
2329
2330 /*
2331 * usb_as_valid_format:
2332 * check if this format can be supported
2333 */
2334 static int
usb_as_valid_format(usb_as_state_t * uasp,uint_t alternate)2335 usb_as_valid_format(usb_as_state_t *uasp, uint_t alternate)
2336 {
2337 usb_as_alt_descr_t *alt_descr = &uasp->usb_as_alts[alternate];
2338 usb_audio_type1_format_descr_t *format = alt_descr->alt_format;
2339
2340 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
2341 "usb_as_valid_format: %d %d %d %d %d",
2342 format->bNrChannels, format->bSubFrameSize,
2343 format->bBitResolution, format->bSamFreqType,
2344 format->bFormatType);
2345 USB_DPRINTF_L4(PRINT_MASK_PM, uasp->usb_as_log_handle,
2346 "alt=%d", alternate);
2347
2348 switch (format->bNrChannels) {
2349 case 0:
2350
2351 return (USB_FAILURE);
2352 default:
2353
2354 break;
2355 }
2356
2357 switch (format->bSubFrameSize) {
2358 case 1:
2359 case 2:
2360 break;
2361 default:
2362
2363 return (USB_FAILURE);
2364 }
2365
2366 switch (format->bBitResolution) {
2367 case USB_AUDIO_PRECISION_8:
2368 case USB_AUDIO_PRECISION_16:
2369 case USB_AUDIO_PRECISION_24:
2370 case USB_AUDIO_PRECISION_32:
2371 break;
2372 default:
2373
2374 return (USB_FAILURE);
2375 }
2376
2377 switch (format->bFormatType) {
2378 case USB_AUDIO_FORMAT_TYPE1_PCM:
2379 break;
2380 default:
2381
2382 return (USB_FAILURE);
2383 }
2384
2385 return (USB_SUCCESS);
2386 }
2387
2388
2389
2390
2391 /*
2392 * Event Management
2393 *
2394 * usb_as_disconnect_event_cb:
2395 * The device has been disconnected.
2396 */
2397 static int
usb_as_disconnect_event_cb(dev_info_t * dip)2398 usb_as_disconnect_event_cb(dev_info_t *dip)
2399 {
2400 usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state(
2401 usb_as_statep, ddi_get_instance(dip));
2402
2403 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle,
2404 "usb_as_disconnect_event_cb: dip=0x%p", (void *)dip);
2405
2406 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
2407
2408 mutex_enter(&uasp->usb_as_mutex);
2409 uasp->usb_as_dev_state = USB_DEV_DISCONNECTED;
2410 mutex_exit(&uasp->usb_as_mutex);
2411
2412 usb_release_access(uasp->usb_as_ser_acc);
2413
2414 return (USB_SUCCESS);
2415 }
2416
2417
2418 /*
2419 * usb_as_cpr_suspend:
2420 */
2421 static int
usb_as_cpr_suspend(dev_info_t * dip)2422 usb_as_cpr_suspend(dev_info_t *dip)
2423 {
2424 usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state(
2425 usb_as_statep, ddi_get_instance(dip));
2426
2427 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle,
2428 "usb_as_cpr_suspend: Begin");
2429
2430 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
2431
2432 mutex_enter(&uasp->usb_as_mutex);
2433 uasp->usb_as_dev_state = USB_DEV_SUSPENDED;
2434 mutex_exit(&uasp->usb_as_mutex);
2435
2436 usb_release_access(uasp->usb_as_ser_acc);
2437
2438 USB_DPRINTF_L4(PRINT_MASK_ALL, uasp->usb_as_log_handle,
2439 "usb_as_cpr_suspend: End");
2440
2441 return (USB_SUCCESS);
2442 }
2443
2444
2445 /*
2446 * usb_as_reconnect_event_cb:
2447 * The device was disconnected but this instance not detached, probably
2448 * because the device was busy.
2449 * if the same device, continue with restoring state
2450 */
2451 static int
usb_as_reconnect_event_cb(dev_info_t * dip)2452 usb_as_reconnect_event_cb(dev_info_t *dip)
2453 {
2454 usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state(
2455 usb_as_statep, ddi_get_instance(dip));
2456
2457 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle,
2458 "usb_as_reconnect_event_cb: dip=0x%p", (void *)dip);
2459
2460 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
2461
2462 mutex_enter(&uasp->usb_as_mutex);
2463 usb_as_restore_device_state(dip, uasp);
2464 mutex_exit(&uasp->usb_as_mutex);
2465
2466 usb_release_access(uasp->usb_as_ser_acc);
2467
2468 return (USB_SUCCESS);
2469 }
2470
2471
2472 /*
2473 * usb_as_cpr_resume:
2474 * recover this device from suspended state
2475 */
2476 static void
usb_as_cpr_resume(dev_info_t * dip)2477 usb_as_cpr_resume(dev_info_t *dip)
2478 {
2479 usb_as_state_t *uasp = (usb_as_state_t *)ddi_get_soft_state(
2480 usb_as_statep, ddi_get_instance(dip));
2481
2482 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uasp->usb_as_log_handle,
2483 "usb_as_cpr_resume: dip=0x%p", (void *)dip);
2484
2485 (void) usb_serialize_access(uasp->usb_as_ser_acc, USB_WAIT, 0);
2486
2487 mutex_enter(&uasp->usb_as_mutex);
2488 usb_as_restore_device_state(dip, uasp);
2489 mutex_exit(&uasp->usb_as_mutex);
2490
2491 usb_release_access(uasp->usb_as_ser_acc);
2492 }
2493
2494
2495 /*
2496 * usb_as_restore_device_state:
2497 * Set original configuration of the device
2498 * enable wrq - this starts new transactions on the control pipe
2499 */
2500 static void
usb_as_restore_device_state(dev_info_t * dip,usb_as_state_t * uasp)2501 usb_as_restore_device_state(dev_info_t *dip, usb_as_state_t *uasp)
2502 {
2503 usb_as_power_t *uaspm;
2504
2505 USB_DPRINTF_L4(PRINT_MASK_ATTA, uasp->usb_as_log_handle,
2506 "usb_as_restore_device_state:");
2507
2508 ASSERT(mutex_owned(&uasp->usb_as_mutex));
2509
2510 uaspm = uasp->usb_as_pm;
2511
2512 /* Check if we are talking to the same device */
2513 mutex_exit(&uasp->usb_as_mutex);
2514 usb_as_pm_busy_component(uasp);
2515 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2516
2517 if (usb_check_same_device(dip, uasp->usb_as_log_handle, USB_LOG_L0,
2518 PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
2519 usb_as_pm_idle_component(uasp);
2520
2521 /* change the device state from suspended to disconnected */
2522 mutex_enter(&uasp->usb_as_mutex);
2523 uasp->usb_as_dev_state = USB_DEV_DISCONNECTED;
2524
2525 return;
2526 }
2527 mutex_enter(&uasp->usb_as_mutex);
2528
2529 if (uaspm) {
2530 if (uaspm->aspm_wakeup_enabled) {
2531 mutex_exit(&uasp->usb_as_mutex);
2532 if (usb_handle_remote_wakeup(uasp->usb_as_dip,
2533 USB_REMOTE_WAKEUP_ENABLE)) {
2534 USB_DPRINTF_L2(PRINT_MASK_ALL,
2535 uasp->usb_as_log_handle,
2536 "enable remote wake up failed");
2537 }
2538 mutex_enter(&uasp->usb_as_mutex);
2539 }
2540 }
2541 uasp->usb_as_dev_state = USB_DEV_ONLINE;
2542
2543 mutex_exit(&uasp->usb_as_mutex);
2544 usb_as_pm_idle_component(uasp);
2545 mutex_enter(&uasp->usb_as_mutex);
2546 }
2547
2548
2549 static void
usb_as_pm_busy_component(usb_as_state_t * usb_as_statep)2550 usb_as_pm_busy_component(usb_as_state_t *usb_as_statep)
2551 {
2552 ASSERT(!mutex_owned(&usb_as_statep->usb_as_mutex));
2553
2554 if (usb_as_statep->usb_as_pm != NULL) {
2555 mutex_enter(&usb_as_statep->usb_as_mutex);
2556 usb_as_statep->usb_as_pm->aspm_pm_busy++;
2557
2558 USB_DPRINTF_L4(PRINT_MASK_PM, usb_as_statep->usb_as_log_handle,
2559 "usb_as_pm_busy_component: %d",
2560 usb_as_statep->usb_as_pm->aspm_pm_busy);
2561
2562 mutex_exit(&usb_as_statep->usb_as_mutex);
2563
2564 if (pm_busy_component(usb_as_statep->usb_as_dip, 0) !=
2565 DDI_SUCCESS) {
2566 mutex_enter(&usb_as_statep->usb_as_mutex);
2567 usb_as_statep->usb_as_pm->aspm_pm_busy--;
2568
2569 USB_DPRINTF_L2(PRINT_MASK_PM,
2570 usb_as_statep->usb_as_log_handle,
2571 "usb_as_pm_busy_component failed: %d",
2572 usb_as_statep->usb_as_pm->aspm_pm_busy);
2573
2574 mutex_exit(&usb_as_statep->usb_as_mutex);
2575 }
2576 }
2577 }
2578
2579
2580 static void
usb_as_pm_idle_component(usb_as_state_t * usb_as_statep)2581 usb_as_pm_idle_component(usb_as_state_t *usb_as_statep)
2582 {
2583 ASSERT(!mutex_owned(&usb_as_statep->usb_as_mutex));
2584
2585 if (usb_as_statep->usb_as_pm != NULL) {
2586 if (pm_idle_component(usb_as_statep->usb_as_dip, 0) ==
2587 DDI_SUCCESS) {
2588 mutex_enter(&usb_as_statep->usb_as_mutex);
2589 ASSERT(usb_as_statep->usb_as_pm->aspm_pm_busy > 0);
2590 usb_as_statep->usb_as_pm->aspm_pm_busy--;
2591
2592 USB_DPRINTF_L4(PRINT_MASK_PM,
2593 usb_as_statep->usb_as_log_handle,
2594 "usb_as_pm_idle_component: %d",
2595 usb_as_statep->usb_as_pm->aspm_pm_busy);
2596
2597 mutex_exit(&usb_as_statep->usb_as_mutex);
2598 }
2599 }
2600 }
2601