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