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