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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright 2023 Oxide Computer Company
28 */
29
30 /*
31 * AUDIO CONTROL Driver:
32 *
33 * usb_ac is a multiplexor that sits on top of usb_as and hid and is
34 * responsible for (1) providing the entry points to audio mixer framework,
35 * (2) passing control commands to and from usb_as and hid and (3) processing
36 * control messages from hid/usb_ah that it can handle.
37 *
38 * 1. Mixer entry points are: usb_ac_setup(), usb_ac_teardown(),
39 * usb_ac_set_config(), usb_ac_set_format(), usb_ac_start_play(),
40 * usb_ac_pause_play(), usb_ac_stop_play, usb_ac_start_record(),
41 * usb_ac_stop_record().
42 * 2. usb_ac is a streams driver that passes streams messages down to
43 * usb_as that selects the correct alternate with passed format
44 * parameters, sets sample frequency, starts play/record, stops
45 * play/record, pause play/record, open/close isoc pipe.
46 * 3. usb_ac handles the set_config command through the default pipe
47 * of sound control interface of the audio device in a synchronous
48 * manner.
49 *
50 * Serialization: A competing thread can't be allowed to interfere with
51 * (1) pipe, (2) streams state.
52 * So we need some kind of serialization among the asynchronous
53 * threads that can run in the driver. The serialization is mostly
54 * needed to avoid races among open/close/events/power entry points
55 * etc. Once a routine takes control, it checks if the resource (pipe or
56 * stream or dev state) is still accessible. If so, it proceeds with
57 * its job and until it completes, no other thread requiring the same
58 * resource can run.
59 *
60 * PM model in usb_ac: Raise power during attach. If a device is not at full
61 * power, raise power in the entry points. After the command is over,
62 * pm_idle_component() is called. The power is lowered in detach().
63 */
64 #include <sys/usb/usba/usbai_version.h>
65 #include <sys/usb/usba.h>
66 #include <sys/sunndi.h>
67 #include <sys/strsubr.h>
68 #include <sys/strsun.h>
69 #include <sys/ddi.h>
70 #include <sys/sunddi.h>
71 #include <sys/sunldi.h>
72
73 #include <sys/audio/audio_driver.h>
74
75 #include <sys/usb/clients/audio/usb_audio.h>
76 #include <sys/usb/clients/audio/usb_mixer.h>
77 #include <sys/usb/clients/audio/usb_ac/usb_ac.h>
78
79 /* for getting the minor node info from hid */
80 #include <sys/usb/clients/hid/hidminor.h>
81 #include <sys/usb/clients/audio/usb_as/usb_as.h>
82
83
84 /* debug support */
85 uint_t usb_ac_errlevel = USB_LOG_L4;
86 uint_t usb_ac_errmask = (uint_t)-1;
87 uint_t usb_ac_instance_debug = (uint_t)-1;
88
89 /*
90 * wait period in seconds for the HID message processing thread
91 * used primarily to check when the stream has closed
92 */
93 uint_t usb_ac_wait_hid = 1;
94
95 /*
96 * table for converting term types of input and output terminals
97 * to OSS port types (pretty rough mapping)
98 */
99 static const char *usb_audio_dtypes[] = {
100 AUDIO_PORT_LINEIN,
101 AUDIO_PORT_LINEOUT,
102 AUDIO_PORT_SPEAKER,
103 AUDIO_PORT_HEADPHONES,
104 AUDIO_PORT_HANDSET,
105 AUDIO_PORT_CD,
106 AUDIO_PORT_MIC,
107 AUDIO_PORT_PHONE,
108 AUDIO_PORT_SPDIFIN,
109 AUDIO_PORT_OTHER,
110 NULL,
111 };
112 enum {
113 USB_PORT_LINEIN = 0,
114 USB_PORT_LINEOUT,
115 USB_PORT_SPEAKER,
116 USB_PORT_HEADPHONES,
117 USB_PORT_HANDSET,
118 USB_PORT_CD,
119 USB_PORT_MIC,
120 USB_PORT_PHONE,
121 USB_PORT_SPDIFIN,
122 USB_PORT_UNKNOWN
123 };
124
125 static struct {
126 ushort_t term_type;
127 uint_t port_type;
128 } usb_ac_term_type_map[] = {
129
130 /* Input Terminal Types */
131 { USB_AUDIO_TERM_TYPE_MICROPHONE, USB_PORT_MIC },
132 { USB_AUDIO_TERM_TYPE_DT_MICROPHONE, USB_PORT_MIC },
133 { USB_AUDIO_TERM_TYPE_PERS_MICROPHONE, USB_PORT_MIC },
134 { USB_AUDIO_TERM_TYPE_OMNI_DIR_MICROPHONE, USB_PORT_MIC },
135 { USB_AUDIO_TERM_TYPE_MICROPHONE_ARRAY, USB_PORT_MIC },
136 { USB_AUDIO_TERM_TYPE_PROCESSING_MIC_ARRAY, USB_PORT_MIC },
137
138 /* Output Terminal Types */
139 { USB_AUDIO_TERM_TYPE_SPEAKER, USB_PORT_SPEAKER },
140 { USB_AUDIO_TERM_TYPE_HEADPHONES, USB_PORT_HEADPHONES },
141 { USB_AUDIO_TERM_TYPE_DISPLAY_AUDIO, USB_PORT_LINEOUT },
142 { USB_AUDIO_TERM_TYPE_DT_SPEAKER, USB_PORT_SPEAKER },
143 { USB_AUDIO_TERM_TYPE_ROOM_SPEAKER, USB_PORT_SPEAKER },
144 { USB_AUDIO_TERM_TYPE_COMM_SPEAKER, USB_PORT_SPEAKER },
145 { USB_AUDIO_TERM_TYPE_LF_EFFECTS_SPEAKER, USB_PORT_SPEAKER },
146
147 /* Bi-directional Terminal Types */
148 { USB_AUDIO_TERM_TYPE_HANDSET, USB_PORT_HANDSET },
149
150 /* Telephony Terminal Types */
151 { USB_AUDIO_TERM_TYPE_PHONE_LINE, USB_PORT_PHONE},
152 { USB_AUDIO_TERM_TYPE_TELEPHONE, USB_PORT_PHONE},
153 { USB_AUDIO_TERM_TYPE_DOWN_LINE_PHONE, USB_PORT_PHONE },
154
155 /* External Terminal Types */
156 { USB_AUDIO_TERM_TYPE_SPDIF_IF, USB_PORT_SPDIFIN },
157 /* Embedded Function Terminal Types */
158 { USB_AUDIO_TERM_TYPE_CD_PLAYER, USB_PORT_CD },
159 { 0, 0 }
160 };
161
162
163 /*
164 * Module linkage routines for the kernel
165 */
166 static int usb_ac_attach(dev_info_t *, ddi_attach_cmd_t);
167 static int usb_ac_detach(dev_info_t *, ddi_detach_cmd_t);
168 static int usb_ac_power(dev_info_t *, int, int);
169
170 static uint_t usb_ac_get_featureID(usb_ac_state_t *, uchar_t, uint_t,
171 uint_t);
172
173 /* module entry points */
174 int usb_ac_open(dev_info_t *);
175 void usb_ac_close(dev_info_t *);
176
177 /* descriptor handling */
178 static int usb_ac_handle_descriptors(usb_ac_state_t *);
179 static void usb_ac_add_unit_descriptor(usb_ac_state_t *, uchar_t *, size_t);
180 static void usb_ac_alloc_unit(usb_ac_state_t *, uint_t);
181 static void usb_ac_free_all_units(usb_ac_state_t *);
182 static void usb_ac_setup_connections(usb_ac_state_t *);
183 static void usb_ac_map_termtype_to_port(usb_ac_state_t *, uint_t);
184
185 /* power management */
186 static int usb_ac_pwrlvl0(usb_ac_state_t *);
187 static int usb_ac_pwrlvl1(usb_ac_state_t *);
188 static int usb_ac_pwrlvl2(usb_ac_state_t *);
189 static int usb_ac_pwrlvl3(usb_ac_state_t *);
190 static void usb_ac_create_pm_components(dev_info_t *, usb_ac_state_t *);
191 static void usb_ac_pm_busy_component(usb_ac_state_t *);
192 static void usb_ac_pm_idle_component(usb_ac_state_t *);
193
194 /* event handling */
195 static int usb_ac_disconnect_event_cb(dev_info_t *);
196 static int usb_ac_reconnect_event_cb(dev_info_t *);
197 static int usb_ac_cpr_suspend(dev_info_t *);
198 static void usb_ac_cpr_resume(dev_info_t *);
199
200 static usb_event_t usb_ac_events = {
201 usb_ac_disconnect_event_cb,
202 usb_ac_reconnect_event_cb,
203 NULL, NULL
204 };
205
206 /* misc. support */
207 static void usb_ac_restore_device_state(dev_info_t *, usb_ac_state_t *);
208 static int usb_ac_cleanup(dev_info_t *, usb_ac_state_t *);
209 static void usb_ac_serialize_access(usb_ac_state_t *);
210 static void usb_ac_release_access(usb_ac_state_t *);
211
212 static void usb_ac_push_unit_id(usb_ac_state_t *, uint_t);
213 static void usb_ac_pop_unit_id(usb_ac_state_t *, uint_t);
214 static void usb_ac_show_traverse_path(usb_ac_state_t *);
215 static int usb_ac_check_path(usb_ac_state_t *, uint_t);
216
217 static uint_t usb_ac_traverse_connections(usb_ac_state_t *, uint_t, uint_t,
218 uint_t, uint_t, uint_t, uint_t,
219 uint_t *, uint_t, uint_t *,
220 int (*func)(usb_ac_state_t *, uint_t, uint_t,
221 uint_t, uint_t, uint_t, uint_t *));
222 static uint_t usb_ac_set_port(usb_ac_state_t *, uint_t, uint_t);
223 static uint_t usb_ac_set_control(usb_ac_state_t *, uint_t, uint_t,
224 uint_t, uint_t, uint_t,
225 uint_t *, uint_t,
226 int (*func)(usb_ac_state_t *, uint_t, uint_t,
227 uint_t, uint_t, uint_t, uint_t *));
228 static uint_t usb_ac_set_monitor_gain_control(usb_ac_state_t *, uint_t,
229 uint_t, uint_t, uint_t, uint_t,
230 uint_t *, uint_t,
231 int (*func)(usb_ac_state_t *, uint_t, uint_t,
232 uint_t, uint_t, uint_t, uint_t *));
233 static uint_t usb_ac_traverse_all_units(usb_ac_state_t *, uint_t, uint_t,
234 uint_t, uint_t, uint_t, uint_t *,
235 uint_t, uint_t *,
236 int (*func)(usb_ac_state_t *, uint_t, uint_t,
237 uint_t, uint_t, uint_t, uint_t *));
238 static int usb_ac_update_port(usb_ac_state_t *, uint_t,
239 uint_t, uint_t, uint_t, uint_t, uint_t *);
240 static int usb_ac_set_selector(usb_ac_state_t *, uint_t,
241 uint_t, uint_t, uint_t, uint_t, uint_t *);
242 static int usb_ac_feature_unit_check(usb_ac_state_t *, uint_t,
243 uint_t, uint_t, uint_t, uint_t, uint_t *);
244 static int usb_ac_set_gain(usb_ac_state_t *, uint_t,
245 uint_t, uint_t, uint_t, uint_t, uint_t *);
246 static int usb_ac_set_monitor_gain(usb_ac_state_t *, uint_t,
247 uint_t, uint_t, uint_t, uint_t, uint_t *);
248 static int usb_ac_set_volume(usb_ac_state_t *, uint_t, short, int dir,
249 int);
250 static int usb_ac_get_maxmin_volume(usb_ac_state_t *, uint_t, int, int,
251 int, short *);
252 static int usb_ac_send_as_cmd(usb_ac_state_t *, usb_audio_eng_t *,
253 int, void *);
254 static int usb_ac_set_format(usb_ac_state_t *, usb_audio_eng_t *);
255 static int usb_ac_do_setup(usb_ac_state_t *, usb_audio_eng_t *);
256
257 /* usb audio basic function entries */
258 static int usb_ac_setup(usb_ac_state_t *, usb_audio_eng_t *);
259 static void usb_ac_teardown(usb_ac_state_t *, usb_audio_eng_t *);
260 static int usb_ac_start_play(usb_ac_state_t *, usb_audio_eng_t *);
261 static int usb_ac_start_record(usb_ac_state_t *, usb_audio_eng_t *);
262 static void usb_ac_stop_record(usb_ac_state_t *, usb_audio_eng_t *);
263 static int usb_ac_restore_audio_state(usb_ac_state_t *, int);
264
265 static int usb_ac_ctrl_restore(usb_ac_state_t *);
266 /*
267 * Mux
268 */
269 static int usb_ac_mux_walk_siblings(usb_ac_state_t *);
270 static void usb_ac_print_reg_data(usb_ac_state_t *,
271 usb_as_registration_t *);
272 static int usb_ac_get_reg_data(usb_ac_state_t *, ldi_handle_t, int);
273 static int usb_ac_setup_plumbed(usb_ac_state_t *, int, int);
274 static int usb_ac_mixer_registration(usb_ac_state_t *);
275 static void usb_ac_hold_siblings(usb_ac_state_t *);
276 static int usb_ac_online_siblings(usb_ac_state_t *);
277 static void usb_ac_rele_siblings(usb_ac_state_t *);
278 static int usb_ac_mux_plumbing(usb_ac_state_t *);
279 static void usb_ac_mux_plumbing_tq(void *);
280 static int usb_ac_mux_unplumbing(usb_ac_state_t *);
281 static void usb_ac_mux_unplumbing_tq(void *);
282 static int usb_ac_plumb(usb_ac_plumbed_t *);
283 static void usb_ac_unplumb(usb_ac_plumbed_t *);
284 static void usb_ac_reader(void *);
285 static int usb_ac_read_msg(usb_ac_plumbed_t *, mblk_t *);
286 static int usb_ac_do_plumbing(usb_ac_state_t *);
287 static int usb_ac_do_unplumbing(usb_ac_state_t *);
288
289
290 static int usb_change_phy_vol(usb_ac_state_t *, int);
291 static void usb_restore_engine(usb_ac_state_t *);
292
293 /* anchor for soft state structures */
294 void *usb_ac_statep;
295
296 /*
297 * DDI Structures
298 */
299
300 /* Device operations structure */
301 static struct dev_ops usb_ac_dev_ops = {
302 DEVO_REV, /* devo_rev */
303 0, /* devo_refcnt */
304 NULL, /* devo_getinfo */
305 nulldev, /* devo_identify - obsolete */
306 nulldev, /* devo_probe - not needed */
307 usb_ac_attach, /* devo_attach */
308 usb_ac_detach, /* devo_detach */
309 nodev, /* devo_reset */
310 NULL, /* devi_cb_ops */
311 NULL, /* devo_busb_ac_ops */
312 usb_ac_power, /* devo_power */
313 ddi_quiesce_not_needed, /* devo_quiesce */
314 };
315
316 /* Linkage structure for loadable drivers */
317 static struct modldrv usb_ac_modldrv = {
318 &mod_driverops, /* drv_modops */
319 "USB Audio Control Driver", /* drv_linkinfo */
320 &usb_ac_dev_ops /* drv_dev_ops */
321 };
322
323 /* Module linkage structure */
324 static struct modlinkage usb_ac_modlinkage = {
325 MODREV_1, /* ml_rev */
326 (void *)&usb_ac_modldrv, /* ml_linkage */
327 NULL /* NULL terminates the list */
328 };
329
330 static int usb_audio_register(usb_ac_state_t *);
331 static int usb_audio_unregister(usb_ac_state_t *);
332
333 static int usb_engine_open(void *, int, unsigned *, caddr_t *);
334 static void usb_engine_close(void *);
335 static uint64_t usb_engine_count(void *);
336 static int usb_engine_start(void *);
337 static void usb_engine_stop(void *);
338 static int usb_engine_format(void *);
339 static int usb_engine_channels(void *);
340 static int usb_engine_rate(void *);
341 static void usb_engine_sync(void *, unsigned);
342 static unsigned usb_engine_qlen(void *);
343
344 /* engine buffer size in terms of fragments */
345
346 audio_engine_ops_t usb_engine_ops = {
347 AUDIO_ENGINE_VERSION,
348 usb_engine_open,
349 usb_engine_close,
350 usb_engine_start,
351 usb_engine_stop,
352 usb_engine_count,
353 usb_engine_format,
354 usb_engine_channels,
355 usb_engine_rate,
356 usb_engine_sync,
357 usb_engine_qlen,
358 };
359
360
361
362 _NOTE(SCHEME_PROTECTS_DATA("unique per call", mblk_t))
363
364 /* standard entry points */
365 int
_init(void)366 _init(void)
367 {
368 int rval;
369
370 /* initialize the soft state */
371 if ((rval = ddi_soft_state_init(&usb_ac_statep,
372 sizeof (usb_ac_state_t), 1)) != DDI_SUCCESS) {
373 return (rval);
374 }
375
376 audio_init_ops(&usb_ac_dev_ops, "usb_ac");
377
378 if ((rval = mod_install(&usb_ac_modlinkage)) != 0) {
379 ddi_soft_state_fini(&usb_ac_statep);
380 audio_fini_ops(&usb_ac_dev_ops);
381 }
382
383 return (rval);
384 }
385
386 int
_fini(void)387 _fini(void)
388 {
389 int rval;
390
391 if ((rval = mod_remove(&usb_ac_modlinkage)) == 0) {
392 /* Free the soft state internal structures */
393 ddi_soft_state_fini(&usb_ac_statep);
394 audio_fini_ops(&usb_ac_dev_ops);
395 }
396
397 return (rval);
398 }
399
400 int
_info(struct modinfo * modinfop)401 _info(struct modinfo *modinfop)
402 {
403 return (mod_info(&usb_ac_modlinkage, modinfop));
404 }
405
406 extern uint_t nproc;
407 #define INIT_PROCESS_CNT 3
408
409 static int
usb_ac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)410 usb_ac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
411 {
412 usb_ac_state_t *uacp = NULL;
413 int instance = ddi_get_instance(dip);
414
415 switch (cmd) {
416 case DDI_ATTACH:
417 break;
418 case DDI_RESUME:
419 usb_ac_cpr_resume(dip);
420
421 return (DDI_SUCCESS);
422 default:
423 return (DDI_FAILURE);
424 }
425
426 /*
427 * wait until all processes are started from main.
428 * USB enumerates early in boot (ie. consconfig time).
429 * If the plumbing takes place early, the file descriptors
430 * are owned by the init process and can never be closed anymore
431 * Consequently, hot removal is not possible and the dips
432 * never go away. By waiting some time, e.g. INIT_PROCESS_CNT,
433 * the problem is avoided.
434 */
435 if (nproc < INIT_PROCESS_CNT) {
436 USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL,
437 "usb_ac%d attach too early", instance);
438
439 return (DDI_FAILURE);
440 }
441
442 /*
443 * Allocate soft state information.
444 */
445 if (ddi_soft_state_zalloc(usb_ac_statep, instance) != DDI_SUCCESS) {
446
447 goto fail;
448 }
449
450 /*
451 * get soft state space and initialize
452 */
453 uacp = (usb_ac_state_t *)ddi_get_soft_state(usb_ac_statep, instance);
454 if (uacp == NULL) {
455
456 goto fail;
457 }
458
459 /* get log handle */
460 uacp->usb_ac_log_handle = usb_alloc_log_hdl(dip, "ac",
461 &usb_ac_errlevel,
462 &usb_ac_errmask, &usb_ac_instance_debug,
463 0);
464
465 uacp->usb_ac_instance = instance;
466 uacp->usb_ac_dip = dip;
467
468 (void) snprintf(uacp->dstr, sizeof (uacp->dstr), "%s#%d",
469 ddi_driver_name(dip), instance);
470
471 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
472 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
473 "usb_client_attach failed");
474
475 usb_free_log_hdl(uacp->usb_ac_log_handle);
476 ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
477
478 return (DDI_FAILURE);
479 }
480
481 if (usb_get_dev_data(dip, &uacp->usb_ac_dev_data,
482 USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
483 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
484 "usb_get_dev_data failed");
485
486 usb_client_detach(dip, NULL);
487 usb_free_log_hdl(uacp->usb_ac_log_handle);
488 ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
489
490 return (DDI_FAILURE);
491 }
492
493 /* initialize mutex & cv */
494 mutex_init(&uacp->usb_ac_mutex, NULL, MUTEX_DRIVER,
495 uacp->usb_ac_dev_data->dev_iblock_cookie);
496
497 uacp->usb_ac_default_ph = uacp->usb_ac_dev_data->dev_default_ph;
498
499 /* parse all class specific descriptors */
500 if (usb_ac_handle_descriptors(uacp) != USB_SUCCESS) {
501
502 goto fail;
503 }
504
505 /* we no longer need the descr tree */
506 usb_free_descr_tree(dip, uacp->usb_ac_dev_data);
507
508 uacp->usb_ac_ser_acc = usb_init_serialization(dip,
509 USB_INIT_SER_CHECK_SAME_THREAD);
510
511 mutex_enter(&uacp->usb_ac_mutex);
512
513 /* we are online */
514 uacp->usb_ac_dev_state = USB_DEV_ONLINE;
515
516 /*
517 * safe guard the postattach to be executed
518 * only two states arepossible: plumbed / unplumbed
519 */
520 uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
521 uacp->usb_ac_current_plumbed_index = -1;
522
523 mutex_exit(&uacp->usb_ac_mutex);
524
525 /* create components to power manage this device */
526 usb_ac_create_pm_components(dip, uacp);
527
528 /* Register for events */
529 if (usb_register_event_cbs(dip, &usb_ac_events, 0) != USB_SUCCESS) {
530 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
531 "usb_ac_attach: couldn't register for events");
532
533 goto fail;
534 }
535
536 USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
537 "usb_ac_attach: End");
538
539 /* report device */
540 ddi_report_dev(dip);
541
542 if (usb_ac_do_plumbing(uacp) != USB_SUCCESS)
543 goto fail;
544
545 return (DDI_SUCCESS);
546
547 fail:
548 if (uacp) {
549 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
550 "attach failed");
551
552 /* wait for plumbing thread to finish */
553 if (uacp->tqp != NULL) {
554 ddi_taskq_wait(uacp->tqp);
555 ddi_taskq_destroy(uacp->tqp);
556 uacp->tqp = NULL;
557 }
558 (void) usb_ac_cleanup(dip, uacp);
559 }
560
561 return (DDI_FAILURE);
562 }
563
564
565 static int
usb_ac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)566 usb_ac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
567 {
568 int instance = ddi_get_instance(dip);
569 usb_ac_state_t *uacp;
570 int rval = USB_FAILURE;
571
572 uacp = ddi_get_soft_state(usb_ac_statep, instance);
573
574 switch (cmd) {
575 case DDI_DETACH:
576 USB_DPRINTF_L4(PRINT_MASK_ATTA,
577 uacp->usb_ac_log_handle, "usb_ac_detach: detach");
578
579 /* wait for plumbing thread to finish */
580 if (uacp->tqp != NULL)
581 ddi_taskq_wait(uacp->tqp);
582
583 mutex_enter(&uacp->usb_ac_mutex);
584
585 /* do not allow detach if still busy */
586 if (uacp->usb_ac_busy_count) {
587 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
588 "usb_ac_detach:still busy, usb_ac_busy_count = %d",
589 uacp->usb_ac_busy_count);
590
591 mutex_exit(&uacp->usb_ac_mutex);
592 return (USB_FAILURE);
593 }
594 mutex_exit(&uacp->usb_ac_mutex);
595
596 (void) usb_audio_unregister(uacp);
597
598
599
600 /*
601 * unplumb to stop activity from other modules, then
602 * cleanup, which will also teardown audio framework state
603 */
604 if (usb_ac_do_unplumbing(uacp) == USB_SUCCESS)
605 rval = usb_ac_cleanup(dip, uacp);
606
607 if (rval != USB_SUCCESS) {
608 USB_DPRINTF_L2(PRINT_MASK_ATTA,
609 uacp->usb_ac_log_handle, "detach failed: %s%d",
610 ddi_driver_name(dip), instance);
611 }
612
613 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
614 case DDI_SUSPEND:
615 USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
616 "usb_ac_detach: suspending");
617
618 rval = usb_ac_cpr_suspend(dip);
619
620 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
621 default:
622
623 return (DDI_FAILURE);
624 }
625 }
626
627
628 /*
629 * usb_ac_cleanup:
630 * cleanup on attach failure and detach
631 */
632 static int
usb_ac_cleanup(dev_info_t * dip,usb_ac_state_t * uacp)633 usb_ac_cleanup(dev_info_t *dip, usb_ac_state_t *uacp)
634 {
635 usb_ac_power_t *uacpm;
636 int rval = USB_FAILURE;
637
638
639 mutex_enter(&uacp->usb_ac_mutex);
640 uacpm = uacp->usb_ac_pm;
641
642 USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
643 "usb_ac_cleanup:begain");
644
645 ASSERT(uacp->usb_ac_busy_count == 0);
646
647 ASSERT(uacp->usb_ac_plumbing_state == USB_AC_STATE_UNPLUMBED);
648
649 mutex_exit(&uacp->usb_ac_mutex);
650
651 /*
652 * Disable the event callbacks, after this point, event
653 * callbacks will never get called. Note we shouldn't hold
654 * the mutex while unregistering events because there may be a
655 * competing event callback thread. Event callbacks are done
656 * with ndi mutex held and this can cause a potential deadlock.
657 */
658 usb_unregister_event_cbs(dip, &usb_ac_events);
659
660 mutex_enter(&uacp->usb_ac_mutex);
661
662 if (uacpm && (uacp->usb_ac_dev_state != USB_DEV_DISCONNECTED)) {
663 if (uacpm->acpm_wakeup_enabled) {
664 mutex_exit(&uacp->usb_ac_mutex);
665 usb_ac_pm_busy_component(uacp);
666 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
667
668 rval = usb_handle_remote_wakeup(dip,
669 USB_REMOTE_WAKEUP_DISABLE);
670 if (rval != USB_SUCCESS) {
671 USB_DPRINTF_L2(PRINT_MASK_PM,
672 uacp->usb_ac_log_handle,
673 "usb_ac_cleanup: disable remote "
674 "wakeup failed, rval=%d", rval);
675 }
676 usb_ac_pm_idle_component(uacp);
677 } else {
678 mutex_exit(&uacp->usb_ac_mutex);
679 }
680
681 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
682
683 mutex_enter(&uacp->usb_ac_mutex);
684 }
685
686 if (uacpm) {
687 kmem_free(uacpm, sizeof (usb_ac_power_t));
688 uacp->usb_ac_pm = NULL;
689 }
690
691 usb_client_detach(dip, uacp->usb_ac_dev_data);
692
693 /* free descriptors */
694 usb_ac_free_all_units(uacp);
695
696 mutex_exit(&uacp->usb_ac_mutex);
697
698 mutex_destroy(&uacp->usb_ac_mutex);
699
700 usb_fini_serialization(uacp->usb_ac_ser_acc);
701
702 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
703 "usb_ac_cleanup: Ending");
704
705 usb_free_log_hdl(uacp->usb_ac_log_handle);
706 kmem_free(uacp->usb_ac_connections, uacp->usb_ac_connections_len);
707 kmem_free(uacp->usb_ac_connections_a, uacp->usb_ac_connections_a_len);
708 kmem_free(uacp->usb_ac_unit_type, uacp->usb_ac_max_unit);
709 kmem_free(uacp->usb_ac_traverse_path, uacp->usb_ac_max_unit);
710
711 ddi_soft_state_free(usb_ac_statep, uacp->usb_ac_instance);
712
713 ddi_prop_remove_all(dip);
714
715 return (USB_SUCCESS);
716 }
717
718
719 int
usb_ac_open(dev_info_t * dip)720 usb_ac_open(dev_info_t *dip)
721 {
722 int inst = ddi_get_instance(dip);
723 usb_ac_state_t *uacp = ddi_get_soft_state(usb_ac_statep, inst);
724
725 mutex_enter(&uacp->usb_ac_mutex);
726
727 uacp->usb_ac_busy_count++;
728
729 mutex_exit(&uacp->usb_ac_mutex);
730
731 usb_ac_pm_busy_component(uacp);
732 (void) pm_raise_power(uacp->usb_ac_dip, 0, USB_DEV_OS_FULL_PWR);
733
734 return (0);
735 }
736
737
738 void
usb_ac_close(dev_info_t * dip)739 usb_ac_close(dev_info_t *dip)
740 {
741 int inst = ddi_get_instance(dip);
742 usb_ac_state_t *uacp = ddi_get_soft_state(usb_ac_statep, inst);
743
744 mutex_enter(&uacp->usb_ac_mutex);
745
746 if (uacp->usb_ac_busy_count > 0)
747 uacp->usb_ac_busy_count--;
748
749 mutex_exit(&uacp->usb_ac_mutex);
750
751 usb_ac_pm_idle_component(uacp);
752 }
753
754
755 /*
756 * usb_ac_read_msg:
757 * Handle asynchronous response from opened streams
758 */
759 static int
usb_ac_read_msg(usb_ac_plumbed_t * plumb_infop,mblk_t * mp)760 usb_ac_read_msg(usb_ac_plumbed_t *plumb_infop, mblk_t *mp)
761 {
762 usb_ac_state_t *uacp = plumb_infop->acp_uacp;
763 int error = DDI_SUCCESS;
764 int val;
765 char val1;
766 struct iocblk *iocp;
767
768
769 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
770
771 /*
772 * typically an M_CTL is used between modules but in order to pass
773 * through the streamhead, an M_PROTO type must be used instead
774 */
775 switch (mp->b_datap->db_type) {
776 case M_PROTO:
777 case M_ERROR:
778 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
779 "M_CTL/M_ERROR");
780
781 switch (plumb_infop->acp_driver) {
782 case USB_AH_PLUMBED:
783 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
784 "message from hid, instance=%d",
785 ddi_get_instance(plumb_infop->acp_dip));
786
787 iocp = (struct iocblk *)(void *)mp->b_rptr;
788 ASSERT(mp->b_cont != NULL);
789
790 if (uacp->usb_ac_registered_with_mixer) {
791
792 val1 = *((char *)mp->b_cont->b_rptr);
793 val = (int)val1;
794
795 USB_DPRINTF_L4(PRINT_MASK_ALL,
796 uacp->usb_ac_log_handle, "val1=0x%x(%d),"
797 "val=0x%x(%d)", val1, val1, val, val);
798
799 switch (iocp->ioc_cmd) {
800 /* Handle relative volume change */
801 case USB_AUDIO_VOL_CHANGE:
802 /* prevent unplumbing */
803 uacp->usb_ac_busy_count++;
804 if (uacp->usb_ac_plumbing_state ==
805 USB_AC_STATE_PLUMBED) {
806 mutex_exit(&uacp->usb_ac_mutex);
807 (void) usb_change_phy_vol(
808 uacp, val);
809 mutex_enter(&uacp->
810 usb_ac_mutex);
811 }
812 uacp->usb_ac_busy_count--;
813 /* FALLTHRU */
814 case USB_AUDIO_MUTE:
815 default:
816 freemsg(mp);
817 break;
818 }
819 } else {
820 freemsg(mp);
821 }
822
823 break;
824 default:
825 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
826 "message from unknown module(%s)",
827 ddi_driver_name(plumb_infop->acp_dip));
828 freemsg(mp);
829 }
830
831 break;
832 default:
833 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
834 "Unknown type=%d", mp->b_datap->db_type);
835 freemsg(mp);
836 }
837
838
839 return (error);
840 }
841
842
843 /*
844 * Power Management
845 * usb_ac_power:
846 * power entry point
847 */
848 static int
usb_ac_power(dev_info_t * dip,int comp,int level)849 usb_ac_power(dev_info_t *dip, int comp, int level)
850 {
851 _NOTE(ARGUNUSED(comp));
852 int instance = ddi_get_instance(dip);
853 usb_ac_state_t *uacp;
854 usb_ac_power_t *uacpm;
855 int rval = DDI_FAILURE;
856
857 uacp = ddi_get_soft_state(usb_ac_statep, instance);
858
859 mutex_enter(&uacp->usb_ac_mutex);
860 uacpm = uacp->usb_ac_pm;
861
862 if (USB_DEV_PWRSTATE_OK(uacpm->acpm_pwr_states, level)) {
863 USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
864 "usb_ac_power: illegal level=%d pwr_states=%d",
865 level, uacpm->acpm_pwr_states);
866
867 goto done;
868 }
869
870 switch (level) {
871 case USB_DEV_OS_PWR_OFF:
872 rval = usb_ac_pwrlvl0(uacp);
873 break;
874 case USB_DEV_OS_PWR_1:
875 rval = usb_ac_pwrlvl1(uacp);
876 break;
877 case USB_DEV_OS_PWR_2:
878 rval = usb_ac_pwrlvl2(uacp);
879 break;
880 case USB_DEV_OS_FULL_PWR:
881 rval = usb_ac_pwrlvl3(uacp);
882 break;
883 }
884
885 done:
886 mutex_exit(&uacp->usb_ac_mutex);
887
888 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
889 }
890
891
892 /*
893 * functions to handle power transition for various levels
894 * These functions act as place holders to issue USB commands
895 * to the devices to change their power levels
896 * Level 0 = Device is powered off
897 * Level 3 = Device if full powered
898 * Level 1,2 = Intermediate power level of the device as implemented
899 * by the hardware.
900 * Note that Level 0 is OS power-off and Level 3 is OS full-power.
901 */
902 static int
usb_ac_pwrlvl0(usb_ac_state_t * uacp)903 usb_ac_pwrlvl0(usb_ac_state_t *uacp)
904 {
905 usb_ac_power_t *uacpm;
906 int rval;
907
908 uacpm = uacp->usb_ac_pm;
909
910 switch (uacp->usb_ac_dev_state) {
911 case USB_DEV_ONLINE:
912 /* Deny the powerdown request if the device is busy */
913 if (uacpm->acpm_pm_busy != 0) {
914
915 return (USB_FAILURE);
916 }
917
918 /* Issue USB D3 command to the device here */
919 rval = usb_set_device_pwrlvl3(uacp->usb_ac_dip);
920 ASSERT(rval == USB_SUCCESS);
921
922 uacp->usb_ac_dev_state = USB_DEV_PWRED_DOWN;
923 uacpm->acpm_current_power = USB_DEV_OS_PWR_OFF;
924
925 /* FALLTHRU */
926 case USB_DEV_DISCONNECTED:
927 case USB_DEV_SUSPENDED:
928 case USB_DEV_PWRED_DOWN:
929 default:
930 return (USB_SUCCESS);
931 }
932 }
933
934
935 /* ARGSUSED */
936 static int
usb_ac_pwrlvl1(usb_ac_state_t * uacp)937 usb_ac_pwrlvl1(usb_ac_state_t *uacp)
938 {
939 int rval;
940
941 /* Issue USB D2 command to the device here */
942 rval = usb_set_device_pwrlvl2(uacp->usb_ac_dip);
943 ASSERT(rval == USB_SUCCESS);
944
945 return (USB_FAILURE);
946 }
947
948
949 /* ARGSUSED */
950 static int
usb_ac_pwrlvl2(usb_ac_state_t * uacp)951 usb_ac_pwrlvl2(usb_ac_state_t *uacp)
952 {
953 int rval;
954
955 rval = usb_set_device_pwrlvl1(uacp->usb_ac_dip);
956 ASSERT(rval == USB_SUCCESS);
957
958 return (USB_FAILURE);
959 }
960
961
962 static int
usb_ac_pwrlvl3(usb_ac_state_t * uacp)963 usb_ac_pwrlvl3(usb_ac_state_t *uacp)
964 {
965 usb_ac_power_t *uacpm;
966 int rval;
967
968 uacpm = uacp->usb_ac_pm;
969
970 switch (uacp->usb_ac_dev_state) {
971 case USB_DEV_PWRED_DOWN:
972 /* Issue USB D0 command to the device here */
973 rval = usb_set_device_pwrlvl0(uacp->usb_ac_dip);
974 ASSERT(rval == USB_SUCCESS);
975
976 uacp->usb_ac_dev_state = USB_DEV_ONLINE;
977 uacpm->acpm_current_power = USB_DEV_OS_FULL_PWR;
978 /* FALLTHRU */
979 case USB_DEV_ONLINE:
980 /* we are already in full power */
981
982 /* FALLTHRU */
983 case USB_DEV_DISCONNECTED:
984 case USB_DEV_SUSPENDED:
985
986 return (USB_SUCCESS);
987 default:
988 USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
989 "usb_ac_pwerlvl3: Illegal dev_state");
990
991 return (USB_FAILURE);
992 }
993 }
994
995
996 static void
usb_ac_create_pm_components(dev_info_t * dip,usb_ac_state_t * uacp)997 usb_ac_create_pm_components(dev_info_t *dip, usb_ac_state_t *uacp)
998 {
999 usb_ac_power_t *uacpm;
1000 uint_t pwr_states;
1001
1002 USB_DPRINTF_L4(PRINT_MASK_PM, uacp->usb_ac_log_handle,
1003 "usb_ac_create_pm_components: begin");
1004
1005 /* Allocate the state structure */
1006 uacpm = kmem_zalloc(sizeof (usb_ac_power_t), KM_SLEEP);
1007 uacp->usb_ac_pm = uacpm;
1008 uacpm->acpm_state = uacp;
1009 uacpm->acpm_capabilities = 0;
1010 uacpm->acpm_current_power = USB_DEV_OS_FULL_PWR;
1011
1012 if (usb_create_pm_components(dip, &pwr_states) ==
1013 USB_SUCCESS) {
1014 if (usb_handle_remote_wakeup(dip,
1015 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
1016 uacpm->acpm_wakeup_enabled = 1;
1017
1018 USB_DPRINTF_L4(PRINT_MASK_PM,
1019 uacp->usb_ac_log_handle,
1020 "remote Wakeup enabled");
1021 }
1022 uacpm->acpm_pwr_states = (uint8_t)pwr_states;
1023 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1024 } else {
1025 if (uacpm) {
1026 kmem_free(uacpm, sizeof (usb_ac_power_t));
1027 uacp->usb_ac_pm = NULL;
1028 }
1029 USB_DPRINTF_L2(PRINT_MASK_PM, uacp->usb_ac_log_handle,
1030 "pm not enabled");
1031 }
1032
1033 }
1034
1035 /*
1036 * usb_ac_get_featureID:
1037 * find out if there is at least one feature unit that supports
1038 * the request controls.
1039 * Return featureID or USB_AC_ID_NONE.
1040 */
1041 static uint_t
usb_ac_get_featureID(usb_ac_state_t * uacp,uchar_t dir,uint_t channel,uint_t control)1042 usb_ac_get_featureID(usb_ac_state_t *uacp, uchar_t dir,
1043 uint_t channel, uint_t control)
1044 {
1045 uint_t count = 0;
1046
1047 return (usb_ac_set_control(uacp, dir, USB_AUDIO_FEATURE_UNIT,
1048 channel, control, USB_AC_FIND_ONE, &count, 0,
1049 usb_ac_feature_unit_check));
1050 }
1051
1052
1053 /*
1054 * usb_ac_feature_unit_check:
1055 * check if a feature unit can support the required channel
1056 * and control combination. Return USB_SUCCESS or USB_FAILURE.
1057 * Called for each matching unit from usb_ac_traverse_connections.
1058 */
1059 /*ARGSUSED*/
1060 static int
usb_ac_feature_unit_check(usb_ac_state_t * uacp,uint_t featureID,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth)1061 usb_ac_feature_unit_check(usb_ac_state_t *uacp, uint_t featureID,
1062 uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
1063 {
1064 usb_audio_feature_unit_descr1_t *feature_descrp;
1065 int n_channel_controls;
1066
1067
1068 ASSERT(featureID < uacp->usb_ac_max_unit);
1069
1070 /*
1071 * check if this control is supported on this channel
1072 */
1073 feature_descrp = (usb_audio_feature_unit_descr1_t *)
1074 uacp->usb_ac_units[featureID].acu_descriptor;
1075 ASSERT(feature_descrp->bUnitID == featureID);
1076
1077 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1078 "bControlSize=%d", feature_descrp->bControlSize);
1079
1080 if (feature_descrp->bControlSize == 0) {
1081 featureID = USB_AC_ID_NONE;
1082 } else {
1083 uint_t index;
1084
1085 n_channel_controls = (feature_descrp->bLength -
1086 offsetof(usb_audio_feature_unit_descr1_t,
1087 bmaControls))/feature_descrp->bControlSize;
1088
1089 USB_DPRINTF_L3(PRINT_MASK_ALL,
1090 uacp->usb_ac_log_handle,
1091 "#controls: %d index=%d", n_channel_controls,
1092 feature_descrp->bControlSize * channel);
1093
1094 if (channel > n_channel_controls) {
1095 featureID = USB_AC_ID_NONE;
1096 } else {
1097 /*
1098 * we only support MUTE and VOLUME
1099 * which are in the first byte
1100 */
1101 index = feature_descrp->bControlSize *
1102 channel;
1103
1104 USB_DPRINTF_L3(PRINT_MASK_ALL,
1105 uacp->usb_ac_log_handle,
1106 "control: 0x%x",
1107 feature_descrp->bmaControls[index]);
1108
1109 if ((feature_descrp->bmaControls[index] &
1110 control) == 0) {
1111 featureID = USB_AC_ID_NONE;
1112 }
1113 }
1114 }
1115
1116 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1117 "usb_ac_feature_unit_check: dir=%d featureID=0x%x",
1118 dir, featureID);
1119
1120 return ((featureID != USB_AC_ID_NONE) ?
1121 USB_SUCCESS : USB_FAILURE);
1122 }
1123
1124
1125 /*
1126 * Descriptor Management
1127 *
1128 * usb_ac_handle_descriptors:
1129 * extract interesting descriptors from the config cloud
1130 */
1131 static int
usb_ac_handle_descriptors(usb_ac_state_t * uacp)1132 usb_ac_handle_descriptors(usb_ac_state_t *uacp)
1133 {
1134 int len, index;
1135 int rval = USB_FAILURE;
1136 usb_audio_cs_if_descr_t descr;
1137 usb_client_dev_data_t *dev_data = uacp->usb_ac_dev_data;
1138 usb_alt_if_data_t *altif_data;
1139 usb_cvs_data_t *cvs;
1140
1141
1142 altif_data = &dev_data->dev_curr_cfg->
1143 cfg_if[dev_data->dev_curr_if].if_alt[0];
1144
1145 uacp->usb_ac_ifno = dev_data->dev_curr_if;
1146 uacp->usb_ac_if_descr = altif_data->altif_descr;
1147
1148 /* find USB_AUDIO_CS_INTERFACE type descriptor */
1149 for (index = 0; index < altif_data->altif_n_cvs; index++) {
1150 cvs = &altif_data->altif_cvs[index];
1151 if (cvs->cvs_buf == NULL) {
1152 continue;
1153 }
1154 if (cvs->cvs_buf[1] == USB_AUDIO_CS_INTERFACE) {
1155 break;
1156 }
1157 }
1158
1159 if (index == altif_data->altif_n_cvs) {
1160 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1161 "usb_ac_handle_descriptors:cannot find descriptor type %d",
1162 USB_AUDIO_CS_INTERFACE);
1163
1164 return (rval);
1165 }
1166
1167 len = usb_parse_data(
1168 CS_AC_IF_HEADER_FORMAT,
1169 cvs->cvs_buf, cvs->cvs_buf_len,
1170 (void *)&descr, sizeof (usb_audio_cs_if_descr_t));
1171
1172 /* is this a sane header descriptor */
1173 if (!((len >= CS_AC_IF_HEADER_SIZE) &&
1174 (descr.bDescriptorType == USB_AUDIO_CS_INTERFACE) &&
1175 (descr.bDescriptorSubType == USB_AUDIO_HEADER))) {
1176 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1177 "invalid header");
1178
1179 return (rval);
1180 }
1181
1182 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1183 "index %d, header: type=0x%x subtype=0x%x bcdADC=0x%x\n\t"
1184 "total=0x%x InCol=0x%x",
1185 index,
1186 descr.bDescriptorType,
1187 descr.bDescriptorSubType,
1188 descr.bcdADC,
1189 descr.wTotalLength,
1190 descr.blnCollection);
1191
1192 /*
1193 * we read descriptors by index and store them in ID array.
1194 * the actual parsing is done in usb_ac_add_unit_descriptor()
1195 */
1196 for (index++; index < altif_data->altif_n_cvs; index++) {
1197 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1198 "index=%d", index);
1199
1200 cvs = &altif_data->altif_cvs[index];
1201 if (cvs->cvs_buf == NULL) {
1202 continue;
1203 }
1204
1205 /* add to ID array */
1206 usb_ac_add_unit_descriptor(uacp, cvs->cvs_buf,
1207 cvs->cvs_buf_len);
1208 }
1209 rval = USB_SUCCESS;
1210
1211 usb_ac_setup_connections(uacp);
1212
1213 /* determine port types */
1214 usb_ac_map_termtype_to_port(uacp, USB_AUDIO_PLAY);
1215 usb_ac_map_termtype_to_port(uacp, USB_AUDIO_RECORD);
1216
1217
1218 return (rval);
1219 }
1220
1221
1222 /*
1223 * usb_ac_setup_connections:
1224 * build a matrix reflecting all connections
1225 */
1226 static void
usb_ac_setup_connections(usb_ac_state_t * uacp)1227 usb_ac_setup_connections(usb_ac_state_t *uacp)
1228 {
1229 usb_ac_unit_list_t *units = uacp->usb_ac_units;
1230 uchar_t *a, **p, i, unit;
1231 size_t a_len, p_len;
1232
1233 /* allocate array for unit types for quick reference */
1234 uacp->usb_ac_unit_type = kmem_zalloc(uacp->usb_ac_max_unit,
1235 KM_SLEEP);
1236 /* allocate array for traversal path */
1237 uacp->usb_ac_traverse_path = kmem_zalloc(uacp->usb_ac_max_unit,
1238 KM_SLEEP);
1239
1240
1241 /* allocate the connection matrix and set it up */
1242 a_len = uacp->usb_ac_max_unit * uacp->usb_ac_max_unit;
1243 p_len = uacp->usb_ac_max_unit * sizeof (uchar_t *);
1244
1245 /* trick to create a 2 dimensional array */
1246 a = kmem_zalloc(a_len, KM_SLEEP);
1247 p = kmem_zalloc(p_len, KM_SLEEP);
1248 for (i = 0; i < uacp->usb_ac_max_unit; i++) {
1249 p[i] = a + i * uacp->usb_ac_max_unit;
1250 }
1251 uacp->usb_ac_connections = p;
1252 uacp->usb_ac_connections_len = p_len;
1253 uacp->usb_ac_connections_a = a;
1254 uacp->usb_ac_connections_a_len = a_len;
1255
1256 /* traverse all units and set connections */
1257 for (unit = 0; unit < uacp->usb_ac_max_unit; unit++) {
1258
1259 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1260 "--------traversing unit=0x%x type=0x%x--------",
1261 unit, units[unit].acu_type);
1262
1263 /* store type in the first unused column */
1264 uacp->usb_ac_unit_type[unit] = units[unit].acu_type;
1265
1266 /* save the Unit ID in the unit it points to */
1267 switch (units[unit].acu_type) {
1268 case USB_AUDIO_FEATURE_UNIT:
1269 {
1270 usb_audio_feature_unit_descr1_t *d =
1271 units[unit].acu_descriptor;
1272
1273 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1274 "USB_AUDIO_FEATURE_UNIT:sourceID=0x%x type=0x%x",
1275 d->bSourceID, units[d->bSourceID].acu_type);
1276
1277 if (d->bSourceID != 0) {
1278 ASSERT(p[unit][d->bSourceID] == B_FALSE);
1279 p[unit][d->bSourceID] = B_TRUE;
1280 }
1281
1282 break;
1283 }
1284 case USB_AUDIO_OUTPUT_TERMINAL:
1285 {
1286 usb_audio_output_term_descr_t *d =
1287 units[unit].acu_descriptor;
1288
1289 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1290 "USB_AUDIO_OUTPUT_TERMINAL:sourceID=0x%x type=0x%x",
1291 d->bSourceID, units[d->bSourceID].acu_type);
1292
1293 if (d->bSourceID != 0) {
1294 ASSERT(p[unit][d->bSourceID] == B_FALSE);
1295 p[unit][d->bSourceID] = B_TRUE;
1296 }
1297
1298 break;
1299 }
1300 case USB_AUDIO_MIXER_UNIT:
1301 {
1302 usb_audio_mixer_unit_descr1_t *d =
1303 units[unit].acu_descriptor;
1304 int n_sourceID = d->bNrInPins;
1305 int id;
1306
1307 for (id = 0; id < n_sourceID; id++) {
1308 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1309 uacp->usb_ac_log_handle,
1310 "USB_AUDIO_MIXER_UNIT:sourceID=0x%x"
1311 "type=0x%x c=%d",
1312 d->baSourceID[id],
1313 units[d->baSourceID[id]].acu_type,
1314 p[unit][d->baSourceID[id]]);
1315
1316 if (d->baSourceID[id] != 0) {
1317 ASSERT(p[unit][d->baSourceID[id]] ==
1318 B_FALSE);
1319 p[unit][d->baSourceID[id]] = B_TRUE;
1320 }
1321 }
1322
1323 break;
1324 }
1325 case USB_AUDIO_SELECTOR_UNIT:
1326 {
1327 usb_audio_selector_unit_descr1_t *d =
1328 units[unit].acu_descriptor;
1329 int n_sourceID = d->bNrInPins;
1330 int id;
1331
1332 for (id = 0; id < n_sourceID; id++) {
1333 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1334 uacp->usb_ac_log_handle,
1335 "USB_AUDIO_SELECTOR_UNIT:sourceID=0x%x"
1336 " type=0x%x", d->baSourceID[id],
1337 units[d->baSourceID[id]].acu_type);
1338
1339 if (d->baSourceID[id] != 0) {
1340 ASSERT(p[unit][d->baSourceID[id]] ==
1341 B_FALSE);
1342 p[unit][d->baSourceID[id]] = B_TRUE;
1343 }
1344 }
1345
1346 break;
1347 }
1348 case USB_AUDIO_PROCESSING_UNIT:
1349 {
1350 usb_audio_mixer_unit_descr1_t *d =
1351 units[unit].acu_descriptor;
1352 int n_sourceID = d->bNrInPins;
1353 int id;
1354
1355 for (id = 0; id < n_sourceID; id++) {
1356 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1357 uacp->usb_ac_log_handle,
1358 "USB_AUDIO_PROCESSING_UNIT:sourceID=0x%x"
1359 " type=0x%x", d->baSourceID[id],
1360 units[d->baSourceID[id]].acu_type);
1361
1362 if (d->baSourceID[id] != 0) {
1363 ASSERT(p[unit][d->baSourceID[id]] ==
1364 B_FALSE);
1365 p[unit][d->baSourceID[id]] = B_TRUE;
1366 }
1367 }
1368
1369 break;
1370 }
1371 case USB_AUDIO_EXTENSION_UNIT:
1372 {
1373 usb_audio_extension_unit_descr1_t *d =
1374 units[unit].acu_descriptor;
1375 int n_sourceID = d->bNrInPins;
1376 int id;
1377
1378 for (id = 0; id < n_sourceID; id++) {
1379 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1380 uacp->usb_ac_log_handle,
1381 "USB_AUDIO_EXTENSION_UNIT:sourceID=0x%x"
1382 "type=0x%x", d->baSourceID[id],
1383 units[d->baSourceID[id]].acu_type);
1384
1385 if (d->baSourceID[id] != 0) {
1386 ASSERT(p[unit][d->baSourceID[id]] ==
1387 B_TRUE);
1388 p[unit][d->baSourceID[id]] = B_FALSE;
1389 }
1390 }
1391
1392 break;
1393 }
1394 case USB_AUDIO_INPUT_TERMINAL:
1395
1396 break;
1397 default:
1398 /*
1399 * Ignore the rest because they are not support yet
1400 */
1401 break;
1402 }
1403 }
1404
1405 #ifdef DEBUG
1406 /* display topology in log buffer */
1407 {
1408 uint_t i, j, l;
1409 char *buf;
1410
1411 l = uacp->usb_ac_max_unit * 5;
1412
1413 buf = kmem_alloc(l, KM_SLEEP);
1414
1415 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1416 "unit types:");
1417
1418 /* two strings so they won't be replaced accidentily by tab */
1419 (void) sprintf(&buf[0], " "" ");
1420 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1421 (void) sprintf(&buf[2 + (i*3)], "%02d ", i);
1422 }
1423 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1424
1425 (void) sprintf(&buf[0], " +-------");
1426 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1427 (void) sprintf(&buf[5+((i-1)*3)], "---");
1428 }
1429 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1430
1431 (void) sprintf(&buf[0], " "" ");
1432 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1433 (void) sprintf(&buf[2 + (i*3)], "%02d ",
1434 uacp->usb_ac_unit_type[i]);
1435 }
1436 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1437 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, " ");
1438
1439 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
1440 "adjacency matrix:");
1441 (void) sprintf(&buf[0], " "" ");
1442 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1443 (void) sprintf(&buf[2 + (i*3)], "%02d ", i);
1444 }
1445 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1446
1447 (void) sprintf(&buf[0], " +-------");
1448 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1449 (void) sprintf(&buf[5+((i-1)*3)], "---");
1450 }
1451 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1452
1453 for (i = 1; i < uacp->usb_ac_max_unit; i++) {
1454 (void) sprintf(&buf[0], "%02d| "" ", i);
1455 for (j = 1; j < uacp->usb_ac_max_unit; j++) {
1456 (void) sprintf(&buf[1+(j * 3)], "%2d ", p[i][j]);
1457 }
1458 USB_DPRINTF_L3(PRINT_MASK_ATTA, uacp->usb_ac_log_handle, buf);
1459 }
1460 kmem_free(buf, l);
1461 }
1462 #endif
1463 }
1464
1465
1466 /*
1467 * usb_ac_add_unit_descriptor:
1468 * take the parsed descriptor in the buffer and store it in the ID unit
1469 * array. we grow the unit array if the ID exceeds the current max
1470 */
1471 static void
usb_ac_add_unit_descriptor(usb_ac_state_t * uacp,uchar_t * buffer,size_t buflen)1472 usb_ac_add_unit_descriptor(usb_ac_state_t *uacp, uchar_t *buffer,
1473 size_t buflen)
1474 {
1475 void *descr;
1476 int len;
1477 char *format;
1478 size_t size;
1479
1480
1481 /* doubling the length should allow for padding */
1482 len = 2 * buffer[0];
1483 descr = kmem_zalloc(len, KM_SLEEP);
1484
1485 switch (buffer[2]) {
1486 case USB_AUDIO_INPUT_TERMINAL:
1487 format = CS_AC_INPUT_TERM_FORMAT;
1488 size = CS_AC_INPUT_TERM_SIZE;
1489
1490 break;
1491 case USB_AUDIO_OUTPUT_TERMINAL:
1492 format = CS_AC_OUTPUT_TERM_FORMAT;
1493 size = CS_AC_OUTPUT_TERM_SIZE;
1494
1495 break;
1496 case USB_AUDIO_MIXER_UNIT:
1497 format = CS_AC_MIXER_UNIT_DESCR1_FORMAT "255c";
1498 size = CS_AC_MIXER_UNIT_DESCR1_SIZE + buffer[4] - 1;
1499
1500 break;
1501 case USB_AUDIO_SELECTOR_UNIT:
1502 format = CS_AC_SELECTOR_UNIT_DESCR1_FORMAT "255c";
1503 size = CS_AC_SELECTOR_UNIT_DESCR1_SIZE + buffer[4] - 1;
1504
1505 break;
1506 case USB_AUDIO_FEATURE_UNIT:
1507 format = CS_AC_FEATURE_UNIT_FORMAT "255c";
1508 size = CS_AC_FEATURE_UNIT_SIZE;
1509
1510 break;
1511 case USB_AUDIO_PROCESSING_UNIT:
1512 format = CS_AC_PROCESSING_UNIT_DESCR1_FORMAT "255c";
1513 size = CS_AC_PROCESSING_UNIT_DESCR1_SIZE + buffer[6] - 1;
1514
1515 break;
1516 case USB_AUDIO_EXTENSION_UNIT:
1517 format = CS_AC_EXTENSION_UNIT_DESCR1_FORMAT "255c";
1518 size = CS_AC_EXTENSION_UNIT_DESCR1_SIZE + buffer[6] - 1;
1519
1520 break;
1521 default:
1522 USB_DPRINTF_L2(PRINT_MASK_ATTA,
1523 uacp->usb_ac_log_handle,
1524 "unsupported descriptor %d", buffer[2]);
1525
1526 /* ignore this descriptor */
1527 kmem_free(descr, len);
1528
1529 return;
1530 }
1531
1532 if (usb_parse_data(format, buffer, buflen, descr, len) < size) {
1533 /* ignore this descriptor */
1534 kmem_free(descr, len);
1535
1536 return;
1537 }
1538
1539 switch (buffer[2]) {
1540 case USB_AUDIO_INPUT_TERMINAL:
1541 {
1542 usb_audio_input_term_descr_t *d =
1543 (usb_audio_input_term_descr_t *)descr;
1544
1545 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1546 uacp->usb_ac_log_handle,
1547 "usb_ac_units[%d] ---input term: type=0x%x sub=0x%x"
1548 "termid=0x%x\n\t"
1549 "termtype=0x%x assoc=0x%x #ch=%d "
1550 "chconf=0x%x ich=0x%x iterm=0x%x",
1551 d->bTerminalID,
1552 d->bDescriptorType, d->bDescriptorSubType,
1553 d->bTerminalID, d->wTerminalType,
1554 d->bAssocTerminal, d->bNrChannels,
1555 d->wChannelConfig, d->iChannelNames,
1556 d->iTerminal);
1557
1558 usb_ac_alloc_unit(uacp, d->bTerminalID);
1559 uacp->usb_ac_units[d->bTerminalID].acu_descriptor = descr;
1560 uacp->usb_ac_units[d->bTerminalID].acu_type = buffer[2];
1561 uacp->usb_ac_units[d->bTerminalID].acu_descr_length = len;
1562
1563 break;
1564 }
1565 case USB_AUDIO_OUTPUT_TERMINAL:
1566 {
1567 usb_audio_output_term_descr_t *d =
1568 (usb_audio_output_term_descr_t *)descr;
1569
1570 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1571 uacp->usb_ac_log_handle,
1572 "usb_ac_units[%d] ---output term: type=0x%x sub=0x%x"
1573 " termid=0x%x\n\t"
1574 "termtype=0x%x assoc=0x%x sourceID=0x%x iterm=0x%x",
1575 d->bTerminalID,
1576 d->bDescriptorType, d->bDescriptorSubType,
1577 d->bTerminalID, d->wTerminalType,
1578 d->bAssocTerminal, d->bSourceID,
1579 d->iTerminal);
1580
1581 usb_ac_alloc_unit(uacp, d->bTerminalID);
1582 uacp->usb_ac_units[d->bTerminalID].acu_descriptor = descr;
1583 uacp->usb_ac_units[d->bTerminalID].acu_type = buffer[2];
1584 uacp->usb_ac_units[d->bTerminalID].acu_descr_length = len;
1585
1586 break;
1587 }
1588 case USB_AUDIO_MIXER_UNIT:
1589 {
1590 usb_audio_mixer_unit_descr1_t *d =
1591 (usb_audio_mixer_unit_descr1_t *)descr;
1592
1593 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1594 uacp->usb_ac_log_handle,
1595 "usb_ac_units[%d] ---mixer unit: type=0x%x sub=0x%x"
1596 " unitid=0x%x\n\t"
1597 "#pins=0x%x sourceid[0]=0x%x",
1598 d->bUnitID,
1599 d->bDescriptorType, d->bDescriptorSubType,
1600 d->bUnitID, d->bNrInPins, d->baSourceID[0]);
1601 usb_ac_alloc_unit(uacp, d->bUnitID);
1602 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1603 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1604 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1605
1606 break;
1607 }
1608 case USB_AUDIO_SELECTOR_UNIT:
1609 {
1610 usb_audio_selector_unit_descr1_t *d =
1611 (usb_audio_selector_unit_descr1_t *)descr;
1612
1613 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1614 uacp->usb_ac_log_handle,
1615 "usb_ac_units[%d] ---selector unit: type=0x%x sub=0x%x"
1616 " unitid=0x%x\n\t"
1617 "#pins=0x%x sourceid[0]=0x%x",
1618 d->bUnitID,
1619 d->bDescriptorType, d->bDescriptorSubType,
1620 d->bUnitID, d->bNrInPins, d->baSourceID[0]);
1621 usb_ac_alloc_unit(uacp, d->bUnitID);
1622 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1623 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1624 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1625
1626 break;
1627 }
1628 case USB_AUDIO_FEATURE_UNIT:
1629 {
1630 usb_audio_feature_unit_descr1_t *d =
1631 (usb_audio_feature_unit_descr1_t *)descr;
1632
1633 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1634 uacp->usb_ac_log_handle,
1635 "usb_ac_units[%d] ---feature unit: type=0x%x sub=0x%x"
1636 " unitid=0x%x\n\t"
1637 "sourceid=0x%x size=0x%x",
1638 d->bUnitID,
1639 d->bDescriptorType, d->bDescriptorSubType,
1640 d->bUnitID, d->bSourceID, d->bControlSize);
1641
1642 usb_ac_alloc_unit(uacp, d->bUnitID);
1643 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1644 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1645 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1646
1647 break;
1648 }
1649 case USB_AUDIO_PROCESSING_UNIT:
1650 {
1651 usb_audio_processing_unit_descr1_t *d =
1652 (usb_audio_processing_unit_descr1_t *)descr;
1653
1654 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1655 uacp->usb_ac_log_handle,
1656 "usb_ac_units[%d] ---processing unit: type=0x%x sub=0x%x"
1657 " unitid=0x%x\n\t"
1658 "#pins=0x%x sourceid[0]=0x%x",
1659 d->bUnitID,
1660 d->bDescriptorType, d->bDescriptorSubType,
1661 d->bUnitID, d->bNrInPins, d->baSourceID[0]);
1662 usb_ac_alloc_unit(uacp, d->bUnitID);
1663 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1664 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1665 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1666
1667 break;
1668 }
1669 case USB_AUDIO_EXTENSION_UNIT:
1670 {
1671 usb_audio_extension_unit_descr1_t *d =
1672 (usb_audio_extension_unit_descr1_t *)descr;
1673
1674 USB_DPRINTF_L3(PRINT_MASK_ATTA,
1675 uacp->usb_ac_log_handle,
1676 "usb_ac_units[%d] ---mixer unit: type=0x%x sub=0x%x"
1677 " unitid=0x%x\n\t"
1678 "#pins=0x%x sourceid[0]=0x%x",
1679 d->bUnitID,
1680 d->bDescriptorType, d->bDescriptorSubType,
1681 d->bUnitID, d->bNrInPins, d->baSourceID[0]);
1682 usb_ac_alloc_unit(uacp, d->bUnitID);
1683 uacp->usb_ac_units[d->bUnitID].acu_descriptor = descr;
1684 uacp->usb_ac_units[d->bUnitID].acu_type = buffer[2];
1685 uacp->usb_ac_units[d->bUnitID].acu_descr_length = len;
1686
1687 break;
1688 }
1689 default:
1690 break;
1691 }
1692 }
1693
1694
1695 /*
1696 * usb_ac_alloc_unit:
1697 * check if the unit ID is less than max_unit in which case no
1698 * extra entries are needed. If more entries are needed, copy over
1699 * the existing array into a new larger array
1700 */
1701 static void
usb_ac_alloc_unit(usb_ac_state_t * uacp,uint_t unit)1702 usb_ac_alloc_unit(usb_ac_state_t *uacp, uint_t unit)
1703 {
1704 usb_ac_unit_list_t *old = NULL;
1705 uint_t max_unit;
1706
1707
1708 if (uacp->usb_ac_units) {
1709 if (unit < uacp->usb_ac_max_unit) {
1710 /* existing array is big enough */
1711
1712 return;
1713 }
1714 old = uacp->usb_ac_units;
1715 max_unit = uacp->usb_ac_max_unit;
1716 }
1717
1718 /* allocate two extra ones */
1719 unit += 2;
1720 uacp->usb_ac_max_unit = unit;
1721 uacp->usb_ac_units = kmem_zalloc(unit *
1722 sizeof (usb_ac_unit_list_t), KM_SLEEP);
1723
1724 if (old) {
1725 size_t len = max_unit * sizeof (usb_ac_unit_list_t);
1726 bcopy(old, uacp->usb_ac_units, len);
1727
1728 kmem_free(old, len);
1729 }
1730 }
1731
1732
1733 /*
1734 * usb_ac_free_all_units:
1735 * free the entire unit list
1736 */
1737 static void
usb_ac_free_all_units(usb_ac_state_t * uacp)1738 usb_ac_free_all_units(usb_ac_state_t *uacp)
1739 {
1740 uint_t unit;
1741 usb_ac_unit_list_t *unitp;
1742
1743 if (uacp->usb_ac_units == NULL) {
1744
1745 return;
1746 }
1747
1748
1749 for (unit = 0; unit < uacp->usb_ac_max_unit; unit++) {
1750 unitp = &uacp->usb_ac_units[unit];
1751 if (unitp) {
1752 if (unitp->acu_descriptor) {
1753 kmem_free(unitp->acu_descriptor,
1754 unitp->acu_descr_length);
1755 }
1756 }
1757 }
1758
1759 kmem_free(uacp->usb_ac_units, uacp->usb_ac_max_unit *
1760 sizeof (usb_ac_unit_list_t));
1761 }
1762
1763
1764 /*
1765 * usb_ac_lookup_port_type:
1766 * map term type to port type
1767 * default just return LINE_IN + LINE_OUT
1768 */
1769 static int
usb_ac_lookup_port_type(ushort_t termtype)1770 usb_ac_lookup_port_type(ushort_t termtype)
1771 {
1772 uint_t i;
1773
1774 /*
1775 * Looking for a input/ouput terminal type to match the port
1776 * type, it should not be common streaming type
1777 */
1778 ASSERT(termtype != USB_AUDIO_TERM_TYPE_STREAMING);
1779
1780 for (i = 0; ; i++) {
1781 if (usb_ac_term_type_map[i].term_type == 0) {
1782
1783 break;
1784 }
1785
1786 if (usb_ac_term_type_map[i].term_type == termtype) {
1787
1788 return (usb_ac_term_type_map[i].port_type);
1789 }
1790 }
1791
1792 return (USB_PORT_UNKNOWN);
1793 }
1794
1795
1796 /*
1797 * usb_ac_update_port:
1798 * called for each terminal
1799 */
1800 /*ARGSUSED*/
1801 static int
usb_ac_update_port(usb_ac_state_t * uacp,uint_t id,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth)1802 usb_ac_update_port(usb_ac_state_t *uacp, uint_t id,
1803 uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
1804 {
1805 if (dir & USB_AUDIO_PLAY) {
1806 usb_audio_output_term_descr_t *d =
1807 (usb_audio_output_term_descr_t *)
1808 uacp->usb_ac_units[id].acu_descriptor;
1809 uint_t port_type =
1810 usb_ac_lookup_port_type(d->wTerminalType);
1811
1812 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1813 "usb_ac_update_port: dir=%d wTerminalType=0x%x, name=%s",
1814 dir, d->wTerminalType, usb_audio_dtypes[port_type]);
1815
1816 uacp->usb_ac_output_ports |= (1U << port_type);
1817 } else {
1818 usb_audio_input_term_descr_t *d =
1819 (usb_audio_input_term_descr_t *)
1820 uacp->usb_ac_units[id].acu_descriptor;
1821 uint_t port_type =
1822 usb_ac_lookup_port_type(d->wTerminalType);
1823
1824 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1825 "usb_ac_update_port: dir=%d wTerminalType=0x%x, name=%s",
1826 dir, d->wTerminalType, usb_audio_dtypes[port_type]);
1827
1828 uacp->usb_ac_input_ports |= (1U << port_type);
1829
1830 }
1831
1832 return (USB_SUCCESS);
1833 }
1834
1835
1836 /*
1837 * usb_ac_map_termtype_to_port:
1838 * starting from a streaming termtype find all
1839 * input or output terminals and OR into uacp->usb_ac_input_ports
1840 * or uacp->usb_ac_output_ports;
1841 */
1842 static void
usb_ac_map_termtype_to_port(usb_ac_state_t * uacp,uint_t dir)1843 usb_ac_map_termtype_to_port(usb_ac_state_t *uacp, uint_t dir)
1844 {
1845 uint_t count = 0;
1846 uint_t depth = 0;
1847 uint_t search_type = (dir & USB_AUDIO_PLAY) ?
1848 USB_AUDIO_OUTPUT_TERMINAL : USB_AUDIO_INPUT_TERMINAL;
1849
1850
1851 (void) usb_ac_traverse_all_units(uacp, dir, search_type, 0,
1852 0, USB_AC_FIND_ALL, &count, 0, &depth, usb_ac_update_port);
1853
1854 ASSERT(depth == 0);
1855 }
1856
1857
1858 /*
1859 * usb_ac_set_port:
1860 * find a selector port (record side only) and set the
1861 * input to the matching pin
1862 */
1863 static uint_t
usb_ac_set_port(usb_ac_state_t * uacp,uint_t dir,uint_t port)1864 usb_ac_set_port(usb_ac_state_t *uacp, uint_t dir, uint_t port)
1865 {
1866 uint_t count = 0;
1867 uint_t id;
1868 uint_t depth = 0;
1869
1870
1871 /* we only support the selector for the record side */
1872 if (dir & USB_AUDIO_RECORD) {
1873 id = usb_ac_traverse_all_units(uacp, dir,
1874 USB_AUDIO_SELECTOR_UNIT, 0,
1875 0, USB_AC_FIND_ONE, &count, port, &depth,
1876 usb_ac_set_selector);
1877
1878 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1879 "usb_ac_set_port: id=%d count=%d port=%d",
1880 id, count, port);
1881
1882 ASSERT(depth == 0);
1883 }
1884
1885 return (USB_SUCCESS);
1886 }
1887
1888
1889 /*
1890 * usb_ac_match_port:
1891 * given the requested port type, find a correspondig term type
1892 * Called from usb_ac_traverse_all_units()
1893 */
1894 /*ARGSUSED*/
1895 static int
usb_ac_match_port(usb_ac_state_t * uacp,uint_t id,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth)1896 usb_ac_match_port(usb_ac_state_t *uacp, uint_t id,
1897 uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
1898 {
1899 uint_t port_type;
1900
1901
1902 if (dir & USB_AUDIO_PLAY) {
1903 usb_audio_output_term_descr_t *d =
1904 (usb_audio_output_term_descr_t *)
1905 uacp->usb_ac_units[id].acu_descriptor;
1906 port_type = usb_ac_lookup_port_type(d->wTerminalType);
1907
1908 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1909 "usb_ac_match_port: "
1910 "dir=%d type=0x%x port_type=%d port=%d",
1911 dir, d->wTerminalType, port_type, arg1);
1912 } else {
1913 usb_audio_output_term_descr_t *d =
1914 (usb_audio_output_term_descr_t *)
1915 uacp->usb_ac_units[id].acu_descriptor;
1916 port_type = usb_ac_lookup_port_type(d->wTerminalType);
1917
1918 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1919 "usb_ac_match_port: "
1920 "dir=%d type=0x%x port_type=%d port=%d",
1921 dir, d->wTerminalType, port_type, arg1);
1922 }
1923
1924 return (((1U << port_type) & arg1) ? USB_SUCCESS : USB_FAILURE);
1925 }
1926
1927
1928 /*
1929 * usb_ac_set_selector:
1930 * Called from usb_ac_traverse_all_units()
1931 * Find the correct pin and set selector to this pin
1932 */
1933 /*ARGSUSED*/
1934 static int
usb_ac_set_selector(usb_ac_state_t * uacp,uint_t id,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth)1935 usb_ac_set_selector(usb_ac_state_t *uacp, uint_t id,
1936 uint_t dir, uint_t channel, uint_t control, uint_t arg1, uint_t *depth)
1937 {
1938 uint_t count = 0;
1939 uint_t unit = USB_AC_ID_NONE;
1940 uint_t pin;
1941 uint_t search_target =
1942 (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL :
1943 USB_AUDIO_INPUT_TERMINAL;
1944 usb_audio_selector_unit_descr1_t *d =
1945 (usb_audio_selector_unit_descr1_t *)
1946 uacp->usb_ac_units[id].acu_descriptor;
1947 int n_sourceID = d->bNrInPins;
1948 int rval = USB_FAILURE;
1949
1950
1951 /*
1952 * for each pin, find a term type that matches the
1953 * requested port type
1954 */
1955 for (pin = 0; pin < n_sourceID; pin++) {
1956 if (d->baSourceID[pin] == 0) {
1957
1958 break;
1959 }
1960 unit = d->baSourceID[pin];
1961
1962 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1963 "usb_ac_set_selector: pin=%d unit=%d", pin, unit);
1964
1965 if (uacp->usb_ac_unit_type[unit] == search_target) {
1966 if (usb_ac_match_port(uacp, unit, dir, channel,
1967 control, arg1, depth) == USB_SUCCESS) {
1968
1969 break;
1970 } else {
1971 unit = USB_AC_ID_NONE;
1972
1973 continue;
1974 }
1975 }
1976
1977 /* find units connected to this unit */
1978 unit = usb_ac_traverse_connections(uacp, unit,
1979 dir, search_target, channel, control,
1980 USB_AC_FIND_ONE, &count, arg1, depth,
1981 usb_ac_match_port);
1982
1983 if (unit != USB_AC_ID_NONE) {
1984
1985 break;
1986 }
1987 }
1988
1989
1990 if (unit != USB_AC_ID_NONE) {
1991 mblk_t *data;
1992 usb_cr_t cr;
1993 usb_cb_flags_t cb_flags;
1994
1995 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
1996 "usb_ac_set_selector: found id=%d at pin %d", unit, pin);
1997
1998 mutex_exit(&uacp->usb_ac_mutex);
1999
2000 data = allocb(1, BPRI_HI);
2001 if (!data) {
2002 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2003 "usb_ac_set_selector: allocate data failed");
2004 mutex_enter(&uacp->usb_ac_mutex);
2005
2006 return (USB_FAILURE);
2007 }
2008
2009 /* pins are 1-based */
2010 *(data->b_rptr) = (char)++pin;
2011
2012 if (usb_pipe_sync_ctrl_xfer(
2013 uacp->usb_ac_dip,
2014 uacp->usb_ac_default_ph,
2015 USB_DEV_REQ_HOST_TO_DEV |
2016 USB_DEV_REQ_TYPE_CLASS |
2017 USB_DEV_REQ_RCPT_IF, /* bmRequestType */
2018 USB_AUDIO_SET_CUR, /* bRequest */
2019 0, /* wValue */
2020 /* feature unit and id */
2021 (id << 8)| uacp->usb_ac_ifno, /* wIndex */
2022 1, /* wLength */
2023 &data,
2024 USB_ATTRS_NONE,
2025 &cr, &cb_flags,
2026 USB_FLAGS_SLEEP) == USB_SUCCESS) {
2027 USB_DPRINTF_L3(PRINT_MASK_ALL,
2028 uacp->usb_ac_log_handle,
2029 "set current selection: %d", *data->b_rptr);
2030
2031 rval = USB_SUCCESS;
2032 } else {
2033 USB_DPRINTF_L2(PRINT_MASK_ALL,
2034 uacp->usb_ac_log_handle,
2035 "set current pin selection failed");
2036 }
2037 freemsg(data);
2038
2039 mutex_enter(&uacp->usb_ac_mutex);
2040 } else {
2041 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2042 "usb_ac_set_selector: nothing found");
2043 }
2044
2045 return (rval);
2046 }
2047
2048
2049 /*
2050 * usb_ac_set_control:
2051 * apply func to all units of search_target type for both the
2052 * requested channel and master channel
2053 */
2054 static uint_t
usb_ac_set_control(usb_ac_state_t * uacp,uint_t dir,uint_t search_target,uint_t channel,uint_t control,uint_t all_or_one,uint_t * count,uint_t arg1,int (* func)(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth))2055 usb_ac_set_control(usb_ac_state_t *uacp, uint_t dir, uint_t search_target,
2056 uint_t channel, uint_t control, uint_t all_or_one,
2057 uint_t *count, uint_t arg1,
2058 int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2059 uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
2060 {
2061 uint_t id;
2062 uint_t depth = 0;
2063
2064 id = usb_ac_traverse_all_units(uacp, dir, search_target, channel,
2065 control, all_or_one, count, arg1, &depth, func);
2066
2067 if ((channel != 0) &&
2068 (((id == USB_AC_ID_NONE) && (all_or_one == USB_AC_FIND_ONE)) ||
2069 (all_or_one == USB_AC_FIND_ALL))) {
2070 /* try master channel */
2071 channel = 0;
2072 id = usb_ac_traverse_all_units(uacp, dir, search_target,
2073 channel, control, all_or_one, count, arg1,
2074 &depth, func);
2075 }
2076
2077 ASSERT(depth == 0);
2078
2079 return (id);
2080 }
2081
2082
2083 /*
2084 * usb_ac_traverse_all_units:
2085 * traverse all units starting with all IT or OT depending on direction.
2086 * If no unit is found for the particular channel, try master channel
2087 * If a matching unit is found, apply the function passed by
2088 * the caller
2089 */
2090 static uint_t
usb_ac_traverse_all_units(usb_ac_state_t * uacp,uint_t dir,uint_t search_target,uint_t channel,uint_t control,uint_t all_or_one,uint_t * count,uint_t arg1,uint_t * depth,int (* func)(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth))2091 usb_ac_traverse_all_units(usb_ac_state_t *uacp, uint_t dir,
2092 uint_t search_target, uint_t channel, uint_t control,
2093 uint_t all_or_one, uint_t *count, uint_t arg1, uint_t *depth,
2094 int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2095 uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
2096 {
2097 uint_t unit, start_type, id;
2098
2099 start_type = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_INPUT_TERMINAL :
2100 USB_AUDIO_OUTPUT_TERMINAL;
2101
2102 /* keep track of recursion */
2103 if ((*depth)++ > USB_AC_MAX_DEPTH) {
2104 USB_DPRINTF_L1(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2105 "Unit topology too complex, giving up");
2106
2107 return (USB_AC_ID_NONE);
2108 }
2109
2110 for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
2111 /* is this an IT or OT? */
2112 if (uacp->usb_ac_unit_type[unit] != start_type) {
2113
2114 continue;
2115 }
2116
2117 /* start at streaming term types */
2118 if (dir & USB_AUDIO_PLAY) {
2119 usb_audio_input_term_descr_t *d =
2120 uacp->usb_ac_units[unit].acu_descriptor;
2121 if (d->wTerminalType !=
2122 USB_AUDIO_TERM_TYPE_STREAMING) {
2123
2124 continue;
2125 }
2126 } else {
2127 usb_audio_output_term_descr_t *d =
2128 uacp->usb_ac_units[unit].acu_descriptor;
2129 if (d->wTerminalType !=
2130 USB_AUDIO_TERM_TYPE_STREAMING) {
2131
2132 continue;
2133 }
2134 }
2135
2136 /* find units connected to this unit */
2137 id = usb_ac_traverse_connections(uacp, unit, dir,
2138 search_target, channel, control, all_or_one, count,
2139 arg1, depth, func);
2140
2141 if ((all_or_one == USB_AC_FIND_ONE) &&
2142 (id != USB_AC_ID_NONE)) {
2143 unit = id;
2144
2145 break;
2146 }
2147 }
2148
2149 (*depth)--;
2150
2151 return ((unit < uacp->usb_ac_max_unit) ? unit : USB_AC_ID_NONE);
2152 }
2153
2154
2155 /*
2156 * usb_ac_set_monitor_gain_control:
2157 * search for a feature unit between output terminal (OT) and
2158 * input terminal. We are looking for a path between
2159 * for example a microphone and a speaker through a feature unit
2160 * and mixer
2161 */
2162 static uint_t
usb_ac_set_monitor_gain_control(usb_ac_state_t * uacp,uint_t dir,uint_t search_target,uint_t channel,uint_t control,uint_t all_or_one,uint_t * count,uint_t arg1,int (* func)(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth))2163 usb_ac_set_monitor_gain_control(usb_ac_state_t *uacp, uint_t dir,
2164 uint_t search_target, uint_t channel, uint_t control,
2165 uint_t all_or_one, uint_t *count, uint_t arg1,
2166 int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2167 uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
2168 {
2169 uint_t unit, id;
2170 uint_t depth = 0;
2171
2172
2173 for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
2174 usb_audio_output_term_descr_t *d =
2175 uacp->usb_ac_units[unit].acu_descriptor;
2176
2177 /* is this an OT and not stream type? */
2178 if ((uacp->usb_ac_unit_type[unit] ==
2179 USB_AUDIO_OUTPUT_TERMINAL) &&
2180 (d->wTerminalType != USB_AUDIO_TERM_TYPE_STREAMING)) {
2181
2182 /* find units connected to this unit */
2183 id = usb_ac_traverse_connections(uacp, unit, dir,
2184 search_target, channel, control, all_or_one, count,
2185 arg1, &depth, func);
2186
2187 if ((all_or_one == USB_AC_FIND_ONE) &&
2188 (id != USB_AC_ID_NONE)) {
2189
2190 break;
2191 }
2192 }
2193 }
2194
2195 ASSERT(depth == 0);
2196
2197 return (id);
2198 }
2199
2200
2201 /*
2202 * usb_ac_push/pop_unit
2203 * add/remove unit ID to the traverse path
2204 */
2205 static void
usb_ac_push_unit_id(usb_ac_state_t * uacp,uint_t unit)2206 usb_ac_push_unit_id(usb_ac_state_t *uacp, uint_t unit)
2207 {
2208 uacp->usb_ac_traverse_path[uacp->usb_ac_traverse_path_index++] =
2209 (uchar_t)unit;
2210 ASSERT(uacp->usb_ac_traverse_path_index < uacp->usb_ac_max_unit);
2211 }
2212
2213
2214 /* ARGSUSED */
2215 static void
usb_ac_pop_unit_id(usb_ac_state_t * uacp,uint_t unit)2216 usb_ac_pop_unit_id(usb_ac_state_t *uacp, uint_t unit)
2217 {
2218 uacp->usb_ac_traverse_path[uacp->usb_ac_traverse_path_index--] = 0;
2219 }
2220
2221
2222 /*
2223 * usb_ac_show_traverse_path:
2224 * display entire path, just for debugging
2225 */
2226 static void
usb_ac_show_traverse_path(usb_ac_state_t * uacp)2227 usb_ac_show_traverse_path(usb_ac_state_t *uacp)
2228 {
2229 int i;
2230
2231 for (i = 0; i < uacp->usb_ac_traverse_path_index; i++) {
2232 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2233 "traverse path %d: unit=%d type=%d",
2234 i, uacp->usb_ac_traverse_path[i],
2235 uacp->usb_ac_unit_type[uacp->usb_ac_traverse_path[i]]);
2236 }
2237 }
2238
2239
2240 /*
2241 * usb_ac_check_path:
2242 * check for a specified type in the traverse path
2243 */
2244 static int
usb_ac_check_path(usb_ac_state_t * uacp,uint_t type)2245 usb_ac_check_path(usb_ac_state_t *uacp, uint_t type)
2246 {
2247 int i;
2248
2249 for (i = 0; i < uacp->usb_ac_traverse_path_index; i++) {
2250 uint_t unit = uacp->usb_ac_traverse_path[i];
2251
2252 if (uacp->usb_ac_unit_type[unit] == type) {
2253
2254 return (USB_SUCCESS);
2255 }
2256 }
2257
2258 return (USB_FAILURE);
2259 }
2260
2261
2262 /*
2263 * usb_ac_traverse_connections:
2264 * traverse all units and for each unit with the right type, call
2265 * func. If the func returns a success and search == USB_AC_FIND_ONE,
2266 * we are done. If all is set then we continue until we terminate
2267 * and input or output terminal.
2268 * For audio play, we traverse columns starting from an input terminal
2269 * to an output terminal while for record we traverse rows from output
2270 * terminal to input terminal.
2271 */
2272 static uint_t
usb_ac_traverse_connections(usb_ac_state_t * uacp,uint_t start_unit,uint_t dir,uint_t search_target,uint_t channel,uint_t control,uint_t all_or_one,uint_t * count,uint_t arg1,uint_t * depth,int (* func)(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t arg1,uint_t * depth))2273 usb_ac_traverse_connections(usb_ac_state_t *uacp, uint_t start_unit, uint_t dir,
2274 uint_t search_target, uint_t channel, uint_t control,
2275 uint_t all_or_one, uint_t *count, uint_t arg1, uint_t *depth,
2276 int (*func)(usb_ac_state_t *uacp, uint_t unit, uint_t dir,
2277 uint_t channel, uint_t control, uint_t arg1, uint_t *depth))
2278 {
2279 uint_t unit, id;
2280 uint_t done = (dir & USB_AUDIO_PLAY) ? USB_AUDIO_OUTPUT_TERMINAL :
2281 USB_AUDIO_INPUT_TERMINAL;
2282
2283
2284 /* keep track of recursion depth */
2285 if ((*depth)++ > USB_AC_MAX_DEPTH) {
2286 USB_DPRINTF_L1(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2287 "Unit topology too complex, giving up");
2288
2289 return (USB_AC_ID_NONE);
2290 }
2291
2292 usb_ac_push_unit_id(uacp, start_unit);
2293
2294 for (unit = 1; unit < uacp->usb_ac_max_unit; unit++) {
2295 uint_t entry = (dir & USB_AUDIO_PLAY) ?
2296 uacp->usb_ac_connections[unit][start_unit] :
2297 uacp->usb_ac_connections[start_unit][unit];
2298
2299 if (entry) {
2300 USB_DPRINTF_L3(PRINT_MASK_ALL,
2301 uacp->usb_ac_log_handle,
2302 "start=%d unit=%d entry=%d type=%d "
2303 "done=%d found=%d",
2304 start_unit, unit, entry, search_target, done,
2305 uacp->usb_ac_unit_type[unit]);
2306
2307 /* did we find a matching type? */
2308 if (uacp->usb_ac_unit_type[unit] == search_target) {
2309 USB_DPRINTF_L3(PRINT_MASK_ALL,
2310 uacp->usb_ac_log_handle,
2311 "match: dir=%d unit=%d type=%d",
2312 dir, unit, search_target);
2313
2314 /* yes, no apply function to this unit */
2315 if (func(uacp, unit, dir, channel,
2316 control, arg1, depth) == USB_SUCCESS) {
2317 (*count)++;
2318
2319 USB_DPRINTF_L3(PRINT_MASK_ALL,
2320 uacp->usb_ac_log_handle,
2321 "func returned success, "
2322 "unit=%d all=%d", unit,
2323 all_or_one);
2324
2325 /* are we done? */
2326 if (all_or_one == USB_AC_FIND_ONE) {
2327
2328 break;
2329 }
2330 }
2331 }
2332
2333 /* did we find the terminating unit */
2334 if (uacp->usb_ac_unit_type[unit] == done) {
2335
2336 continue;
2337 }
2338 id = usb_ac_traverse_connections(uacp, unit, dir,
2339 search_target, channel, control,
2340 all_or_one, count, arg1, depth, func);
2341 if ((id != USB_AC_ID_NONE) &&
2342 (all_or_one == USB_AC_FIND_ONE)) {
2343 unit = id;
2344
2345 break;
2346 }
2347 }
2348 }
2349
2350 (*depth)--;
2351 usb_ac_pop_unit_id(uacp, start_unit);
2352
2353 return ((unit < uacp->usb_ac_max_unit) ? unit : USB_AC_ID_NONE);
2354 }
2355
2356
2357 /*
2358 * Event Management
2359 *
2360 * usb_ac_disconnect_event_cb:
2361 * The device has been disconnected. we either wait for
2362 * detach or a reconnect event.
2363 */
2364 static int
usb_ac_disconnect_event_cb(dev_info_t * dip)2365 usb_ac_disconnect_event_cb(dev_info_t *dip)
2366 {
2367 usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
2368 usb_ac_statep, ddi_get_instance(dip));
2369
2370 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2371 "usb_ac_disconnect_event_cb:start");
2372
2373 usb_ac_serialize_access(uacp);
2374 mutex_enter(&uacp->usb_ac_mutex);
2375
2376 /* setting to disconnect state will prevent replumbing */
2377 uacp->usb_ac_dev_state = USB_DEV_DISCONNECTED;
2378
2379 if (uacp->usb_ac_busy_count) {
2380 USB_DPRINTF_L0(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2381 "device was disconnected while busy. "
2382 "Data may have been lost");
2383 }
2384 mutex_exit(&uacp->usb_ac_mutex);
2385
2386 usb_ac_release_access(uacp);
2387 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2388 "usb_ac_disconnect_event_cb:done");
2389
2390
2391 return (USB_SUCCESS);
2392 }
2393
2394
2395 /*
2396 * usb_ac_cpr_suspend:
2397 */
2398 static int
usb_ac_cpr_suspend(dev_info_t * dip)2399 usb_ac_cpr_suspend(dev_info_t *dip)
2400 {
2401 usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
2402 usb_ac_statep, ddi_get_instance(dip));
2403
2404 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2405 "usb_ac_cpr_suspend: Begin");
2406
2407 mutex_enter(&uacp->usb_ac_mutex);
2408 uacp->usb_ac_dev_state = USB_DEV_SUSPENDED;
2409 mutex_exit(&uacp->usb_ac_mutex);
2410
2411 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2412 "usb_ac_cpr_suspend: End");
2413
2414 return (USB_SUCCESS);
2415 }
2416
2417
2418
2419 /*
2420 * usb_ac_reconnect_event_cb:
2421 * The device was disconnected but this instance not detached, probably
2422 * because the device was busy.
2423 * if the same device, continue with restoring state
2424 * We should either be in the unplumbed state or the plumbed open
2425 * state.
2426 */
2427 static int
usb_ac_reconnect_event_cb(dev_info_t * dip)2428 usb_ac_reconnect_event_cb(dev_info_t *dip)
2429 {
2430 usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
2431 usb_ac_statep, ddi_get_instance(dip));
2432
2433 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2434 "usb_ac_reconnect_event_cb:begain");
2435
2436 mutex_enter(&uacp->usb_ac_mutex);
2437 mutex_exit(&uacp->usb_ac_mutex);
2438
2439 usb_ac_serialize_access(uacp);
2440
2441 /* check the plumbing state */
2442 mutex_enter(&uacp->usb_ac_mutex);
2443 uacp->usb_ac_busy_count++;
2444 if (uacp->usb_ac_plumbing_state ==
2445 USB_AC_STATE_PLUMBED) {
2446 mutex_exit(&uacp->usb_ac_mutex);
2447 usb_ac_restore_device_state(dip, uacp);
2448 mutex_enter(&uacp->usb_ac_mutex);
2449 }
2450 uacp->usb_ac_busy_count--;
2451
2452 if (uacp->usb_ac_busy_count) {
2453 USB_DPRINTF_L0(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2454 "busy device has been reconnected");
2455 }
2456
2457 mutex_exit(&uacp->usb_ac_mutex);
2458
2459 usb_ac_release_access(uacp);
2460 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2461 "usb_ac_reconnect_event_cb:done");
2462
2463 return (USB_SUCCESS);
2464 }
2465
2466
2467 /*
2468 * usb_ac_cpr_resume:
2469 * Restore device state
2470 */
2471 static void
usb_ac_cpr_resume(dev_info_t * dip)2472 usb_ac_cpr_resume(dev_info_t *dip)
2473 {
2474 usb_ac_state_t *uacp = (usb_ac_state_t *)ddi_get_soft_state(
2475 usb_ac_statep, ddi_get_instance(dip));
2476
2477 USB_DPRINTF_L4(PRINT_MASK_EVENTS, uacp->usb_ac_log_handle,
2478 "usb_ac_cpr_resume");
2479
2480 usb_ac_serialize_access(uacp);
2481
2482 usb_ac_restore_device_state(dip, uacp);
2483
2484 usb_ac_release_access(uacp);
2485 }
2486
2487
2488 /*
2489 * usb_ac_restore_device_state:
2490 * Set original configuration of the device
2491 * enable wrq - this starts new transactions on the control pipe
2492 */
2493 static void
usb_ac_restore_device_state(dev_info_t * dip,usb_ac_state_t * uacp)2494 usb_ac_restore_device_state(dev_info_t *dip, usb_ac_state_t *uacp)
2495 {
2496 usb_ac_power_t *uacpm;
2497 int rval;
2498
2499 USB_DPRINTF_L4(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
2500 "usb_ac_restore_device_state:");
2501
2502 usb_ac_pm_busy_component(uacp);
2503 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2504
2505 /* Check if we are talking to the same device */
2506 if (usb_check_same_device(dip, uacp->usb_ac_log_handle,
2507 USB_LOG_L0, PRINT_MASK_ALL,
2508 USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
2509 usb_ac_pm_idle_component(uacp);
2510
2511 /* change the device state from suspended to disconnected */
2512 mutex_enter(&uacp->usb_ac_mutex);
2513 uacp->usb_ac_dev_state = USB_DEV_DISCONNECTED;
2514 mutex_exit(&uacp->usb_ac_mutex);
2515
2516 return;
2517 }
2518
2519 mutex_enter(&uacp->usb_ac_mutex);
2520 uacpm = uacp->usb_ac_pm;
2521 if (uacpm) {
2522 if (uacpm->acpm_wakeup_enabled) {
2523 mutex_exit(&uacp->usb_ac_mutex);
2524
2525 if ((rval = usb_handle_remote_wakeup(uacp->usb_ac_dip,
2526 USB_REMOTE_WAKEUP_ENABLE)) != USB_SUCCESS) {
2527
2528 USB_DPRINTF_L4(PRINT_MASK_ATTA,
2529 uacp->usb_ac_log_handle,
2530 "usb_ac_restore_device_state: "
2531 "remote wakeup "
2532 "enable failed, rval=%d", rval);
2533 }
2534
2535 mutex_enter(&uacp->usb_ac_mutex);
2536 }
2537 }
2538
2539 /* prevent unplumbing */
2540 uacp->usb_ac_busy_count++;
2541 uacp->usb_ac_dev_state = USB_DEV_ONLINE;
2542 if (uacp->usb_ac_plumbing_state == USB_AC_STATE_PLUMBED) {
2543 (void) usb_ac_restore_audio_state(uacp, 0);
2544 }
2545 uacp->usb_ac_busy_count--;
2546 mutex_exit(&uacp->usb_ac_mutex);
2547 usb_ac_pm_idle_component(uacp);
2548 }
2549
2550
2551 /*
2552 * usb_ac_am_restore_state
2553 */
2554 static void
usb_ac_am_restore_state(void * arg)2555 usb_ac_am_restore_state(void *arg)
2556 {
2557 usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
2558
2559 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2560 "usb_ac_am_restore_state: Begin");
2561
2562 usb_ac_serialize_access(uacp);
2563
2564 mutex_enter(&uacp->usb_ac_mutex);
2565
2566 if (uacp->usb_ac_plumbing_state ==
2567 USB_AC_STATE_PLUMBED_RESTORING) {
2568 mutex_exit(&uacp->usb_ac_mutex);
2569
2570 /*
2571 * allow hid and usb_as to restore themselves
2572 * (some handshake would have been preferable though)
2573 */
2574 delay(USB_AC_RESTORE_DELAY);
2575
2576 usb_restore_engine(uacp);
2577
2578 mutex_enter(&uacp->usb_ac_mutex);
2579 uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
2580 }
2581
2582 /* allow unplumbing */
2583 uacp->usb_ac_busy_count--;
2584 mutex_exit(&uacp->usb_ac_mutex);
2585
2586 usb_ac_release_access(uacp);
2587
2588 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2589 "usb_ac_am_restore_state: End");
2590 }
2591
2592
2593 /*
2594 * usb_ac_restore_audio_state:
2595 */
2596 static int
usb_ac_restore_audio_state(usb_ac_state_t * uacp,int flag)2597 usb_ac_restore_audio_state(usb_ac_state_t *uacp, int flag)
2598 {
2599 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
2600
2601
2602 switch (uacp->usb_ac_plumbing_state) {
2603 case USB_AC_STATE_PLUMBED:
2604 uacp->usb_ac_plumbing_state =
2605 USB_AC_STATE_PLUMBED_RESTORING;
2606
2607 break;
2608 case USB_AC_STATE_UNPLUMBED:
2609
2610 return (USB_SUCCESS);
2611 case USB_AC_STATE_PLUMBED_RESTORING:
2612 default:
2613
2614 return (USB_FAILURE);
2615 }
2616
2617 /*
2618 * increment busy_count again, it will be decremented
2619 * in usb_ac_am_restore_state
2620 */
2621 uacp->usb_ac_busy_count++;
2622
2623 if (flag & USB_FLAGS_SLEEP) {
2624 mutex_exit(&uacp->usb_ac_mutex);
2625 usb_ac_am_restore_state((void *)uacp);
2626 mutex_enter(&uacp->usb_ac_mutex);
2627 } else {
2628 mutex_exit(&uacp->usb_ac_mutex);
2629 if (usb_async_req(uacp->usb_ac_dip,
2630 usb_ac_am_restore_state,
2631 (void *)uacp, USB_FLAGS_SLEEP) != USB_SUCCESS) {
2632
2633 mutex_enter(&uacp->usb_ac_mutex);
2634 uacp->usb_ac_busy_count--;
2635
2636 return (USB_FAILURE);
2637 }
2638 mutex_enter(&uacp->usb_ac_mutex);
2639 }
2640
2641 return (USB_SUCCESS);
2642 }
2643
2644
2645 /*
2646 * Mixer Callback Management
2647 * NOTE: all mixer callbacks are serialized. we cannot be closed while
2648 * we are in the middle of a callback. There needs to be a
2649 * teardown first. We cannot be unplumbed as long as we are
2650 * still open.
2651 *
2652 * usb_ac_setup:
2653 * Send setup to usb_as if the first setup
2654 * Check power is done in usb_ac_send_as_cmd()
2655 */
2656 static int
usb_ac_setup(usb_ac_state_t * uacp,usb_audio_eng_t * engine)2657 usb_ac_setup(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
2658 {
2659 int rval = USB_SUCCESS;
2660
2661
2662 mutex_enter(&uacp->usb_ac_mutex);
2663
2664 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
2665 mutex_exit(&uacp->usb_ac_mutex);
2666
2667 return (USB_FAILURE);
2668 }
2669 mutex_exit(&uacp->usb_ac_mutex);
2670
2671 usb_ac_serialize_access(uacp);
2672
2673
2674 rval = usb_ac_do_setup(uacp, engine);
2675
2676 usb_ac_release_access(uacp);
2677
2678 return (rval);
2679 }
2680
2681
2682 /*
2683 * usb_ac_do_setup:
2684 * Wrapper function for usb_ac_setup which can be called
2685 * either from audio framework for usb_ac_set_format
2686 */
2687 static int
usb_ac_do_setup(usb_ac_state_t * uacp,usb_audio_eng_t * engine)2688 usb_ac_do_setup(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
2689 {
2690 usb_ac_streams_info_t *streams_infop = NULL;
2691
2692
2693 mutex_enter(&uacp->usb_ac_mutex);
2694
2695
2696 streams_infop = (usb_ac_streams_info_t *)engine->streams;
2697
2698 /*
2699 * Handle multiple setup calls. Pass the setup call to usb_as only
2700 * the first time so isoc pipe will be opened only once
2701 */
2702 if (streams_infop->acs_setup_teardown_count++) {
2703 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2704 "usb_ac_do_setup: more than one setup, cnt=%d",
2705 streams_infop->acs_setup_teardown_count);
2706
2707 mutex_exit(&uacp->usb_ac_mutex);
2708
2709 return (USB_SUCCESS);
2710 }
2711
2712 /* Send setup command to usb_as */
2713 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_SETUP, 0) !=
2714 USB_SUCCESS) {
2715 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2716 "usb_ac_do_setup: failure");
2717
2718 streams_infop->acs_setup_teardown_count--;
2719
2720 mutex_exit(&uacp->usb_ac_mutex);
2721
2722 return (USB_FAILURE);
2723 }
2724
2725 mutex_exit(&uacp->usb_ac_mutex);
2726
2727 return (USB_SUCCESS);
2728 }
2729
2730
2731 /*
2732 * usb_ac_teardown:
2733 * Send teardown to usb_as if the last teardown
2734 * Check power is done in usb_ac_send_as_cmd()
2735 * NOTE: allow teardown when disconnected
2736 */
2737 static void
usb_ac_teardown(usb_ac_state_t * uacp,usb_audio_eng_t * engine)2738 usb_ac_teardown(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
2739 {
2740
2741 usb_ac_streams_info_t *streams_infop = NULL;
2742
2743 usb_ac_serialize_access(uacp);
2744
2745
2746 streams_infop = engine->streams;
2747
2748
2749 mutex_enter(&uacp->usb_ac_mutex);
2750
2751
2752
2753 /* There should be at least one matching setup call */
2754 ASSERT(streams_infop->acs_setup_teardown_count);
2755
2756 /*
2757 * Handle multiple setup/teardown calls. Pass the call to usb_as
2758 * only this is the last teardown so that isoc pipe is closed
2759 * only once
2760 */
2761 if (--(streams_infop->acs_setup_teardown_count)) {
2762 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2763 "usb_ac_teardown: more than one setup/teardown, "
2764 "cnt=%d",
2765 streams_infop->acs_setup_teardown_count);
2766
2767 goto done;
2768 }
2769
2770 /* Send teardown command to usb_as */
2771 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_TEARDOWN,
2772 (void *)NULL) != USB_SUCCESS) {
2773
2774 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2775 "usb_ac_teardown: failure");
2776
2777 streams_infop->acs_setup_teardown_count++;
2778
2779
2780 goto done;
2781 }
2782 done:
2783
2784 mutex_exit(&uacp->usb_ac_mutex);
2785
2786 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2787 "usb_ac_teardown: End");
2788 usb_ac_release_access(uacp);
2789 }
2790
2791
2792 /*
2793 * usb_ac_set_monitor_gain:
2794 * called for each output terminal which supports
2795 * from usb_ac_traverse_connections
2796 */
2797 static int
usb_ac_set_monitor_gain(usb_ac_state_t * uacp,uint_t unit,uint_t dir,uint_t channel,uint_t control,uint_t gain,uint_t * depth)2798 usb_ac_set_monitor_gain(usb_ac_state_t *uacp, uint_t unit,
2799 uint_t dir, uint_t channel, uint_t control, uint_t gain, uint_t *depth)
2800 {
2801 usb_audio_output_term_descr_t *d =
2802 uacp->usb_ac_units[unit].acu_descriptor;
2803
2804 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2805 "usb_ac_set_monitor_gain: ");
2806
2807 /* log how we got here */
2808 usb_ac_push_unit_id(uacp, unit);
2809 usb_ac_show_traverse_path(uacp);
2810 usb_ac_pop_unit_id(uacp, unit);
2811
2812 /* we only care about the ITs connected to real hw inputs */
2813 switch (d->wTerminalType) {
2814 case USB_AUDIO_TERM_TYPE_STREAMING:
2815
2816 return (USB_FAILURE);
2817
2818 case USB_AUDIO_TERM_TYPE_DT_MICROPHONE:
2819 case USB_AUDIO_TERM_TYPE_PERS_MICROPHONE:
2820 case USB_AUDIO_TERM_TYPE_OMNI_DIR_MICROPHONE:
2821 case USB_AUDIO_TERM_TYPE_MICROPHONE_ARRAY:
2822 case USB_AUDIO_TERM_TYPE_PROCESSING_MIC_ARRAY:
2823 default:
2824
2825 break;
2826 }
2827
2828 /*
2829 * we can only do this if the microphone is mixed into the
2830 * audio output so look for a mixer first
2831 */
2832 if (usb_ac_check_path(uacp, USB_AUDIO_MIXER_UNIT) ==
2833 USB_SUCCESS) {
2834 int i, id;
2835
2836 /* now look for a feature unit */
2837 for (i = uacp->usb_ac_traverse_path_index - 1; i >= 0;
2838 i--) {
2839 id = uacp->usb_ac_traverse_path[i];
2840
2841 switch (uacp->usb_ac_unit_type[id]) {
2842 case USB_AUDIO_MIXER_UNIT:
2843
2844 /* the FU should be before the mixer */
2845 return (USB_FAILURE);
2846
2847 case USB_AUDIO_FEATURE_UNIT:
2848 /*
2849 * now set the volume
2850 */
2851 if (usb_ac_set_gain(uacp, id, dir, channel,
2852 control, gain, depth) != USB_SUCCESS) {
2853
2854 /* try master channel */
2855 if (usb_ac_set_gain(uacp, id, dir,
2856 0, control, gain, depth) !=
2857 USB_SUCCESS) {
2858
2859 return (USB_FAILURE);
2860 }
2861 }
2862
2863 return (USB_SUCCESS);
2864
2865 default:
2866 continue;
2867 }
2868 }
2869 }
2870
2871 return (USB_FAILURE);
2872 }
2873
2874
2875 /*
2876 * usb_ac_set_gain is called for each feature unit which supports
2877 * the requested controls from usb_ac_traverse_connections
2878 * we still need to check whether this unit supports the requested
2879 * control.
2880 */
2881 static int
usb_ac_set_gain(usb_ac_state_t * uacp,uint_t featureID,uint_t dir,uint_t channel,uint_t control,uint_t gain,uint_t * depth)2882 usb_ac_set_gain(usb_ac_state_t *uacp, uint_t featureID,
2883 uint_t dir, uint_t channel, uint_t control, uint_t gain, uint_t *depth)
2884 {
2885 short max, min, current;
2886
2887 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2888 "usb_ac_set_gain: id=%d dir=%d ch=%d cntl=%d gain=%d",
2889 featureID, dir, channel, control, gain);
2890
2891 if (usb_ac_feature_unit_check(uacp, featureID,
2892 dir, channel, control, gain, depth) != USB_SUCCESS) {
2893
2894 return (USB_FAILURE);
2895 }
2896
2897 if (usb_ac_get_maxmin_volume(uacp, channel,
2898 USB_AUDIO_GET_MAX, dir, featureID, &max) != USB_SUCCESS) {
2899 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2900 "usb_ac_set_gain: getting max gain failed");
2901
2902 return (USB_FAILURE);
2903 }
2904
2905 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2906 "usb_ac_set_gain: channel %d, max=%d", channel, max);
2907
2908 if (usb_ac_get_maxmin_volume(uacp, channel,
2909 USB_AUDIO_GET_MIN, dir, featureID, &min) != USB_SUCCESS) {
2910 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2911 "usb_ac_set_gain: getting min gain failed");
2912
2913 return (USB_FAILURE);
2914 }
2915
2916 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2917 "usb_ac_set_gain: channel=%d, min=%d", channel, min);
2918
2919 if (usb_ac_get_maxmin_volume(uacp, channel,
2920 USB_AUDIO_GET_CUR, dir, featureID, ¤t) != USB_SUCCESS) {
2921 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2922 "usb_ac_set_gain: getting cur gain failed");
2923
2924 return (USB_FAILURE);
2925 }
2926
2927 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2928 "usb_ac_set_gain: channel=%d, cur=%d", channel, current);
2929
2930 /*
2931 * Set the gain for a channel. The audio mixer calculates the
2932 * impact, if any, on the channel's gain.
2933 *
2934 * 0 <= gain <= AUDIO_MAX_GAIN
2935 *
2936 * channel #, 0 == left, 1 == right
2937 */
2938
2939 if (gain == 0) {
2940 gain = USB_AUDIO_VOLUME_SILENCE;
2941 } else {
2942 gain = max - ((max - min) * (AF_MAX_GAIN - gain))/AF_MAX_GAIN;
2943 }
2944
2945 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2946 "usb_ac_set_gain: ch=%d dir=%d max=%d min=%d gain=%d",
2947 channel, dir, max, min, gain);
2948
2949 if (usb_ac_set_volume(uacp, channel, gain, dir,
2950 featureID) != USB_SUCCESS) {
2951 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2952 "usb_ac_set_gain: setting volume failed");
2953
2954 return (USB_FAILURE);
2955 }
2956
2957 /* just curious, read it back, device may round up/down */
2958 if (usb_ac_get_maxmin_volume(uacp, channel,
2959 USB_AUDIO_GET_CUR, dir, featureID, ¤t) != USB_SUCCESS) {
2960 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2961 "usb_ac_set_gain: getting cur gain failed");
2962 }
2963
2964 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
2965 "usb_ac_set_gain done: "
2966 "id=%d channel=%d, cur=%d gain=%d", featureID, channel,
2967 (ushort_t)current, (ushort_t)gain);
2968
2969 return (USB_SUCCESS);
2970 }
2971
2972
2973 /*
2974 * usb_ac_set_format
2975 * This mixer callback initiates a command to be sent to
2976 * usb_as to select an alternate with the passed characteristics
2977 * and also to set the sample frequency.
2978 * Note that this may be called when a playing is going on in
2979 * the streaming interface. To handle that, first stop
2980 * playing/recording, close the pipe by sending a teardown
2981 * command, send the set_format command down and then reopen
2982 * the pipe. Note : (1) audio framework will restart play/record
2983 * after a set_format command. (2) Check power is done in
2984 * usb_ac_send_as_cmd().
2985 */
2986 int
usb_ac_set_format(usb_ac_state_t * uacp,usb_audio_eng_t * engine)2987 usb_ac_set_format(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
2988 {
2989 usb_ac_streams_info_t *streams_infop = NULL;
2990 usb_audio_formats_t format;
2991 int old_setup_teardown_count = 0;
2992
2993 mutex_enter(&uacp->usb_ac_mutex);
2994 streams_infop = (usb_ac_streams_info_t *)engine->streams;
2995
2996 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
2997 mutex_exit(&uacp->usb_ac_mutex);
2998
2999 return (USB_FAILURE);
3000 }
3001 mutex_exit(&uacp->usb_ac_mutex);
3002
3003 usb_ac_serialize_access(uacp);
3004 mutex_enter(&uacp->usb_ac_mutex);
3005
3006 bzero(&format, sizeof (usb_audio_formats_t));
3007
3008 /* save format info */
3009 format.fmt_n_srs = 1;
3010 format.fmt_srs = (uint_t *)&(engine->fmt.sr);
3011 format.fmt_chns = (uchar_t)engine->fmt.ch;
3012 format.fmt_precision = (uchar_t)engine->fmt.prec;
3013 format.fmt_encoding = (uchar_t)engine->fmt.enc;
3014
3015 old_setup_teardown_count = streams_infop->acs_setup_teardown_count;
3016
3017 /* isoc pipe not open and playing is not in progress */
3018 if (old_setup_teardown_count) {
3019 streams_infop->acs_setup_teardown_count = 1;
3020
3021 mutex_exit(&uacp->usb_ac_mutex);
3022 usb_ac_release_access(uacp);
3023
3024 usb_ac_stop_play(uacp, engine);
3025 usb_ac_teardown(uacp, engine);
3026
3027 usb_ac_serialize_access(uacp);
3028 mutex_enter(&uacp->usb_ac_mutex);
3029 }
3030
3031 /*
3032 * Set format for the streaming interface with lower write queue
3033 * This boils down to set_alternate interface command in
3034 * usb_as and the reply mp contains the currently active
3035 * alternate number that is stored in the as_req structure
3036 */
3037 if (usb_ac_send_as_cmd(uacp, engine,
3038 USB_AUDIO_SET_FORMAT, &format) != USB_SUCCESS) {
3039 USB_DPRINTF_L2(PRINT_MASK_ALL,
3040 uacp->usb_ac_log_handle,
3041 "usb_ac_set_format: failed");
3042 goto fail;
3043
3044 }
3045 int sample = engine->fmt.sr;
3046
3047 /* Set the sample rate */
3048 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_SET_SAMPLE_FREQ,
3049 &sample) != USB_SUCCESS) {
3050 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3051 "usb_ac_set_format: setting format failed");
3052 goto fail;
3053
3054 }
3055
3056 mutex_exit(&uacp->usb_ac_mutex);
3057
3058 usb_ac_release_access(uacp);
3059
3060 /* This should block until successful */
3061 if (old_setup_teardown_count) {
3062 (void) usb_ac_setup(uacp, engine);
3063 }
3064
3065 mutex_enter(&uacp->usb_ac_mutex);
3066 streams_infop->acs_setup_teardown_count = old_setup_teardown_count;
3067 mutex_exit(&uacp->usb_ac_mutex);
3068
3069 return (USB_SUCCESS);
3070 fail:
3071 streams_infop->acs_setup_teardown_count = old_setup_teardown_count;
3072 mutex_exit(&uacp->usb_ac_mutex);
3073 usb_ac_release_access(uacp);
3074
3075 return (USB_FAILURE);
3076
3077 }
3078
3079 /*
3080 * usb_ac_start_play
3081 * Send a start_play command down to usb_as
3082 * Check power is done in usb_ac_send_as_cmd()
3083 */
3084 static int
usb_ac_start_play(usb_ac_state_t * uacp,usb_audio_eng_t * engine)3085 usb_ac_start_play(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
3086 {
3087 int samples;
3088 usb_audio_play_req_t play_req;
3089
3090
3091 mutex_enter(&uacp->usb_ac_mutex);
3092 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
3093 mutex_exit(&uacp->usb_ac_mutex);
3094
3095 return (USB_FAILURE);
3096 }
3097 mutex_exit(&uacp->usb_ac_mutex);
3098
3099 usb_ac_serialize_access(uacp);
3100
3101 mutex_enter(&uacp->usb_ac_mutex);
3102
3103
3104
3105 /* Check for continuous sample rate done in usb_as */
3106 samples = engine->fmt.sr * engine->fmt.ch / engine->intrate;
3107 if (samples & engine->fmt.ch) {
3108 samples++;
3109 }
3110
3111 play_req.up_samples = samples;
3112 play_req.up_handle = uacp;
3113
3114 /* Send setup command to usb_as */
3115 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_START_PLAY,
3116 (void *)&play_req) != USB_SUCCESS) {
3117
3118 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3119 "usb_ac_start_play: failure");
3120
3121 mutex_exit(&uacp->usb_ac_mutex);
3122
3123 usb_ac_release_access(uacp);
3124
3125 return (USB_FAILURE);
3126 }
3127
3128 mutex_exit(&uacp->usb_ac_mutex);
3129
3130 usb_ac_release_access(uacp);
3131
3132 return (USB_SUCCESS);
3133 }
3134
3135
3136 /*
3137 * usb_ac_stop_play:
3138 * Stop the play engine
3139 * called from mixer framework.
3140 */
3141 void
usb_ac_stop_play(usb_ac_state_t * uacp,usb_audio_eng_t * engine)3142 usb_ac_stop_play(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
3143 {
3144
3145 if (engine == NULL) {
3146 engine = &(uacp->engines[0]);
3147 }
3148 mutex_enter(&uacp->usb_ac_mutex);
3149 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
3150 mutex_exit(&uacp->usb_ac_mutex);
3151
3152 return;
3153 }
3154 mutex_exit(&uacp->usb_ac_mutex);
3155
3156 usb_ac_serialize_access(uacp);
3157 mutex_enter(&uacp->usb_ac_mutex);
3158
3159 /* Send setup command to usb_as */
3160 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_PAUSE_PLAY,
3161 (void *)NULL) != USB_SUCCESS) {
3162
3163 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3164 "usb_ac_do_pause_play: failure");
3165 }
3166
3167 mutex_exit(&uacp->usb_ac_mutex);
3168 usb_ac_release_access(uacp);
3169 }
3170
3171
3172 /*
3173 * usb_ac_start_record:
3174 * Sends a start record command down to usb_as.
3175 * Check power is done in usb_ac_send_as_cmd()
3176 */
3177 static int
usb_ac_start_record(usb_ac_state_t * uacp,usb_audio_eng_t * engine)3178 usb_ac_start_record(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
3179 {
3180
3181
3182 mutex_enter(&uacp->usb_ac_mutex);
3183 if (uacp->usb_ac_dev_state != USB_DEV_ONLINE) {
3184 mutex_exit(&uacp->usb_ac_mutex);
3185
3186 return (USB_FAILURE);
3187 }
3188 mutex_exit(&uacp->usb_ac_mutex);
3189
3190 usb_ac_serialize_access(uacp);
3191 mutex_enter(&uacp->usb_ac_mutex);
3192
3193
3194 /* Send setup command to usb_as */
3195 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_START_RECORD,
3196 (void *)uacp) != USB_SUCCESS) {
3197
3198 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3199 "usb_ac_start_record: failure");
3200
3201 mutex_exit(&uacp->usb_ac_mutex);
3202
3203 usb_ac_release_access(uacp);
3204
3205 return (USB_FAILURE);
3206 }
3207
3208 mutex_exit(&uacp->usb_ac_mutex);
3209 usb_ac_release_access(uacp);
3210
3211 return (USB_SUCCESS);
3212 }
3213
3214
3215 /*
3216 * usb_ac_stop_record:
3217 * Wrapper function for usb_ac_do_stop_record and is
3218 * called form mixer framework.
3219 */
3220 static void
usb_ac_stop_record(usb_ac_state_t * uacp,usb_audio_eng_t * engine)3221 usb_ac_stop_record(usb_ac_state_t *uacp, usb_audio_eng_t *engine)
3222 {
3223
3224 usb_ac_serialize_access(uacp);
3225 mutex_enter(&uacp->usb_ac_mutex);
3226
3227 /* Send setup command to usb_as */
3228 if (usb_ac_send_as_cmd(uacp, engine, USB_AUDIO_STOP_RECORD,
3229 NULL) != USB_SUCCESS) {
3230
3231 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3232 "usb_ac_do_stop_record: failure");
3233 }
3234
3235 mutex_exit(&uacp->usb_ac_mutex);
3236 usb_ac_release_access(uacp);
3237 }
3238
3239
3240 /*
3241 * Helper Functions for Mixer callbacks
3242 *
3243 * usb_ac_get_maxmin_volume:
3244 * Send USBA command down to get the maximum or minimum gain balance
3245 * Calculate min or max gain balance and return that. Return
3246 * USB_FAILURE for failure cases
3247 */
3248 /* ARGSUSED */
3249 static int
usb_ac_get_maxmin_volume(usb_ac_state_t * uacp,uint_t channel,int cmd,int dir,int feature_unitID,short * max_or_minp)3250 usb_ac_get_maxmin_volume(usb_ac_state_t *uacp, uint_t channel, int cmd,
3251 int dir, int feature_unitID, short *max_or_minp)
3252 {
3253 mblk_t *data = NULL;
3254 usb_cr_t cr;
3255 usb_cb_flags_t cb_flags;
3256
3257
3258 mutex_exit(&uacp->usb_ac_mutex);
3259
3260 if (usb_pipe_sync_ctrl_xfer(
3261 uacp->usb_ac_dip,
3262 uacp->usb_ac_default_ph,
3263 USB_DEV_REQ_DEV_TO_HOST |
3264 USB_DEV_REQ_TYPE_CLASS |
3265 USB_DEV_REQ_RCPT_IF, /* bmRequestType */
3266 cmd, /* bRequest */
3267 (USB_AUDIO_VOLUME_CONTROL << 8) | channel, /* wValue */
3268 /* feature unit and id */
3269 (feature_unitID << 8)| uacp->usb_ac_ifno, /* wIndex */
3270 2, /* wLength */
3271 &data,
3272 USB_ATTRS_NONE,
3273 &cr, &cb_flags,
3274 USB_FLAGS_SLEEP) != USB_SUCCESS) {
3275 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3276 "usb_ac_get_maxmin_volume: failed, "
3277 "cr=%d, cb=0x%x cmd=%d, data=0x%p",
3278 cr, cb_flags, cmd, (void *)data);
3279
3280 freemsg(data);
3281 mutex_enter(&uacp->usb_ac_mutex);
3282
3283 return (USB_FAILURE);
3284 }
3285
3286 mutex_enter(&uacp->usb_ac_mutex);
3287 ASSERT(MBLKL(data) == 2);
3288
3289 *max_or_minp = (*(data->b_rptr+1) << 8) | *data->b_rptr;
3290
3291 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3292 "usb_ac_get_maxmin_volume: max_or_min=0x%x", *max_or_minp);
3293
3294 freemsg(data);
3295
3296 return (USB_SUCCESS);
3297 }
3298
3299
3300 /*
3301 * usb_ac_set_volume:
3302 * Send USBA command down to set the gain balance
3303 */
3304 /* ARGSUSED */
3305 static int
usb_ac_set_volume(usb_ac_state_t * uacp,uint_t channel,short gain,int dir,int feature_unitID)3306 usb_ac_set_volume(usb_ac_state_t *uacp, uint_t channel, short gain, int dir,
3307 int feature_unitID)
3308 {
3309 mblk_t *data = NULL;
3310 usb_cr_t cr;
3311 usb_cb_flags_t cb_flags;
3312 int rval = USB_FAILURE;
3313
3314
3315 mutex_exit(&uacp->usb_ac_mutex);
3316
3317 /* Construct the mblk_t from gain for sending to USBA */
3318 data = allocb(4, BPRI_HI);
3319 if (!data) {
3320 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3321 "usb_ac_set_volume: allocate data failed");
3322 mutex_enter(&uacp->usb_ac_mutex);
3323
3324 return (USB_FAILURE);
3325 }
3326
3327
3328
3329 *(data->b_wptr++) = (char)gain;
3330 *(data->b_wptr++) = (char)(gain >> 8);
3331
3332 if ((rval = usb_pipe_sync_ctrl_xfer(
3333 uacp->usb_ac_dip,
3334 uacp->usb_ac_default_ph,
3335 USB_DEV_REQ_HOST_TO_DEV |
3336 USB_DEV_REQ_TYPE_CLASS |
3337 USB_DEV_REQ_RCPT_IF, /* bmRequestType */
3338 USB_AUDIO_SET_CUR, /* bRequest */
3339 (USB_AUDIO_VOLUME_CONTROL << 8) | channel, /* wValue */
3340 /* feature unit and id */
3341 (feature_unitID << 8) | uacp->usb_ac_ifno, /* wIndex */
3342 2, /* wLength */
3343 &data, 0,
3344 &cr, &cb_flags, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
3345 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3346 "usb_ac_set_volume: failed, cr=%d cb=0x%x",
3347 cr, cb_flags);
3348 }
3349
3350 freemsg(data);
3351 mutex_enter(&uacp->usb_ac_mutex);
3352
3353 return (rval);
3354 }
3355
3356
3357 /*
3358 * usb_ac_set_mute is called for each unit that supports the
3359 * requested control from usb_ac_traverse_connections
3360 */
3361 int
usb_ac_set_mute(usb_ac_state_t * uacp,uint_t featureID,uint_t dir,uint_t channel,uint_t control,uint_t muteval,uint_t * depth)3362 usb_ac_set_mute(usb_ac_state_t *uacp, uint_t featureID, uint_t dir,
3363 uint_t channel, uint_t control, uint_t muteval, uint_t *depth)
3364 {
3365 mblk_t *data;
3366 usb_cr_t cr;
3367 usb_cb_flags_t cb_flags;
3368 int rval = USB_FAILURE;
3369
3370
3371 if (usb_ac_feature_unit_check(uacp, featureID,
3372 dir, channel, control, 0, depth) != USB_SUCCESS) {
3373
3374 return (USB_FAILURE);
3375 }
3376 mutex_exit(&uacp->usb_ac_mutex);
3377
3378 /* Construct the mblk_t for sending to USBA */
3379 data = allocb(1, BPRI_HI);
3380
3381 if (!data) {
3382 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3383 "usb_ac_set_mute: allocate data failed");
3384 mutex_enter(&uacp->usb_ac_mutex);
3385
3386 return (USB_FAILURE);
3387 }
3388
3389
3390 *(data->b_wptr++) = (char)muteval;
3391
3392 if ((rval = usb_pipe_sync_ctrl_xfer(
3393 uacp->usb_ac_dip,
3394 uacp->usb_ac_default_ph,
3395 USB_DEV_REQ_HOST_TO_DEV |
3396 USB_DEV_REQ_TYPE_CLASS |
3397 USB_DEV_REQ_RCPT_IF, /* bmRequestType */
3398 USB_AUDIO_SET_CUR, /* bRequest */
3399 (USB_AUDIO_MUTE_CONTROL << 8) | channel, /* wValue */
3400 /* feature unit and id */
3401 (featureID << 8) | uacp->usb_ac_ifno, /* wIndex */
3402 1, /* wLength */
3403 &data,
3404 0, /* attributes */
3405 &cr, &cb_flags, 0)) != USB_SUCCESS) {
3406
3407 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3408 "usb_ac_set_mute: failed, cr=%d cb=0x%x", cr, cb_flags);
3409 }
3410 freemsg(data);
3411
3412 mutex_enter(&uacp->usb_ac_mutex);
3413
3414 return (rval);
3415 }
3416
3417
3418 /*
3419 * usb_ac_send_as_cmd:
3420 * Allocate message blk, send a command down to usb_as,
3421 * wait for the reply and free the message
3422 *
3423 * although not really needed to raise power if sending to as
3424 * it seems better to ensure that both interfaces are at full power
3425 */
3426 static int
usb_ac_send_as_cmd(usb_ac_state_t * uacp,usb_audio_eng_t * engine,int cmd,void * arg)3427 usb_ac_send_as_cmd(usb_ac_state_t *uacp, usb_audio_eng_t *engine,
3428 int cmd, void *arg)
3429 {
3430 usb_ac_streams_info_t *streams_infop;
3431 usb_ac_plumbed_t *plumb_infop;
3432 int rv;
3433 int rval;
3434 ldi_handle_t lh;
3435
3436 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
3437 streams_infop = engine->streams;
3438 plumb_infop = streams_infop->acs_plumbed;
3439
3440
3441 lh = plumb_infop->acp_lh;
3442
3443 rv = ldi_ioctl(lh, cmd, (intptr_t)arg, FKIOCTL, kcred, &rval);
3444 if (rv != 0) {
3445 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3446 "usb_ac_send_as_cmd: ldi_ioctl failed, error=%d", rv);
3447
3448 return (USB_FAILURE);
3449 }
3450
3451 return (USB_SUCCESS);
3452 }
3453
3454
3455 /*
3456 * usb_ac_serialize/release_access:
3457 */
3458 static void
usb_ac_serialize_access(usb_ac_state_t * uacp)3459 usb_ac_serialize_access(usb_ac_state_t *uacp)
3460 {
3461 (void) usb_serialize_access(uacp->usb_ac_ser_acc, USB_WAIT, 0);
3462 }
3463
3464 static void
usb_ac_release_access(usb_ac_state_t * uacp)3465 usb_ac_release_access(usb_ac_state_t *uacp)
3466 {
3467 usb_release_access(uacp->usb_ac_ser_acc);
3468 }
3469
3470
3471 static void
usb_ac_pm_busy_component(usb_ac_state_t * usb_ac_statep)3472 usb_ac_pm_busy_component(usb_ac_state_t *usb_ac_statep)
3473 {
3474 ASSERT(!mutex_owned(&usb_ac_statep->usb_ac_mutex));
3475
3476 if (usb_ac_statep->usb_ac_pm != NULL) {
3477 mutex_enter(&usb_ac_statep->usb_ac_mutex);
3478 usb_ac_statep->usb_ac_pm->acpm_pm_busy++;
3479
3480 USB_DPRINTF_L4(PRINT_MASK_PM,
3481 usb_ac_statep->usb_ac_log_handle,
3482 "usb_ac_pm_busy_component: %d",
3483 usb_ac_statep->usb_ac_pm->acpm_pm_busy);
3484
3485 mutex_exit(&usb_ac_statep->usb_ac_mutex);
3486
3487 if (pm_busy_component(usb_ac_statep->usb_ac_dip, 0) !=
3488 DDI_SUCCESS) {
3489 mutex_enter(&usb_ac_statep->usb_ac_mutex);
3490 usb_ac_statep->usb_ac_pm->acpm_pm_busy--;
3491
3492 USB_DPRINTF_L2(PRINT_MASK_PM,
3493 usb_ac_statep->usb_ac_log_handle,
3494 "usb_ac_pm_busy_component failed: %d",
3495 usb_ac_statep->usb_ac_pm->acpm_pm_busy);
3496
3497 mutex_exit(&usb_ac_statep->usb_ac_mutex);
3498 }
3499 }
3500 }
3501
3502
3503 static void
usb_ac_pm_idle_component(usb_ac_state_t * usb_ac_statep)3504 usb_ac_pm_idle_component(usb_ac_state_t *usb_ac_statep)
3505 {
3506 ASSERT(!mutex_owned(&usb_ac_statep->usb_ac_mutex));
3507
3508 if (usb_ac_statep->usb_ac_pm != NULL) {
3509 if (pm_idle_component(usb_ac_statep->usb_ac_dip, 0) ==
3510 DDI_SUCCESS) {
3511 mutex_enter(&usb_ac_statep->usb_ac_mutex);
3512 ASSERT(usb_ac_statep->usb_ac_pm->acpm_pm_busy > 0);
3513 usb_ac_statep->usb_ac_pm->acpm_pm_busy--;
3514
3515 USB_DPRINTF_L4(PRINT_MASK_PM,
3516 usb_ac_statep->usb_ac_log_handle,
3517 "usb_ac_pm_idle_component: %d",
3518 usb_ac_statep->usb_ac_pm->acpm_pm_busy);
3519
3520 mutex_exit(&usb_ac_statep->usb_ac_mutex);
3521 }
3522 }
3523 }
3524
3525
3526 /*
3527 * handle read from plumbed drivers
3528 */
3529 static void
usb_ac_reader(void * argp)3530 usb_ac_reader(void *argp)
3531 {
3532 usb_ac_plumbed_t *acp = (usb_ac_plumbed_t *)argp;
3533 usb_ac_state_t *uacp = acp->acp_uacp;
3534 ldi_handle_t lh;
3535 mblk_t *mp;
3536 int rv;
3537 timestruc_t tv = {0};
3538
3539 mutex_enter(&uacp->usb_ac_mutex);
3540 lh = acp->acp_lh;
3541 tv.tv_sec = usb_ac_wait_hid;
3542
3543 while (acp->acp_flags & ACP_ENABLED) {
3544 mp = NULL;
3545
3546 mutex_exit(&uacp->usb_ac_mutex);
3547
3548 rv = ldi_getmsg(lh, &mp, &tv);
3549
3550 mutex_enter(&uacp->usb_ac_mutex);
3551
3552 if (rv == ENODEV) {
3553 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3554 "Device is not availabe");
3555 break;
3556 }
3557
3558
3559 if ((acp->acp_flags & ACP_ENABLED) && mp != NULL && rv == 0)
3560 rv = usb_ac_read_msg(acp, mp);
3561
3562 }
3563 mutex_exit(&uacp->usb_ac_mutex);
3564 }
3565
3566
3567 /*
3568 * setup threads to read from the other usb modules that may send unsolicited
3569 * or asynchronous messages, which is only hid currently
3570 */
3571 static int
usb_ac_plumb(usb_ac_plumbed_t * acp)3572 usb_ac_plumb(usb_ac_plumbed_t *acp)
3573 {
3574 usb_ac_state_t *uacp = acp->acp_uacp;
3575 dev_info_t *dip;
3576 dev_info_t *acp_dip;
3577 int acp_inst;
3578 char *acp_name;
3579 char tq_nm[128];
3580 int rv = USB_FAILURE;
3581
3582 mutex_enter(&uacp->usb_ac_mutex);
3583
3584 dip = uacp->usb_ac_dip;
3585
3586 acp_dip = acp->acp_dip;
3587 acp_inst = ddi_get_instance(acp_dip);
3588 acp_name = (char *)ddi_driver_name(acp_dip);
3589
3590 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3591 "usb_ac_plumb:begin");
3592
3593 if (strcmp(acp_name, "hid") != 0) {
3594 rv = USB_SUCCESS;
3595 goto OUT;
3596 }
3597
3598 (void) snprintf(tq_nm, sizeof (tq_nm), "%s_%d_tq",
3599 ddi_driver_name(acp_dip), acp_inst);
3600
3601 acp->acp_tqp = ddi_taskq_create(dip, tq_nm, 1, TASKQ_DEFAULTPRI, 0);
3602 if (acp->acp_tqp == NULL)
3603 goto OUT;
3604
3605 if (ddi_taskq_dispatch(acp->acp_tqp, usb_ac_reader, (void *)acp,
3606 DDI_SLEEP) != DDI_SUCCESS)
3607 goto OUT;
3608
3609 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3610 "usb_ac_plumb: dispatched reader");
3611
3612 rv = USB_SUCCESS;
3613
3614 OUT:
3615 mutex_exit(&uacp->usb_ac_mutex);
3616
3617 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3618 "usb_ac_plumb: done, rv=%d", rv);
3619
3620 return (rv);
3621 }
3622
3623
3624 static void
usb_ac_mux_plumbing_tq(void * arg)3625 usb_ac_mux_plumbing_tq(void *arg)
3626 {
3627 usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
3628
3629 if (usb_ac_mux_plumbing(uacp) != USB_SUCCESS)
3630 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3631 "usb_ac_mux_plumbing_tq:failed");
3632 }
3633
3634
3635 static int
usb_ac_do_plumbing(usb_ac_state_t * uacp)3636 usb_ac_do_plumbing(usb_ac_state_t *uacp)
3637 {
3638 dev_info_t *dip = uacp->usb_ac_dip;
3639 int inst = ddi_get_instance(dip);
3640 char tq_nm[128];
3641 int rv = USB_FAILURE;
3642
3643 (void) snprintf(tq_nm, sizeof (tq_nm), "%s_%d_tq",
3644 ddi_driver_name(dip), inst);
3645
3646 uacp->tqp = ddi_taskq_create(dip, tq_nm, 1, TASKQ_DEFAULTPRI, 0);
3647 if (uacp->tqp == NULL) {
3648 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3649 "usb_ac_do_plumbing: ddi_taskq_create failed");
3650 goto OUT;
3651 }
3652
3653 if (ddi_taskq_dispatch(uacp->tqp, usb_ac_mux_plumbing_tq, (void *)uacp,
3654 DDI_SLEEP) != DDI_SUCCESS) {
3655 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3656 "usb_ac_do_plumbing: ddi_taskq_dispatch failed");
3657 goto OUT;
3658 }
3659
3660 rv = USB_SUCCESS;
3661
3662 OUT:
3663 return (rv);
3664 }
3665
3666
3667
3668 static void
usb_ac_mux_unplumbing_tq(void * arg)3669 usb_ac_mux_unplumbing_tq(void *arg)
3670 {
3671 usb_ac_state_t *uacp = (usb_ac_state_t *)arg;
3672
3673 if (usb_ac_mux_unplumbing(uacp) != USB_SUCCESS)
3674 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3675 "usb_ac_mux_unplumbing:failed");
3676 }
3677
3678
3679 static int
usb_ac_do_unplumbing(usb_ac_state_t * uacp)3680 usb_ac_do_unplumbing(usb_ac_state_t *uacp)
3681 {
3682 int rv = USB_FAILURE;
3683
3684 if (uacp->tqp == NULL)
3685 return (USB_SUCCESS);
3686
3687 if (ddi_taskq_dispatch(uacp->tqp, usb_ac_mux_unplumbing_tq,
3688 (void *)uacp, DDI_SLEEP) != DDI_SUCCESS) {
3689 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3690 "usb_ac_do_unplumbing: ddi_taskq_dispatch failed");
3691 goto OUT;
3692 }
3693
3694 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3695 "usb_ac_do_unplumbing: waiting for unplumb thread");
3696
3697 ddi_taskq_wait(uacp->tqp);
3698 rv = USB_SUCCESS;
3699
3700 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3701 "usb_ac_do_unplumbing: unplumb thread done");
3702
3703 OUT:
3704 if (uacp->tqp != NULL) {
3705 ddi_taskq_destroy(uacp->tqp);
3706 uacp->tqp = NULL;
3707 }
3708 return (rv);
3709 }
3710
3711
3712 /*
3713 * teardown threads to the other usb modules
3714 * and clear structures as part of unplumbing
3715 */
3716 static void
usb_ac_unplumb(usb_ac_plumbed_t * acp)3717 usb_ac_unplumb(usb_ac_plumbed_t *acp)
3718 {
3719 usb_ac_streams_info_t *streams_infop;
3720 usb_ac_state_t *uacp = acp->acp_uacp;
3721
3722
3723 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3724 "usb_ac_unplumb: begin");
3725
3726 if (acp->acp_tqp != NULL) {
3727 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3728 "usb_ac_unplumb: destroying taskq");
3729
3730 ddi_taskq_destroy(acp->acp_tqp);
3731 }
3732
3733 mutex_enter(&uacp->usb_ac_mutex);
3734
3735 if (acp->acp_driver == USB_AS_PLUMBED) {
3736 /*
3737 * we bzero the streams info and plumbed structure
3738 * since there is no guarantee that the next plumbing
3739 * will be identical
3740 */
3741 streams_infop = (usb_ac_streams_info_t *)acp->acp_data;
3742
3743 /* bzero the relevant plumbing structure */
3744 bzero(streams_infop, sizeof (usb_ac_streams_info_t));
3745 }
3746 bzero(acp, sizeof (usb_ac_plumbed_t));
3747
3748 mutex_exit(&uacp->usb_ac_mutex);
3749
3750 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3751 "usb_ac_unplumb: done");
3752 }
3753
3754
3755 /*ARGSUSED*/
3756 static int
usb_ac_mux_plumbing(usb_ac_state_t * uacp)3757 usb_ac_mux_plumbing(usb_ac_state_t *uacp)
3758 {
3759 dev_info_t *dip;
3760
3761 /* get the usb_ac dip */
3762 dip = uacp->usb_ac_dip;
3763
3764 /* Access to the global variables is synchronized */
3765 mutex_enter(&uacp->usb_ac_mutex);
3766
3767 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3768 "usb_ac_mux_plumbing:state = %d",
3769 uacp->usb_ac_plumbing_state);
3770
3771 if (uacp->usb_ac_plumbing_state >= USB_AC_STATE_PLUMBED) {
3772 mutex_exit(&uacp->usb_ac_mutex);
3773 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3774 "usb_ac_mux_plumbing: audio streams driver"
3775 " already plumbed");
3776
3777 return (USB_SUCCESS);
3778 }
3779
3780 /* usb_as and hid should be attached but double check */
3781 if (usb_ac_online_siblings(uacp) != USB_SUCCESS) {
3782 mutex_exit(&uacp->usb_ac_mutex);
3783 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3784 "usb_ac_mux_plumbing:no audio streams driver plumbed");
3785
3786 return (USB_FAILURE);
3787 }
3788
3789 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3790 "usb_ac_mux_plumbing: raising power");
3791 mutex_exit(&uacp->usb_ac_mutex);
3792
3793 /* bring the device to full power */
3794 usb_ac_pm_busy_component(uacp);
3795 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
3796
3797 /* avoid dips disappearing while we are plumbing */
3798 usb_ac_hold_siblings(uacp);
3799
3800 mutex_enter(&uacp->usb_ac_mutex);
3801
3802 /*
3803 * walk all siblings and create the usb_ac<->usb_as and
3804 * usb_ac<->hid streams. return of 0 indicates no or
3805 * partial/failed plumbing
3806 */
3807 if (usb_ac_mux_walk_siblings(uacp) == 0) {
3808 /* pretend that we are plumbed so we can unplumb */
3809 uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
3810
3811 mutex_exit(&uacp->usb_ac_mutex);
3812
3813 (void) usb_ac_mux_unplumbing(uacp);
3814
3815 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3816 "usb_ac_mux_plumbing: no audio streams driver plumbed");
3817
3818 usb_ac_rele_siblings(uacp);
3819
3820 usb_ac_pm_idle_component(uacp);
3821
3822 return (USB_FAILURE);
3823 }
3824 uacp->usb_ac_plumbing_state = USB_AC_STATE_PLUMBED;
3825
3826 /* restore state if we have already registered with the mixer */
3827 if (uacp->usb_ac_registered_with_mixer) {
3828 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3829 "usb_ac_mux_plumbing:already registered with mixer,"
3830 "restoring state");
3831
3832 (void) usb_ac_restore_audio_state(uacp, USB_FLAGS_SLEEP);
3833
3834 } else if (usb_ac_mixer_registration(uacp) != USB_SUCCESS) {
3835 mutex_exit(&uacp->usb_ac_mutex);
3836
3837 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3838 "usb_ac_mux_plumbing: mixer registration failed");
3839
3840 (void) usb_ac_mux_unplumbing(uacp);
3841
3842 usb_ac_rele_siblings(uacp);
3843
3844 usb_ac_pm_idle_component(uacp);
3845
3846 return (USB_FAILURE);
3847 }
3848
3849 mutex_exit(&uacp->usb_ac_mutex);
3850 usb_ac_rele_siblings(uacp);
3851
3852 usb_ac_pm_idle_component(uacp);
3853
3854 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3855 "usb_ac_mux_plumbing:done");
3856
3857 return (USB_SUCCESS);
3858 }
3859
3860
3861 static int
usb_ac_mux_unplumbing(usb_ac_state_t * uacp)3862 usb_ac_mux_unplumbing(usb_ac_state_t *uacp)
3863 {
3864 usb_ac_plumbed_t *acp;
3865 ldi_handle_t lh;
3866 dev_info_t *acp_dip;
3867 int inst;
3868 int i;
3869 dev_t devt;
3870 minor_t minor;
3871 int maxlinked = 0;
3872
3873 mutex_enter(&uacp->usb_ac_mutex);
3874
3875
3876 if (uacp->usb_ac_plumbing_state == USB_AC_STATE_UNPLUMBED) {
3877 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3878 "usb_ac_mux_unplumbing: already unplumbed!");
3879 mutex_exit(&uacp->usb_ac_mutex);
3880
3881 return (USB_SUCCESS);
3882 }
3883
3884 /* usb_ac might not have anything plumbed yet */
3885 if (uacp->usb_ac_current_plumbed_index == -1) {
3886 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3887 "usb_ac_mux_unplumbing: nothing plumbed");
3888 uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
3889 mutex_exit(&uacp->usb_ac_mutex);
3890
3891 return (USB_SUCCESS);
3892 }
3893
3894 /* do not allow detach if still busy */
3895 if (uacp->usb_ac_busy_count) {
3896 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3897 "usb_ac_mux_unplumbing: mux still busy (%d)",
3898 uacp->usb_ac_busy_count);
3899 mutex_exit(&uacp->usb_ac_mutex);
3900
3901 return (USB_FAILURE);
3902 }
3903
3904 uacp->usb_ac_plumbing_state = USB_AC_STATE_UNPLUMBED;
3905
3906 /* close ac-as and ac-hid streams */
3907 maxlinked = uacp->usb_ac_current_plumbed_index + 1;
3908 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3909 "usb_ac_mux_unplumbing: maxlinked = %d", maxlinked);
3910
3911 for (i = 0; i < maxlinked; i++) {
3912 /*
3913 * we must save members of usb_ac_plumbed[] before calling
3914 * usb_ac_unplumb() because it clears the structure
3915 */
3916 acp = &uacp->usb_ac_plumbed[i];
3917 lh = acp->acp_lh;
3918 acp_dip = acp->acp_dip;
3919 devt = acp->acp_devt;
3920
3921 if (acp_dip == NULL) {
3922 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3923 "usb_ac_mux_unplumbing: [%d] - skipping", i);
3924 continue;
3925 }
3926
3927 minor = getminor(devt);
3928 inst = ddi_get_instance(acp_dip);
3929
3930 uacp->usb_ac_current_plumbed_index = i;
3931
3932 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3933 "usb_ac_mux_unplumbing: [%d] - %s%d minor 0x%x", i,
3934 ddi_driver_name(acp_dip), inst, minor);
3935
3936 if (lh != NULL) {
3937
3938 acp->acp_flags &= ~ACP_ENABLED;
3939
3940 mutex_exit(&uacp->usb_ac_mutex);
3941
3942 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3943 "usb_ac_mux_unplumbing:[%d] - closing", i);
3944
3945 /*
3946 * ldi_close will cause panic if ldi_getmsg
3947 * is not finished. ddi_taskq_destroy will wait
3948 * for the thread to complete.
3949 */
3950 usb_ac_unplumb(acp);
3951 (void) ldi_close(lh, FREAD|FWRITE, kcred);
3952
3953
3954 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3955 "usb_ac_mux_unplumbing: [%d] - unplumbed", i);
3956
3957 mutex_enter(&uacp->usb_ac_mutex);
3958 }
3959 }
3960
3961 mutex_exit(&uacp->usb_ac_mutex);
3962
3963 /* Wait till all activity in the default pipe has drained */
3964 usb_ac_serialize_access(uacp);
3965 usb_ac_release_access(uacp);
3966
3967 mutex_enter(&uacp->usb_ac_mutex);
3968 uacp->usb_ac_current_plumbed_index = -1;
3969 mutex_exit(&uacp->usb_ac_mutex);
3970
3971 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
3972 "usb_ac_mux_unplumbing: done");
3973
3974 return (USB_SUCCESS);
3975 }
3976
3977
3978 /*
3979 * walk all siblings and create the ac<->as and ac<->hid streams
3980 */
3981 static int
usb_ac_mux_walk_siblings(usb_ac_state_t * uacp)3982 usb_ac_mux_walk_siblings(usb_ac_state_t *uacp)
3983 {
3984 dev_info_t *pdip;
3985 dev_info_t *child_dip;
3986 major_t drv_major;
3987 minor_t drv_minor;
3988 int drv_instance;
3989 char *drv_name;
3990 dev_t drv_devt;
3991 ldi_handle_t drv_lh;
3992 ldi_ident_t li;
3993 int error;
3994 int count = 0;
3995
3996 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
3997
3998 pdip = ddi_get_parent(uacp->usb_ac_dip);
3999 child_dip = ddi_get_child(pdip);
4000
4001 while ((child_dip != NULL) && (count < USB_AC_MAX_PLUMBED)) {
4002 drv_instance = ddi_get_instance(child_dip);
4003 drv_name = (char *)ddi_driver_name(child_dip);
4004
4005 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4006 "usb_ac_mux_walk_siblings: plumbing %s%d count=%d",
4007 drv_name, drv_instance, count);
4008
4009 /* ignore own dip */
4010 if (child_dip == uacp->usb_ac_dip) {
4011 child_dip = ddi_get_next_sibling(child_dip);
4012 continue;
4013 }
4014 drv_instance = ddi_get_instance(child_dip);
4015
4016 /* ignore other dip other than usb_as and hid */
4017 if (strcmp(ddi_driver_name(child_dip), "usb_as") == 0) {
4018 uacp->usb_ac_plumbed[count].acp_driver = USB_AS_PLUMBED;
4019 drv_minor = USB_AS_CONSTRUCT_MINOR(drv_instance);
4020 } else if (strcmp(ddi_driver_name(child_dip), "hid") == 0) {
4021 uacp->usb_ac_plumbed[count].acp_driver = USB_AH_PLUMBED;
4022 drv_minor = HID_CONSTRUCT_EXTERNAL_MINOR(drv_instance);
4023 } else {
4024 drv_minor = drv_instance;
4025 uacp->usb_ac_plumbed[count].acp_driver =
4026 UNKNOWN_PLUMBED;
4027 child_dip = ddi_get_next_sibling(child_dip);
4028
4029 continue;
4030 }
4031
4032 if (!i_ddi_devi_attached(child_dip)) {
4033 child_dip = ddi_get_next_sibling(child_dip);
4034
4035 continue;
4036 }
4037
4038 if (DEVI_IS_DEVICE_REMOVED(child_dip)) {
4039 child_dip = ddi_get_next_sibling(child_dip);
4040
4041 continue;
4042 }
4043
4044 drv_major = ddi_driver_major(child_dip);
4045
4046 uacp->usb_ac_current_plumbed_index = count;
4047
4048 mutex_exit(&uacp->usb_ac_mutex);
4049
4050 drv_devt = makedevice(drv_major, drv_minor);
4051
4052 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4053 "usb_ac_mux_walk_siblings:: opening %s%d devt=(%d, 0x%x)",
4054 drv_name, drv_instance, drv_major, drv_minor);
4055
4056 error = ldi_ident_from_dip(uacp->usb_ac_dip, &li);
4057 if (error == 0) {
4058 mutex_enter(&uacp->usb_ac_mutex);
4059 uacp->usb_ac_plumbed[count].acp_flags |= ACP_ENABLED;
4060 mutex_exit(&uacp->usb_ac_mutex);
4061
4062 error = ldi_open_by_dev(&drv_devt, OTYP_CHR,
4063 FREAD|FWRITE, kcred, &drv_lh, li);
4064 ldi_ident_release(li);
4065 }
4066
4067 mutex_enter(&uacp->usb_ac_mutex);
4068 if (error) {
4069 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4070 "usb_ac_mux_walk_siblings: open of devt=(%d, 0x%x)"
4071 " failed error=%d", drv_major, drv_minor, error);
4072
4073 return (0);
4074 }
4075
4076 uacp->usb_ac_plumbed[count].acp_uacp = uacp;
4077 uacp->usb_ac_plumbed[count].acp_devt = drv_devt;
4078 uacp->usb_ac_plumbed[count].acp_lh = drv_lh;
4079 uacp->usb_ac_plumbed[count].acp_dip = child_dip;
4080 uacp->usb_ac_plumbed[count].acp_ifno =
4081 usb_get_if_number(child_dip);
4082
4083 if (uacp->usb_ac_plumbed[count].acp_driver == USB_AS_PLUMBED) {
4084 /* get registration data */
4085 if (usb_ac_get_reg_data(uacp, drv_lh, count) !=
4086 USB_SUCCESS) {
4087
4088 USB_DPRINTF_L3(PRINT_MASK_ALL,
4089 uacp->usb_ac_log_handle,
4090 "usb_ac_mux_walk_siblings:"
4091 "usb_ac_get_reg_data failed on %s%d",
4092 drv_name, drv_instance);
4093
4094 uacp->usb_ac_plumbed[count].acp_dip = NULL;
4095
4096 return (0);
4097 }
4098 } else if (uacp->usb_ac_plumbed[count].acp_driver ==
4099 USB_AH_PLUMBED) {
4100 int rval;
4101
4102 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4103 "usb_ac_mux_walk_siblings: pushing usb_ah on %s%d",
4104 drv_name, drv_instance);
4105
4106 mutex_exit(&uacp->usb_ac_mutex);
4107
4108 /* push usb_ah module on top of hid */
4109 error = ldi_ioctl(drv_lh, I_PUSH, (intptr_t)"usb_ah",
4110 FKIOCTL, kcred, &rval);
4111 mutex_enter(&uacp->usb_ac_mutex);
4112
4113 if (error) {
4114 USB_DPRINTF_L2(PRINT_MASK_ALL,
4115 uacp->usb_ac_log_handle,
4116 "usb_ac_mux_walk_siblings: ldi_ioctl"
4117 "I_PUSH failed on %s%d, error=%d",
4118 drv_name, drv_instance, error);
4119
4120 uacp->usb_ac_plumbed[count].acp_dip = NULL;
4121
4122 /* skip plumbing the hid driver */
4123 child_dip = ddi_get_next_sibling(child_dip);
4124 continue;
4125 }
4126 } else {
4127 /* should not be here */
4128 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4129 "usb_ac_mux_walk_siblings:- unknown module %s%d",
4130 drv_name, drv_instance);
4131 count--;
4132
4133 uacp->usb_ac_plumbed[count].acp_dip = NULL;
4134
4135 /* skip plumbing an unknown module */
4136 child_dip = ddi_get_next_sibling(child_dip);
4137 continue;
4138 }
4139
4140 mutex_exit(&uacp->usb_ac_mutex);
4141 error = usb_ac_plumb(&uacp->usb_ac_plumbed[count]);
4142 mutex_enter(&uacp->usb_ac_mutex);
4143
4144 if (error != USB_SUCCESS) {
4145 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4146 "usb_ac_mux_walk_siblings: usb_ac_plumb "
4147 "failed for %s%d", drv_name, drv_instance);
4148
4149 return (0);
4150 }
4151
4152 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4153 "usb_ac_mux_walk_siblings:plumbed %d, minor 0x%x",
4154 drv_instance, drv_minor);
4155
4156 child_dip = ddi_get_next_sibling(child_dip);
4157 count++;
4158 }
4159
4160 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4161 "usb_ac_mux_walk_siblings: %d drivers plumbed under usb_ac mux",
4162 count);
4163
4164 return (count);
4165 }
4166
4167
4168 /*
4169 * Register with mixer only after first plumbing.
4170 * Also do not register if earlier reg data
4171 * couldn't be received from at least one
4172 * streaming interface
4173 */
4174
4175 static int
usb_ac_mixer_registration(usb_ac_state_t * uacp)4176 usb_ac_mixer_registration(usb_ac_state_t *uacp)
4177 {
4178 usb_as_registration_t *asreg;
4179 int n;
4180
4181 if (uacp->usb_ac_registered_with_mixer) {
4182 return (USB_SUCCESS);
4183 }
4184
4185 for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
4186 if (uacp->usb_ac_streams[n].acs_rcvd_reg_data) {
4187 break;
4188 }
4189 }
4190
4191 /* Haven't found a streaming interface; fail mixer registration */
4192 if (n > USB_AC_MAX_AS_PLUMBED) {
4193 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4194 "usb_ac_mixer_registration:- no streaming interface found");
4195
4196 return (USB_FAILURE);
4197 }
4198
4199 /*
4200 * Fill out streaming interface specific stuff
4201 * Note that we handle only one playing and one recording
4202 * streaming interface at the most
4203 */
4204 for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
4205 int ch, chs, id;
4206
4207 if (uacp->usb_ac_streams[n].acs_rcvd_reg_data == 0) {
4208 continue;
4209 }
4210
4211 asreg = &(uacp->usb_ac_streams[n].acs_streams_reg);
4212 if (asreg->reg_valid == 0) {
4213 continue;
4214 }
4215
4216
4217 chs = asreg->reg_formats[0].fmt_chns;
4218
4219 /* check if any channel supports vol. control for this fmt */
4220 for (ch = 0; ch <= chs; ch++) {
4221 if ((id = usb_ac_get_featureID(uacp,
4222 asreg->reg_mode, ch,
4223 USB_AUDIO_VOLUME_CONTROL)) != -1) {
4224 USB_DPRINTF_L3(PRINT_MASK_ALL,
4225 uacp->usb_ac_log_handle,
4226 "usb_ac_mixer_registration:n= [%d]"
4227 "- dir=%d featureID=%d",
4228 n, asreg->reg_mode, id);
4229
4230 break;
4231 }
4232 }
4233
4234 uacp->usb_ac_streams[n].acs_default_gain =
4235 (id == USB_AC_ID_NONE) ? (AF_MAX_GAIN): (AF_MAX_GAIN*3/4);
4236
4237 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4238 "usb_ac_mixer_registration:n= [%d] - mode=%d chs=%d"
4239 "default_gain=%d id=%d",
4240 n, asreg->reg_mode, chs,
4241 uacp->usb_ac_streams[n].acs_default_gain, id);
4242
4243 }
4244
4245 /* the rest */
4246
4247 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4248 "usb_ac_mixer_registration: calling usb_audio_register");
4249
4250 mutex_exit(&uacp->usb_ac_mutex);
4251
4252 if (usb_audio_register(uacp) != USB_SUCCESS) {
4253 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4254 "usb_ac_mixer_registration: usb_audio_register failed");
4255
4256 mutex_enter(&uacp->usb_ac_mutex);
4257
4258 return (USB_FAILURE);
4259 }
4260
4261 mutex_enter(&uacp->usb_ac_mutex);
4262
4263 uacp->usb_ac_registered_with_mixer = 1;
4264
4265 return (USB_SUCCESS);
4266 }
4267
4268
4269 /*
4270 * Get registriations data when driver attach
4271 */
4272 static int
usb_ac_get_reg_data(usb_ac_state_t * uacp,ldi_handle_t drv_lh,int index)4273 usb_ac_get_reg_data(usb_ac_state_t *uacp, ldi_handle_t drv_lh, int index)
4274 {
4275 int n, error, rval;
4276 usb_as_registration_t *streams_reg;
4277
4278
4279 ASSERT(uacp->usb_ac_registered_with_mixer == 0);
4280
4281 for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
4282 /*
4283 * We haven't received registration data
4284 * from n-th streaming interface in the array
4285 */
4286 if (!uacp->usb_ac_streams[n].acs_rcvd_reg_data) {
4287 break;
4288 }
4289 }
4290
4291 if (n >= USB_AC_MAX_AS_PLUMBED) {
4292 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4293 "More than 2 streaming interfaces (play "
4294 "and/or record) currently not supported");
4295
4296 return (USB_FAILURE);
4297 }
4298
4299 /* take the stream reg struct with the same index */
4300 streams_reg = &uacp->usb_ac_streams[n].acs_streams_reg;
4301
4302 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4303 "usb_ac_get_reg_data:regdata from usb_as: streams_reg=0x%p, n=%d",
4304 (void *)streams_reg, n);
4305
4306 mutex_exit(&uacp->usb_ac_mutex);
4307
4308 if ((error = ldi_ioctl(drv_lh, USB_AUDIO_MIXER_REGISTRATION,
4309 (intptr_t)streams_reg, FKIOCTL, kcred, &rval)) != 0) {
4310 USB_DPRINTF_L2(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4311 "usb_ac_get_reg_data: ldi_ioctl failed for"
4312 "mixer registration error=%d", error);
4313
4314 mutex_enter(&uacp->usb_ac_mutex);
4315
4316 return (USB_FAILURE);
4317 } else {
4318 mutex_enter(&uacp->usb_ac_mutex);
4319
4320 rval = usb_ac_setup_plumbed(uacp, index, n);
4321
4322 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4323 "usb_ac_get_reg_data:usb_ac_streams[%d]: "
4324 "received_reg_data=%d type=%s", index,
4325 uacp->usb_ac_streams[n].acs_rcvd_reg_data,
4326 ((streams_reg->reg_mode == USB_AUDIO_PLAY) ?
4327 "play" : "record"));
4328
4329 usb_ac_print_reg_data(uacp, streams_reg);
4330
4331 return (rval);
4332 }
4333 }
4334
4335
4336 /*
4337 * setup plumbed and stream info structure
4338 */
4339 static int
usb_ac_setup_plumbed(usb_ac_state_t * uacp,int plb_idx,int str_idx)4340 usb_ac_setup_plumbed(usb_ac_state_t *uacp, int plb_idx, int str_idx)
4341 {
4342 uacp->usb_ac_plumbed[plb_idx].acp_data =
4343 &uacp->usb_ac_streams[str_idx];
4344 uacp->usb_ac_streams[str_idx].acs_plumbed =
4345 &uacp->usb_ac_plumbed[plb_idx];
4346 uacp->usb_ac_streams[str_idx].acs_rcvd_reg_data = 1;
4347
4348
4349 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4350 "usb_ac_setup_plumbed: done - plb_idx=%d str_idx=%d ",
4351 plb_idx, str_idx);
4352
4353 return (USB_SUCCESS);
4354 }
4355
4356
4357 /*
4358 * function to dump registration data
4359 */
4360 static void
usb_ac_print_reg_data(usb_ac_state_t * uacp,usb_as_registration_t * reg)4361 usb_ac_print_reg_data(usb_ac_state_t *uacp,
4362 usb_as_registration_t *reg)
4363 {
4364 int n;
4365
4366 for (n = 0; n < reg->reg_n_formats; n++) {
4367 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4368 "format%d: alt=%d chns=%d prec=%d enc=%d", n,
4369 reg->reg_formats[n].fmt_alt,
4370 reg->reg_formats[n].fmt_chns,
4371 reg->reg_formats[n].fmt_precision,
4372 reg->reg_formats[n].fmt_encoding);
4373 }
4374
4375 for (n = 0; n < USB_AS_N_FORMATS; n++) {
4376 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4377 "reg_formats[%d] ptr=0x%p", n,
4378 (void *)®->reg_formats[n]);
4379 }
4380
4381 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4382 "usb_ac_print_reg_data: End");
4383 }
4384
4385
4386 static int
usb_ac_online_siblings(usb_ac_state_t * uacp)4387 usb_ac_online_siblings(usb_ac_state_t *uacp)
4388 {
4389 dev_info_t *pdip, *child_dip;
4390 int rval = USB_SUCCESS;
4391
4392 ASSERT(mutex_owned(&uacp->usb_ac_mutex));
4393
4394 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4395 "usb_ac_online_siblings:start");
4396
4397 pdip = ddi_get_parent(uacp->usb_ac_dip);
4398
4399 child_dip = ddi_get_child(pdip);
4400 while (child_dip != NULL) {
4401
4402 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4403 "usb_ac_online_siblings: onlining %s%d ref=%d",
4404 ddi_driver_name(child_dip),
4405 ddi_get_instance(child_dip),
4406 DEVI(child_dip)->devi_ref);
4407
4408 /* Online the child_dip of usb_as and hid, if not already */
4409 if ((strcmp(ddi_driver_name(child_dip), "usb_as") == 0) ||
4410 (strcmp(ddi_driver_name(child_dip), "hid") == 0)) {
4411
4412 mutex_exit(&uacp->usb_ac_mutex);
4413 if (ndi_devi_online(child_dip, NDI_ONLINE_ATTACH) !=
4414 NDI_SUCCESS) {
4415 USB_DPRINTF_L3(PRINT_MASK_ALL,
4416 uacp->usb_ac_log_handle,
4417 "usb_ac_online_siblings:failed to online"
4418 "device %s%d", ddi_driver_name(child_dip),
4419 ddi_get_instance(child_dip));
4420
4421 /* only onlining usb_as is fatal */
4422 if (strcmp(ddi_driver_name(child_dip),
4423 "usb_as") == 0) {
4424 mutex_enter(&uacp->usb_ac_mutex);
4425 rval = USB_FAILURE;
4426 break;
4427 }
4428 }
4429 mutex_enter(&uacp->usb_ac_mutex);
4430 }
4431 child_dip = ddi_get_next_sibling(child_dip);
4432 }
4433
4434 return (rval);
4435 }
4436
4437
4438 /*
4439 * hold all audio children before or after plumbing
4440 * online usb_as and hid, if not already
4441 */
4442 static void
usb_ac_hold_siblings(usb_ac_state_t * uacp)4443 usb_ac_hold_siblings(usb_ac_state_t *uacp)
4444 {
4445 dev_info_t *pdip, *child_dip;
4446
4447 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4448 "usb_ac_hold_siblings:start");
4449
4450 /* hold all siblings and ourselves */
4451 pdip = ddi_get_parent(uacp->usb_ac_dip);
4452
4453 /* hold the children */
4454 ndi_devi_enter(pdip);
4455 child_dip = ddi_get_child(pdip);
4456 while (child_dip != NULL) {
4457 ndi_hold_devi(child_dip);
4458
4459 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4460 "usb_ac_hold_siblings: held %s%d ref=%d",
4461 ddi_driver_name(child_dip), ddi_get_instance(child_dip),
4462 DEVI(child_dip)->devi_ref);
4463
4464 child_dip = ddi_get_next_sibling(child_dip);
4465 }
4466 ndi_devi_exit(pdip);
4467 }
4468
4469
4470 /*
4471 * release all audio children before or after plumbing
4472 */
4473 static void
usb_ac_rele_siblings(usb_ac_state_t * uacp)4474 usb_ac_rele_siblings(usb_ac_state_t *uacp)
4475 {
4476 dev_info_t *pdip, *child_dip;
4477
4478 USB_DPRINTF_L4(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4479 "usb_ac_rele_siblings: start");
4480
4481 /* release all siblings and ourselves */
4482 pdip = ddi_get_parent(uacp->usb_ac_dip);
4483 ndi_devi_enter(pdip);
4484 child_dip = ddi_get_child(pdip);
4485 while (child_dip != NULL) {
4486 ndi_rele_devi(child_dip);
4487
4488 USB_DPRINTF_L3(PRINT_MASK_ALL, uacp->usb_ac_log_handle,
4489 "usb_ac_rele_siblings: released %s%d ref=%d",
4490 ddi_driver_name(child_dip), ddi_get_instance(child_dip),
4491 DEVI(child_dip)->devi_ref);
4492
4493 child_dip = ddi_get_next_sibling(child_dip);
4494 }
4495 ndi_devi_exit(pdip);
4496 }
4497 static void
usb_restore_engine(usb_ac_state_t * statep)4498 usb_restore_engine(usb_ac_state_t *statep)
4499 {
4500 usb_audio_eng_t *engp;
4501 int i;
4502
4503 for (i = 0; i < USB_AC_ENG_MAX; i++) {
4504
4505 mutex_enter(&statep->usb_ac_mutex);
4506 engp = &statep->engines[i];
4507 mutex_exit(&statep->usb_ac_mutex);
4508
4509 if (engp->af_engp == NULL)
4510 continue;
4511 if (usb_ac_set_format(statep, engp) != USB_SUCCESS) {
4512 USB_DPRINTF_L2(PRINT_MASK_ATTA,
4513 statep->usb_ac_log_handle,
4514 "usb_restore_engine:set format fail, i=%d", i);
4515 return;
4516 }
4517 if (engp->started) {
4518 (void) usb_engine_start(engp);
4519 }
4520
4521 }
4522
4523 (void) usb_ac_ctrl_restore(statep);
4524 }
4525
4526
4527 /*
4528 * get the maximum format specification the device supports
4529 */
4530 static void
usb_ac_max_fmt(usb_as_registration_t * reg_data,usb_audio_format_t * fmtp)4531 usb_ac_max_fmt(usb_as_registration_t *reg_data,
4532 usb_audio_format_t *fmtp)
4533 {
4534
4535 uint_t ch = 0, sr = 0, prec = 0, enc = 0;
4536 int i;
4537
4538 usb_audio_formats_t *reg_formats = reg_data->reg_formats;
4539
4540 /* format priority: channels, sample rate, precision, encoding */
4541 for (i = 0; i < reg_data->reg_n_formats; i++) {
4542 uint_t val, fmt_sr;
4543 int n, keep;
4544
4545 val = reg_formats[i].fmt_chns;
4546 if (val < ch)
4547 continue;
4548 if (val > ch)
4549 keep = 1;
4550
4551 for (n = 0, fmt_sr = 0; n < reg_formats[i].fmt_n_srs; n++) {
4552 if (fmt_sr < reg_formats[i].fmt_srs[n]) {
4553 fmt_sr = reg_formats[i].fmt_srs[n];
4554 }
4555 }
4556 if (!keep && fmt_sr < sr)
4557 continue;
4558 if (fmt_sr > sr)
4559 keep = 1;
4560
4561 val = reg_formats[i].fmt_precision;
4562 if (!keep && (val < prec))
4563 continue;
4564 if (val > prec)
4565 keep = 1;
4566
4567 val = reg_formats[i].fmt_encoding;
4568 if (!keep && (val < enc))
4569 continue;
4570
4571 ch = reg_formats[i].fmt_chns;
4572 sr = fmt_sr;
4573 prec = reg_formats[i].fmt_precision;
4574 enc = reg_formats[i].fmt_encoding;
4575 }
4576
4577 fmtp->ch = ch;
4578 fmtp->sr = sr;
4579 fmtp->prec = prec;
4580 fmtp->enc = enc;
4581 }
4582
4583
4584 static void
usb_ac_rem_eng(usb_ac_state_t * statep,usb_audio_eng_t * engp)4585 usb_ac_rem_eng(usb_ac_state_t *statep, usb_audio_eng_t *engp)
4586 {
4587 if (statep->usb_ac_audio_dev == NULL || engp->af_engp == NULL)
4588 return;
4589
4590 audio_dev_remove_engine(statep->usb_ac_audio_dev, engp->af_engp);
4591 audio_engine_free(engp->af_engp);
4592
4593 mutex_enter(&engp->lock);
4594 engp->af_engp = NULL;
4595 engp->streams = NULL;
4596 mutex_exit(&engp->lock);
4597
4598 mutex_destroy(&engp->lock);
4599 cv_destroy(&engp->usb_audio_cv);
4600 }
4601
4602
4603 static int
usb_ac_add_eng(usb_ac_state_t * uacp,usb_ac_streams_info_t * asinfo)4604 usb_ac_add_eng(usb_ac_state_t *uacp, usb_ac_streams_info_t *asinfo)
4605 {
4606 audio_dev_t *af_devp = uacp->usb_ac_audio_dev;
4607 usb_audio_eng_t *engp;
4608 audio_engine_t *af_engp;
4609 int rv = USB_FAILURE;
4610 int dir = asinfo->acs_streams_reg.reg_mode;
4611 uint_t defgain;
4612
4613 if (asinfo->acs_rcvd_reg_data == 0) {
4614
4615 return (USB_SUCCESS);
4616 }
4617 if (dir == USB_AUDIO_PLAY) {
4618 engp = &(uacp->engines[0]);
4619 } else {
4620 engp = &(uacp->engines[1]);
4621 }
4622
4623 cv_init(&engp->usb_audio_cv, NULL, CV_DRIVER, NULL);
4624
4625 mutex_init(&engp->lock, NULL, MUTEX_DRIVER, NULL);
4626
4627 mutex_enter(&engp->lock);
4628
4629 engp->af_eflags =
4630 (dir == USB_AUDIO_PLAY)?ENGINE_OUTPUT_CAP:ENGINE_INPUT_CAP;
4631 engp->statep = uacp;
4632
4633 /* Set the format for the engine */
4634 usb_ac_max_fmt(&(asinfo->acs_streams_reg), &engp->fmt);
4635
4636 /* init the default gain */
4637 defgain = asinfo->acs_default_gain;
4638 if (engp->fmt.ch == 2) {
4639 engp->af_defgain = AUDIO_CTRL_STEREO_VAL(defgain, defgain);
4640 } else {
4641 engp->af_defgain = defgain;
4642 }
4643 engp->streams = asinfo;
4644
4645 mutex_exit(&engp->lock);
4646
4647 af_engp = audio_engine_alloc(&usb_engine_ops, engp->af_eflags);
4648 if (af_engp == NULL) {
4649
4650 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
4651 "audio_engine_alloc failed");
4652 goto OUT;
4653 }
4654 ASSERT(engp->af_engp == 0);
4655
4656 mutex_enter(&engp->lock);
4657 engp->af_engp = af_engp;
4658 mutex_exit(&engp->lock);
4659
4660 audio_engine_set_private(af_engp, engp);
4661 audio_dev_add_engine(af_devp, af_engp);
4662
4663 /*
4664 * Set the format for this engine
4665 */
4666 if (usb_ac_set_format(uacp, engp) != USB_SUCCESS) {
4667 USB_DPRINTF_L2(PRINT_MASK_ATTA, uacp->usb_ac_log_handle,
4668 "set format failed, dir = %d", dir);
4669 goto OUT;
4670 }
4671 rv = USB_SUCCESS;
4672
4673 OUT:
4674 if (rv != USB_SUCCESS)
4675 usb_ac_rem_eng(uacp, engp);
4676
4677 return (rv);
4678 }
4679
4680
4681 static int
usb_ac_ctrl_set_defaults(usb_ac_state_t * statep)4682 usb_ac_ctrl_set_defaults(usb_ac_state_t *statep)
4683 {
4684 usb_audio_ctrl_t *ctrlp;
4685 int rv = USB_SUCCESS;
4686 USB_DPRINTF_L4(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
4687 "usb_ac_ctrl_set_defaults:begin");
4688
4689 for (int i = 0; i < CTL_NUM; i++) {
4690 ctrlp = statep->controls[i];
4691 if (!ctrlp) {
4692 continue;
4693 }
4694 if (audio_control_write(ctrlp->af_ctrlp, ctrlp->cval)) {
4695 USB_DPRINTF_L2(PRINT_MASK_ATTA,
4696 statep->usb_ac_log_handle,
4697 "usb_ac_ctrl_set_defaults:control write failed");
4698 rv = USB_FAILURE;
4699 }
4700
4701 }
4702 USB_DPRINTF_L4(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
4703 "usb_ac_ctrl_set_defaults:end");
4704 return (rv);
4705 }
4706
4707
4708 static int
usb_ac_ctrl_restore(usb_ac_state_t * statep)4709 usb_ac_ctrl_restore(usb_ac_state_t *statep)
4710 {
4711 usb_audio_ctrl_t *ctrlp;
4712 int rv = USB_SUCCESS;
4713
4714 for (int i = 0; i < CTL_NUM; i++) {
4715 ctrlp = statep->controls[i];
4716 if (ctrlp) {
4717 USB_DPRINTF_L3(PRINT_MASK_ATTA,
4718 statep->usb_ac_log_handle,
4719 "usb_ac_ctrl_restore:i = %d", i);
4720 if (audio_control_write(ctrlp->af_ctrlp, ctrlp->cval)) {
4721 rv = USB_FAILURE;
4722 }
4723 }
4724 }
4725 return (rv);
4726 }
4727
4728
4729
4730
4731 /*
4732 * moves data between driver buffer and framework/shim buffer
4733 */
4734 static void
usb_eng_bufio(usb_audio_eng_t * engp,void * buf,size_t sz)4735 usb_eng_bufio(usb_audio_eng_t *engp, void *buf, size_t sz)
4736 {
4737 size_t cpsz = sz;
4738 caddr_t *src, *dst;
4739
4740 if (engp->af_eflags & ENGINE_OUTPUT_CAP) {
4741 src = &engp->bufpos;
4742 dst = (caddr_t *)&buf;
4743 } else {
4744 src = (caddr_t *)&buf;
4745 dst = &engp->bufpos;
4746 }
4747
4748 /*
4749 * Wrap. If sz is exactly the remainder of the buffer
4750 * (bufpos + sz == bufendp) then the second cpsz should be 0 and so
4751 * the second memcpy() should have no effect, with bufpos updated
4752 * to the head of the buffer.
4753 */
4754 if (engp->bufpos + sz >= engp->bufendp) {
4755 cpsz = (size_t)engp->bufendp - (size_t)engp->bufpos;
4756 (void) memcpy(*dst, *src, cpsz);
4757
4758
4759 buf = (caddr_t)buf + cpsz;
4760 engp->bufpos = engp->bufp;
4761 cpsz = sz - cpsz;
4762 }
4763
4764 if (cpsz) {
4765 (void) memcpy(*dst, *src, cpsz);
4766
4767
4768 engp->bufpos += cpsz;
4769 }
4770 engp->bufio_count++;
4771 }
4772
4773
4774 /*
4775 * control read callback
4776 */
4777 static int
usb_audio_ctrl_read(void * arg,uint64_t * cvalp)4778 usb_audio_ctrl_read(void *arg, uint64_t *cvalp)
4779 {
4780 usb_audio_ctrl_t *ctrlp = arg;
4781
4782 mutex_enter(&ctrlp->ctrl_mutex);
4783 *cvalp = ctrlp->cval;
4784 mutex_exit(&ctrlp->ctrl_mutex);
4785
4786 return (0);
4787 }
4788
4789
4790 /*
4791 * stereo level control callback
4792 */
4793 static int
usb_audio_write_stero_rec(void * arg,uint64_t cval)4794 usb_audio_write_stero_rec(void *arg, uint64_t cval)
4795 {
4796 usb_audio_ctrl_t *ctrlp = arg;
4797 usb_ac_state_t *statep = ctrlp->statep;
4798 int rv = EIO;
4799 int left, right;
4800 uint_t count = 0;
4801
4802
4803 left = AUDIO_CTRL_STEREO_LEFT(cval);
4804 right = AUDIO_CTRL_STEREO_RIGHT(cval);
4805
4806 if (left < AF_MIN_GAIN || left > AF_MAX_GAIN ||
4807 right < AF_MIN_GAIN || right > AF_MAX_GAIN) {
4808
4809 return (EINVAL);
4810 }
4811
4812 mutex_enter(&ctrlp->ctrl_mutex);
4813 ctrlp->cval = cval;
4814 mutex_exit(&ctrlp->ctrl_mutex);
4815
4816 mutex_enter(&statep->usb_ac_mutex);
4817 (void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4818 USB_AUDIO_FEATURE_UNIT, 1,
4819 USB_AUDIO_VOLUME_CONTROL,
4820 USB_AC_FIND_ALL, &count, left, usb_ac_set_gain);
4821
4822 (void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4823 USB_AUDIO_FEATURE_UNIT, 2,
4824 USB_AUDIO_VOLUME_CONTROL,
4825 USB_AC_FIND_ALL, &count, right, usb_ac_set_gain);
4826 rv = 0;
4827
4828 done:
4829 mutex_exit(&statep->usb_ac_mutex);
4830 return (rv);
4831 }
4832
4833 static int
usb_audio_write_ster_vol(void * arg,uint64_t cval)4834 usb_audio_write_ster_vol(void *arg, uint64_t cval)
4835 {
4836 usb_audio_ctrl_t *ctrlp = arg;
4837 usb_ac_state_t *statep = ctrlp->statep;
4838 int rv = EIO;
4839 int left, right;
4840 uint_t count = 0;
4841
4842 left = AUDIO_CTRL_STEREO_LEFT(cval);
4843 right = AUDIO_CTRL_STEREO_RIGHT(cval);
4844
4845 if (left < AF_MIN_GAIN || left > AF_MAX_GAIN ||
4846 right < AF_MIN_GAIN || right > AF_MAX_GAIN) {
4847 return (EINVAL);
4848 }
4849
4850 mutex_enter(&ctrlp->ctrl_mutex);
4851 ctrlp->cval = cval;
4852 mutex_exit(&ctrlp->ctrl_mutex);
4853
4854
4855 mutex_enter(&statep->usb_ac_mutex);
4856 (void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4857 USB_AUDIO_FEATURE_UNIT, 1,
4858 USB_AUDIO_VOLUME_CONTROL,
4859 USB_AC_FIND_ALL, &count, left, usb_ac_set_gain);
4860
4861 (void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4862 USB_AUDIO_FEATURE_UNIT, 2,
4863 USB_AUDIO_VOLUME_CONTROL,
4864 USB_AC_FIND_ALL, &count, right, usb_ac_set_gain);
4865 rv = 0;
4866
4867 OUT:
4868 mutex_exit(&statep->usb_ac_mutex);
4869 return (rv);
4870 }
4871
4872
4873 /*
4874 * mono level control callback
4875 */
4876 static int
usb_audio_write_mono_vol(void * arg,uint64_t cval)4877 usb_audio_write_mono_vol(void *arg, uint64_t cval)
4878 {
4879 usb_audio_ctrl_t *ctrlp = arg;
4880 usb_ac_state_t *statep = ctrlp->statep;
4881 int rv = EIO;
4882 int gain;
4883
4884 uint_t count = 0;
4885
4886 if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4887 return (EINVAL);
4888 }
4889
4890 mutex_enter(&ctrlp->ctrl_mutex);
4891 ctrlp->cval = cval;
4892 mutex_exit(&ctrlp->ctrl_mutex);
4893
4894 gain = (int)(cval);
4895
4896 mutex_enter(&statep->usb_ac_mutex);
4897 (void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
4898 USB_AUDIO_FEATURE_UNIT, 1,
4899 USB_AUDIO_VOLUME_CONTROL,
4900 USB_AC_FIND_ALL, &count, gain, usb_ac_set_gain);
4901
4902 rv = 0;
4903 OUT:
4904 mutex_exit(&statep->usb_ac_mutex);
4905
4906 return (rv);
4907 }
4908
4909
4910 /*
4911 * mono level control callback
4912 */
4913 static int
usb_audio_write_monitor_gain(void * arg,uint64_t cval)4914 usb_audio_write_monitor_gain(void *arg, uint64_t cval)
4915 {
4916 usb_audio_ctrl_t *ctrlp = arg;
4917 usb_ac_state_t *statep = ctrlp->statep;
4918 int rv = EIO;
4919 int gain;
4920 uint_t count = 0;
4921
4922 if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4923
4924 return (EINVAL);
4925 }
4926
4927 mutex_enter(&ctrlp->ctrl_mutex);
4928 ctrlp->cval = cval;
4929 mutex_exit(&ctrlp->ctrl_mutex);
4930
4931 gain = (int)(cval);
4932
4933 mutex_enter(&statep->usb_ac_mutex);
4934 (void) usb_ac_set_monitor_gain_control(statep, USB_AUDIO_RECORD,
4935 USB_AUDIO_INPUT_TERMINAL, 1,
4936 USB_AUDIO_VOLUME_CONTROL,
4937 USB_AC_FIND_ALL, &count, gain,
4938 usb_ac_set_monitor_gain);
4939
4940 rv = 0;
4941 OUT:
4942 mutex_exit(&statep->usb_ac_mutex);
4943 return (rv);
4944 }
4945
4946 static int
usb_audio_write_mono_rec(void * arg,uint64_t cval)4947 usb_audio_write_mono_rec(void *arg, uint64_t cval)
4948 {
4949 usb_audio_ctrl_t *ctrlp = arg;
4950 usb_ac_state_t *statep = ctrlp->statep;
4951 int rv = EIO;
4952 int gain;
4953
4954 uint_t count = 0;
4955
4956 if (cval < (uint64_t)AF_MIN_GAIN || cval > (uint64_t)AF_MAX_GAIN) {
4957
4958 return (EINVAL);
4959 }
4960
4961 mutex_enter(&ctrlp->ctrl_mutex);
4962 ctrlp->cval = cval;
4963 mutex_exit(&ctrlp->ctrl_mutex);
4964
4965 gain = (int)(cval);
4966
4967 mutex_enter(&statep->usb_ac_mutex);
4968 (void) usb_ac_set_control(statep, USB_AUDIO_RECORD,
4969 USB_AUDIO_FEATURE_UNIT, 1,
4970 USB_AUDIO_VOLUME_CONTROL,
4971 USB_AC_FIND_ALL, &count, gain, usb_ac_set_gain);
4972
4973 rv = 0;
4974
4975 mutex_exit(&statep->usb_ac_mutex);
4976 return (rv);
4977 }
4978
4979 static int
usb_audio_write_mic_boost(void * arg,uint64_t cval)4980 usb_audio_write_mic_boost(void *arg, uint64_t cval)
4981 {
4982 usb_audio_ctrl_t *ctrlp = arg;
4983
4984 mutex_enter(&ctrlp->ctrl_mutex);
4985 ctrlp->cval = cval;
4986 mutex_exit(&ctrlp->ctrl_mutex);
4987 /* do nothing here */
4988 return (0);
4989 }
4990
4991 static int
usb_audio_write_rec_src(void * arg,uint64_t cval)4992 usb_audio_write_rec_src(void *arg, uint64_t cval)
4993 {
4994 usb_audio_ctrl_t *ctrlp = arg;
4995 usb_ac_state_t *statep = ctrlp->statep;
4996 int rv = 0;
4997
4998 if (cval & ~(statep->usb_ac_input_ports))
4999 return (EINVAL);
5000
5001 mutex_enter(&ctrlp->ctrl_mutex);
5002 ctrlp->cval = cval;
5003 mutex_exit(&ctrlp->ctrl_mutex);
5004
5005 mutex_enter(&statep->usb_ac_mutex);
5006 if (usb_ac_set_port(statep, USB_AUDIO_RECORD, cval) != USB_SUCCESS) {
5007
5008 USB_DPRINTF_L2(PRINT_MASK_ALL, statep->usb_ac_log_handle,
5009 "usb_audio_write_rec_src: failed");
5010 rv = EINVAL;
5011 }
5012 mutex_exit(&statep->usb_ac_mutex);
5013 rv = 0;
5014
5015 OUT:
5016 return (rv);
5017
5018 }
5019
5020
5021 int
usb_audio_set_mute(usb_ac_state_t * statep,uint64_t cval)5022 usb_audio_set_mute(usb_ac_state_t *statep, uint64_t cval)
5023 {
5024 short muteval;
5025 int rval;
5026
5027 uint_t count;
5028 muteval = (cval == 0) ? USB_AUDIO_MUTE_ON : USB_AUDIO_MUTE_OFF;
5029 count = 0;
5030 /* only support AUDIO_PLAY */
5031
5032 mutex_enter(&statep->usb_ac_mutex);
5033 (void) usb_ac_set_control(statep, USB_AUDIO_PLAY,
5034 USB_AUDIO_FEATURE_UNIT, 0,
5035 USB_AUDIO_MUTE_CONTROL,
5036 USB_AC_FIND_ALL, &count, muteval,
5037 usb_ac_set_mute);
5038 mutex_exit(&statep->usb_ac_mutex);
5039
5040 rval = (count == 0) ? USB_SUCCESS : USB_FAILURE;
5041
5042 return (rval);
5043 }
5044
5045
5046 /*
5047 * port selection control callback
5048 */
5049 /*
5050 * audio control registration related routines
5051 */
5052
5053 static usb_audio_ctrl_t *
usb_audio_ctrl_alloc(usb_ac_state_t * statep,uint32_t num,uint64_t val)5054 usb_audio_ctrl_alloc(usb_ac_state_t *statep, uint32_t num, uint64_t val)
5055 {
5056 audio_ctrl_desc_t desc;
5057 audio_ctrl_wr_t fn;
5058 usb_audio_ctrl_t *pc;
5059
5060 pc = kmem_zalloc(sizeof (usb_audio_ctrl_t), KM_SLEEP);
5061
5062 mutex_init(&pc->ctrl_mutex, NULL, MUTEX_DRIVER, NULL);
5063
5064 bzero(&desc, sizeof (desc));
5065
5066 switch (num) {
5067 case CTL_VOLUME_MONO:
5068 desc.acd_name = AUDIO_CTRL_ID_VOLUME;
5069 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5070 desc.acd_minvalue = 0;
5071 desc.acd_maxvalue = AF_MAX_GAIN;
5072 desc.acd_flags = AUDIO_CTRL_FLAG_MAINVOL | AUDIO_CTRL_FLAG_RW
5073 | AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL;
5074 fn = usb_audio_write_mono_vol;
5075 break;
5076
5077 case CTL_VOLUME_STERO:
5078 desc.acd_name = AUDIO_CTRL_ID_VOLUME;
5079 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
5080 desc.acd_minvalue = 0;
5081 desc.acd_maxvalue = AF_MAX_GAIN;
5082 desc.acd_flags = AUDIO_CTRL_FLAG_MAINVOL | AUDIO_CTRL_FLAG_RW
5083 | AUDIO_CTRL_FLAG_PLAY | AUDIO_CTRL_FLAG_POLL;
5084 fn = usb_audio_write_ster_vol;
5085
5086 break;
5087
5088 case CTL_REC_MONO:
5089 desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
5090 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5091 desc.acd_minvalue = 0;
5092 desc.acd_maxvalue = AF_MAX_GAIN;
5093 desc.acd_flags = AUDIO_CTRL_FLAG_RECVOL|AUDIO_CTRL_FLAG_REC
5094 | AUDIO_CTRL_FLAG_RW;
5095 fn = usb_audio_write_mono_rec;
5096 break;
5097 case CTL_REC_STERO:
5098
5099 desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
5100 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
5101 desc.acd_minvalue = 0;
5102 desc.acd_maxvalue = AF_MAX_GAIN;
5103 desc.acd_flags = AUDIO_CTRL_FLAG_RECVOL|AUDIO_CTRL_FLAG_REC
5104 | AUDIO_CTRL_FLAG_RW;
5105 fn = usb_audio_write_stero_rec;
5106 break;
5107
5108 case CTL_MONITOR_GAIN:
5109
5110 desc.acd_name = AUDIO_CTRL_ID_MONGAIN;
5111 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
5112 desc.acd_minvalue = 0;
5113 desc.acd_maxvalue = AF_MAX_GAIN;
5114 desc.acd_flags = AUDIO_CTRL_FLAG_MONVOL |AUDIO_CTRL_FLAG_MONITOR
5115 |AUDIO_CTRL_FLAG_RW;
5116 fn = usb_audio_write_monitor_gain;
5117 break;
5118
5119 case CTL_MIC_BOOST:
5120
5121 desc.acd_name = AUDIO_CTRL_ID_MICBOOST;
5122 desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
5123 desc.acd_minvalue = 0;
5124 desc.acd_maxvalue = 1;
5125 desc.acd_flags = AUDIO_CTRL_FLAG_RW;
5126 fn = usb_audio_write_mic_boost;
5127 break;
5128 case CTL_REC_SRC:
5129
5130 desc.acd_name = AUDIO_CTRL_ID_RECSRC;
5131 desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
5132 desc.acd_minvalue = statep->usb_ac_input_ports;
5133 desc.acd_maxvalue = statep->usb_ac_input_ports;
5134 desc.acd_flags = AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC;
5135 for (int i = 0; usb_audio_dtypes[i]; i++) {
5136 desc.acd_enum[i] = usb_audio_dtypes[i];
5137 }
5138
5139 fn = usb_audio_write_rec_src;
5140 break;
5141
5142
5143
5144 default:
5145
5146 break;
5147 }
5148
5149 mutex_enter(&pc->ctrl_mutex);
5150
5151 pc->statep = statep;
5152 pc->cval = val;
5153 pc->af_ctrlp = audio_dev_add_control(statep->usb_ac_audio_dev, &desc,
5154 usb_audio_ctrl_read, fn, pc);
5155
5156 mutex_exit(&pc->ctrl_mutex);
5157
5158 mutex_enter(&statep->usb_ac_mutex);
5159 statep->controls[num] = pc;
5160 mutex_exit(&statep->usb_ac_mutex);
5161
5162
5163 return (pc);
5164 }
5165
5166
5167 static void
usb_audio_ctrl_free(usb_audio_ctrl_t * ctrlp)5168 usb_audio_ctrl_free(usb_audio_ctrl_t *ctrlp)
5169 {
5170 kmem_free(ctrlp, sizeof (usb_audio_ctrl_t));
5171 }
5172
5173 static void
usb_ac_rem_controls(usb_ac_state_t * statep)5174 usb_ac_rem_controls(usb_ac_state_t *statep)
5175 {
5176 usb_audio_ctrl_t *ctrlp;
5177
5178 for (int i = 0; i < CTL_NUM; i++) {
5179 ctrlp = statep->controls[i];
5180 if (ctrlp) {
5181 if (ctrlp->af_ctrlp != NULL)
5182 audio_dev_del_control(ctrlp->af_ctrlp);
5183
5184 usb_audio_ctrl_free(ctrlp);
5185 mutex_enter(&statep->usb_ac_mutex);
5186 statep->controls[i] = NULL;
5187 mutex_exit(&statep->usb_ac_mutex);
5188 }
5189 }
5190
5191 }
5192
5193
5194 static int
usb_ac_add_controls(usb_ac_state_t * statep)5195 usb_ac_add_controls(usb_ac_state_t *statep)
5196 {
5197 int rv = USB_FAILURE;
5198 usb_audio_format_t *format;
5199
5200
5201 if (statep->engines[0].af_engp) {
5202 /* Init controls for play format */
5203 format = &(statep->engines[0].fmt);
5204 if (format->ch == 2) {
5205 (void) usb_audio_ctrl_alloc(statep, CTL_VOLUME_STERO,
5206 statep->engines[0].af_defgain);
5207 } else {
5208 (void) usb_audio_ctrl_alloc(statep, CTL_VOLUME_MONO,
5209 statep->engines[0].af_defgain);
5210 }
5211
5212 }
5213
5214 /* Init controls for rec format */
5215 if (statep->engines[1].af_engp) {
5216 format = &(statep->engines[1].fmt);
5217 if (format->ch == 2) {
5218 (void) usb_audio_ctrl_alloc(statep, CTL_REC_STERO,
5219 statep->engines[1].af_defgain);
5220 } else {
5221 (void) usb_audio_ctrl_alloc(statep, CTL_REC_MONO,
5222 statep->engines[1].af_defgain);
5223 }
5224
5225 /* Add monitor control */
5226 {
5227 (void) usb_audio_ctrl_alloc(statep,
5228 CTL_MONITOR_GAIN, 0);
5229 }
5230
5231 /* Add ports control */
5232 {
5233 (void) usb_audio_ctrl_alloc(statep, CTL_REC_SRC,
5234 statep->usb_ac_input_ports);
5235 }
5236
5237 }
5238
5239
5240 rv = USB_SUCCESS;
5241
5242 OUT:
5243 if (rv != USB_SUCCESS)
5244 usb_ac_rem_controls(statep);
5245 return (rv);
5246 }
5247
5248
5249
5250
5251
5252 /*ARGSUSED*/
5253 static int
usb_audio_unregister(usb_ac_state_t * statep)5254 usb_audio_unregister(usb_ac_state_t *statep)
5255 {
5256 int i;
5257
5258 if (statep == NULL)
5259 return (USB_SUCCESS);
5260
5261 if (statep->usb_ac_audio_dev == NULL)
5262 return (USB_SUCCESS);
5263
5264 if ((statep->flags & AF_REGISTERED) &&
5265 audio_dev_unregister(statep->usb_ac_audio_dev) != DDI_SUCCESS) {
5266 return (USB_FAILURE);
5267 }
5268 mutex_enter(&statep->usb_ac_mutex);
5269 statep->flags &= ~AF_REGISTERED;
5270 mutex_exit(&statep->usb_ac_mutex);
5271
5272 for (i = 0; i < USB_AC_ENG_MAX; i++)
5273 usb_ac_rem_eng(statep, &statep->engines[i]);
5274
5275 usb_ac_rem_controls(statep);
5276
5277 audio_dev_free(statep->usb_ac_audio_dev);
5278
5279 mutex_enter(&statep->usb_ac_mutex);
5280 statep->usb_ac_audio_dev = NULL;
5281 mutex_exit(&statep->usb_ac_mutex);
5282
5283 return (USB_SUCCESS);
5284 }
5285
5286
5287 static int
usb_audio_register(usb_ac_state_t * statep)5288 usb_audio_register(usb_ac_state_t *statep)
5289 {
5290 audio_dev_t *af_devp;
5291 int rv = USB_FAILURE;
5292 int n;
5293
5294 af_devp = audio_dev_alloc(statep->usb_ac_dip, 0);
5295 audio_dev_set_description(af_devp, "USB Audio");
5296 audio_dev_set_version(af_devp, "1.0");
5297
5298 mutex_enter(&statep->usb_ac_mutex);
5299 statep->usb_ac_audio_dev = af_devp;
5300 mutex_exit(&statep->usb_ac_mutex);
5301
5302
5303 for (n = 0; n < USB_AC_MAX_AS_PLUMBED; n++) {
5304 if (usb_ac_add_eng(statep, &(statep->usb_ac_streams[n]))
5305 != USB_SUCCESS) {
5306 USB_DPRINTF_L2(PRINT_MASK_ATTA,
5307 statep->usb_ac_log_handle,
5308 "usb_audio_register: add engine n =%d failed", n);
5309 goto OUT;
5310 }
5311 }
5312
5313
5314 if (usb_ac_add_controls(statep) != USB_SUCCESS) {
5315 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5316 "usb_audio_register: add controls failed");
5317 goto OUT;
5318 }
5319
5320 if (usb_ac_ctrl_set_defaults(statep) != USB_SUCCESS) {
5321 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5322 "usb_audio_register: set defaults failed");
5323 goto OUT;
5324 }
5325
5326 if (audio_dev_register(af_devp) != DDI_SUCCESS) {
5327 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5328 "audio_dev_register() failed");
5329 goto OUT;
5330 }
5331 mutex_enter(&statep->usb_ac_mutex);
5332 statep->flags |= AF_REGISTERED;
5333 mutex_exit(&statep->usb_ac_mutex);
5334
5335 rv = USB_SUCCESS;
5336
5337 OUT:
5338 if (rv != USB_SUCCESS) {
5339 (void) usb_audio_unregister(statep);
5340 }
5341 return (rv);
5342 }
5343
5344
5345 int
usb_ac_get_audio(void * handle,void * buf,int samples)5346 usb_ac_get_audio(void *handle, void *buf, int samples)
5347 {
5348 usb_ac_state_t *statep = (usb_ac_state_t *)(handle);
5349 usb_audio_eng_t *engp = &(statep->engines[0]);
5350 unsigned reqframes = samples >> engp->frsmshift;
5351 unsigned frames;
5352 unsigned i;
5353 size_t sz;
5354 caddr_t bp = buf;
5355
5356 mutex_enter(&engp->lock);
5357 if (!engp->started) {
5358 mutex_exit(&engp->lock);
5359
5360 return (0);
5361 }
5362 engp->busy = B_TRUE;
5363 mutex_exit(&engp->lock);
5364
5365 /* break requests from the driver into fragment sized chunks */
5366 for (i = 0; i < reqframes; i += frames) {
5367
5368 mutex_enter(&engp->lock);
5369 frames = reqframes - i;
5370 if (frames > engp->fragfr)
5371 frames = engp->fragfr;
5372
5373 sz = (frames << engp->frsmshift) << engp->smszshift;
5374
5375 /* must move data before updating framework */
5376 usb_eng_bufio(engp, bp, sz);
5377 engp->frames += frames;
5378 bp += sz;
5379
5380 mutex_exit(&engp->lock);
5381 }
5382
5383 mutex_enter(&engp->lock);
5384 engp->io_count++;
5385 engp->busy = B_FALSE;
5386 cv_signal(&engp->usb_audio_cv);
5387 mutex_exit(&engp->lock);
5388
5389 return (samples);
5390 }
5391
5392
5393
5394 void
usb_ac_send_audio(void * handle,void * buf,int samples)5395 usb_ac_send_audio(void *handle, void *buf, int samples)
5396 {
5397 usb_ac_state_t *statep = (usb_ac_state_t *)(handle);
5398 usb_audio_eng_t *engp = &(statep->engines[1]);
5399 unsigned reqframes = samples >> engp->frsmshift;
5400 unsigned frames;
5401 unsigned i;
5402 size_t sz;
5403 caddr_t bp = buf;
5404
5405 mutex_enter(&engp->lock);
5406
5407 if (!engp->started) {
5408
5409 mutex_exit(&engp->lock);
5410 return;
5411 }
5412 engp->busy = B_TRUE;
5413 mutex_exit(&engp->lock);
5414
5415 /* break requests from the driver into fragment sized chunks */
5416 for (i = 0; i < reqframes; i += frames) {
5417 mutex_enter(&engp->lock);
5418
5419 frames = reqframes - i;
5420 if (frames > engp->fragfr)
5421 frames = engp->fragfr;
5422
5423 sz = (frames << engp->frsmshift) << engp->smszshift;
5424
5425 /* must move data before updating framework */
5426 usb_eng_bufio(engp, bp, sz);
5427 engp->frames += frames;
5428 bp += sz;
5429
5430 mutex_exit(&engp->lock);
5431 }
5432
5433 mutex_enter(&engp->lock);
5434 engp->io_count++;
5435 engp->busy = B_FALSE;
5436 cv_signal(&engp->usb_audio_cv);
5437 mutex_exit(&engp->lock);
5438 }
5439
5440
5441 /*
5442 * **************************************************************************
5443 * audio framework engine callbacks
5444 */
5445 static int
usb_engine_open(void * arg,int flag,unsigned * nframesp,caddr_t * bufp)5446 usb_engine_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
5447 {
5448 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5449 usb_ac_state_t *statep = engp->statep;
5450 int rv = EIO;
5451
5452 _NOTE(ARGUNUSED(flag));
5453
5454 if (usb_ac_open(statep->usb_ac_dip) != USB_SUCCESS) {
5455
5456 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5457 "usb_ac_open() failed");
5458 return (EIO);
5459 }
5460
5461 mutex_enter(&engp->lock);
5462
5463 engp->intrate = 150;
5464 engp->sampsz = engp->fmt.prec / 8;
5465 engp->framesz = engp->sampsz * engp->fmt.ch;
5466
5467 engp->frsmshift = engp->fmt.ch / 2;
5468 engp->smszshift = engp->sampsz / 2;
5469
5470 /*
5471 * In order to match the requested number of samples per interrupt
5472 * from SADA drivers when computing the fragment size,
5473 * we need to first truncate the floating point result from
5474 * sample rate * channels / intr rate
5475 * then adjust up to an even number, before multiplying it
5476 * with the sample size
5477 */
5478 engp->fragsz = engp->fmt.sr * engp->fmt.ch / engp->intrate;
5479 if (engp->fragsz & 1)
5480 engp->fragsz++;
5481 engp->fragsz *= engp->sampsz;
5482 engp->fragfr = engp->fragsz / engp->framesz;
5483
5484 engp->nfrags = 10;
5485 engp->bufsz = engp->fragsz * engp->nfrags;
5486
5487 engp->bufp = kmem_zalloc(engp->bufsz, KM_SLEEP);
5488 engp->bufpos = engp->bufp;
5489 engp->bufendp = engp->bufp + engp->bufsz;
5490 engp->frames = 0;
5491 engp->io_count = 0;
5492 engp->bufio_count = 0;
5493 engp->started = B_FALSE;
5494 engp->busy = B_FALSE;
5495
5496 *nframesp = engp->nfrags * engp->fragfr;
5497 *bufp = engp->bufp;
5498
5499 mutex_exit(&engp->lock);
5500
5501 if (usb_ac_setup(statep, engp) != USB_SUCCESS) {
5502 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5503 "device setup failed");
5504 goto OUT;
5505 }
5506
5507
5508
5509 mutex_enter(&statep->usb_ac_mutex);
5510 statep->flags |= AD_SETUP;
5511 mutex_exit(&statep->usb_ac_mutex);
5512
5513 rv = 0;
5514
5515
5516 OUT:
5517 if (rv != 0)
5518 usb_engine_close(arg);
5519
5520 return (rv);
5521 }
5522
5523
5524 static void
usb_engine_close(void * arg)5525 usb_engine_close(void *arg)
5526 {
5527 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5528 usb_ac_state_t *statep = engp->statep;
5529
5530 mutex_enter(&engp->lock);
5531 while (engp->busy) {
5532 cv_wait(&engp->usb_audio_cv, &engp->lock);
5533 }
5534
5535 mutex_exit(&engp->lock);
5536
5537 if (statep->flags & AD_SETUP) {
5538 usb_ac_teardown(statep, engp);
5539 mutex_enter(&statep->usb_ac_mutex);
5540 statep->flags &= ~AD_SETUP;
5541 mutex_exit(&statep->usb_ac_mutex);
5542 }
5543 mutex_enter(&engp->lock);
5544
5545 if (engp->bufp != NULL) {
5546 kmem_free(engp->bufp, engp->bufsz);
5547 engp->bufp = NULL;
5548 engp->bufpos = NULL;
5549 engp->bufendp = NULL;
5550 }
5551
5552 mutex_exit(&engp->lock);
5553
5554 usb_ac_close(statep->usb_ac_dip);
5555 }
5556
5557
5558
5559 static int
usb_engine_start(void * arg)5560 usb_engine_start(void *arg)
5561 {
5562 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5563 int rv = 0;
5564 int (*start)(usb_ac_state_t *, usb_audio_eng_t *);
5565
5566 mutex_enter(&engp->lock);
5567 engp->started = B_TRUE;
5568 mutex_exit(&engp->lock);
5569
5570 usb_ac_state_t *statep = engp->statep;
5571
5572 start = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ?
5573 usb_ac_start_play : usb_ac_start_record;
5574
5575 if ((*start)(statep, engp) != USB_SUCCESS) {
5576 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5577 "failed to start %d engine", engp->af_eflags);
5578 rv = EIO;
5579 }
5580
5581
5582 return (rv);
5583 }
5584
5585
5586 static void
usb_engine_stop(void * arg)5587 usb_engine_stop(void *arg)
5588 {
5589 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5590
5591 mutex_enter(&engp->lock);
5592 engp->started = B_FALSE;
5593 mutex_exit(&engp->lock);
5594
5595 usb_ac_state_t *statep = engp->statep;
5596 void (*stop)(usb_ac_state_t *, usb_audio_eng_t *);
5597
5598 stop = ((engp)->af_eflags & ENGINE_OUTPUT_CAP) ?
5599 usb_ac_stop_play : usb_ac_stop_record;
5600
5601 (*stop)(statep, engp);
5602 }
5603
5604
5605 static uint64_t
usb_engine_count(void * arg)5606 usb_engine_count(void *arg)
5607 {
5608 usb_audio_eng_t *engp = arg;
5609 uint64_t val;
5610
5611 mutex_enter(&engp->lock);
5612 val = engp->frames;
5613 mutex_exit(&engp->lock);
5614
5615 return (val);
5616 }
5617
5618
5619 static int
usb_engine_format(void * arg)5620 usb_engine_format(void *arg)
5621 {
5622 usb_audio_eng_t *engp = arg;
5623
5624 switch (engp->fmt.enc) {
5625 case USB_AUDIO_FORMAT_TYPE1_MULAW:
5626 return (AUDIO_FORMAT_ULAW);
5627 case USB_AUDIO_FORMAT_TYPE1_ALAW:
5628 return (AUDIO_FORMAT_ALAW);
5629 case USB_AUDIO_FORMAT_TYPE1_PCM8:
5630 return (AUDIO_FORMAT_U8);
5631
5632 case USB_AUDIO_FORMAT_TYPE1_PCM:
5633 break;
5634 default:
5635 return (AUDIO_FORMAT_NONE);
5636 }
5637
5638 switch (engp->fmt.prec) {
5639 case USB_AUDIO_PRECISION_8:
5640 return (AUDIO_FORMAT_S8);
5641 case USB_AUDIO_PRECISION_16:
5642 return (AUDIO_FORMAT_S16_LE);
5643 case USB_AUDIO_PRECISION_24:
5644 return (AUDIO_FORMAT_S24_LE);
5645 case USB_AUDIO_PRECISION_32:
5646 return (AUDIO_FORMAT_S32_LE);
5647 default:
5648 break;
5649 }
5650 return (AUDIO_FORMAT_NONE);
5651
5652
5653 }
5654
5655 static int
usb_engine_channels(void * arg)5656 usb_engine_channels(void *arg)
5657 {
5658 usb_audio_eng_t *engp = arg;
5659
5660 return (engp->fmt.ch);
5661 }
5662
5663
5664 static int
usb_engine_rate(void * arg)5665 usb_engine_rate(void *arg)
5666 {
5667 usb_audio_eng_t *engp = arg;
5668
5669 return (engp->fmt.sr);
5670 }
5671
5672
5673 /*ARGSUSED*/
5674 static void
usb_engine_sync(void * arg,unsigned nframes)5675 usb_engine_sync(void *arg, unsigned nframes)
5676 {
5677 /* Do nothing */
5678 }
5679
5680
5681 static unsigned
usb_engine_qlen(void * arg)5682 usb_engine_qlen(void *arg)
5683 {
5684 usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
5685
5686 return (engp->fragfr);
5687 }
5688
5689 /*
5690 * **************************************************************************
5691 * interfaces used by USB audio
5692 */
5693
5694 /*ARGSUSED*/
5695 static int
usb_change_phy_vol(usb_ac_state_t * statep,int value)5696 usb_change_phy_vol(usb_ac_state_t *statep, int value)
5697 {
5698 usb_audio_ctrl_t *ctrlp;
5699 uint64_t cval = 0;
5700 int64_t left, right, delta = 0;
5701
5702 ctrlp = statep->controls[CTL_VOLUME_STERO];
5703
5704 ASSERT(value != 0);
5705
5706 delta = (value < 0)?-1:1;
5707
5708 left = AUDIO_CTRL_STEREO_LEFT(ctrlp->cval) + delta;
5709 right = AUDIO_CTRL_STEREO_RIGHT(ctrlp->cval) + delta;
5710
5711 if (left > AF_MAX_GAIN)
5712 left = AF_MAX_GAIN;
5713 if (right > AF_MAX_GAIN)
5714 right = AF_MAX_GAIN;
5715
5716 if (left < AF_MIN_GAIN)
5717 left = AF_MIN_GAIN;
5718 if (right < AF_MIN_GAIN)
5719 right = AF_MIN_GAIN;
5720
5721 cval = AUDIO_CTRL_STEREO_VAL(left, right);
5722
5723 if (audio_control_write(ctrlp->af_ctrlp, cval)) {
5724 USB_DPRINTF_L2(PRINT_MASK_ATTA, statep->usb_ac_log_handle,
5725 "updateing control to value 0x%llx by driver failed",
5726 (long long unsigned)cval);
5727 return (USB_FAILURE);
5728 }
5729 return (USB_SUCCESS);
5730 }
5731