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