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