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