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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/types.h> 26 #include <sys/open.h> 27 #include <sys/errno.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/audio/audio_oss.h> 31 #include <sys/file.h> 32 #include <sys/note.h> 33 #include <sys/sysmacros.h> 34 #include <sys/list.h> 35 #include "audio_client.h" 36 37 #define OSS_FMT AFMT_S16_LE 38 #define OSS_RATE 48000 39 #define OSS_CHANNELS 2 40 41 typedef struct ossclient ossclient_t; 42 typedef struct ossdev ossdev_t; 43 44 static const struct { 45 int oss; 46 int fmt; 47 } oss_formats[] = { 48 { AFMT_MU_LAW, AUDIO_FORMAT_ULAW }, 49 { AFMT_A_LAW, AUDIO_FORMAT_ALAW }, 50 { AFMT_U8, AUDIO_FORMAT_U8 }, 51 { AFMT_S8, AUDIO_FORMAT_S8 }, 52 { AFMT_S16_BE, AUDIO_FORMAT_S16_BE }, 53 { AFMT_S16_LE, AUDIO_FORMAT_S16_LE }, 54 { AFMT_U16_BE, AUDIO_FORMAT_U16_BE }, 55 { AFMT_U16_LE, AUDIO_FORMAT_U16_LE }, 56 { AFMT_S24_BE, AUDIO_FORMAT_S24_BE }, 57 { AFMT_S24_LE, AUDIO_FORMAT_S24_LE }, 58 { AFMT_S32_BE, AUDIO_FORMAT_S32_BE }, 59 { AFMT_S32_LE, AUDIO_FORMAT_S32_LE }, 60 { AFMT_S24_PACKED, AUDIO_FORMAT_S24_PACKED }, 61 { AFMT_AC3, AUDIO_FORMAT_AC3 }, 62 { AFMT_QUERY, AUDIO_FORMAT_NONE } 63 }; 64 65 /* common structure shared between both mixer and dsp nodes */ 66 struct ossclient { 67 ossdev_t *o_ossdev; 68 audio_client_t *o_client; 69 /* sndstat */ 70 kmutex_t o_ss_lock; 71 char *o_ss_buf; 72 size_t o_ss_len; 73 size_t o_ss_sz; 74 size_t o_ss_off; 75 }; 76 77 struct ossdev { 78 audio_dev_t *d_dev; 79 80 uint_t d_nctrl; /* num actual controls */ 81 uint_t d_nalloc; /* num allocated controls */ 82 audio_ctrl_t **d_ctrls; /* array of control handles */ 83 oss_mixext *d_exts; /* array of mixer descs */ 84 85 int d_play_grp; 86 int d_rec_grp; 87 int d_mon_grp; 88 int d_misc_grp; 89 90 kmutex_t d_mx; 91 kcondvar_t d_cv; 92 }; 93 94 static int 95 oss_cnt_controls(audio_ctrl_t *ctrl, void *arg) 96 { 97 int *pint = (int *)arg; 98 int cnt; 99 audio_ctrl_desc_t desc; 100 101 cnt = *pint; 102 cnt++; 103 *pint = cnt; 104 105 if (auclnt_control_describe(ctrl, &desc) != 0) 106 return (AUDIO_WALK_CONTINUE); 107 108 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 109 for (uint64_t mask = desc.acd_maxvalue; mask; mask >>= 1) { 110 if (mask & 1) { 111 cnt++; 112 } 113 } 114 *pint = cnt; 115 } 116 117 return (AUDIO_WALK_CONTINUE); 118 } 119 120 /* 121 * Add one entry to the OSS user control table to internal control 122 * helper table. 123 * 124 * This is used with auimpl_walk_controls. The table must be pre- 125 * allocated before it is walk'd. This includes the root and 126 * extended control markers! 127 */ 128 static int 129 oss_add_control(audio_ctrl_t *ctrl, void *arg) 130 { 131 ossdev_t *odev = arg; 132 audio_ctrl_desc_t desc; 133 oss_mixext *ext; 134 int bit; 135 uint64_t mask; 136 const char *name; 137 int parent; 138 int flags; 139 unsigned scope; 140 141 if (auclnt_control_describe(ctrl, &desc)) 142 return (AUDIO_WALK_CONTINUE); 143 144 parent = 0; 145 146 /* 147 * Add appropriate group if not already done so. 148 */ 149 if (desc.acd_flags & AUDIO_CTRL_FLAG_PLAY) { 150 if (!odev->d_play_grp) { 151 ext = &odev->d_exts[odev->d_nctrl]; 152 ext->ctrl = odev->d_nctrl; 153 ext->control_no = -1; 154 ext->type = MIXT_GROUP; 155 ext->desc = MIXEXT_SCOPE_OUTPUT; 156 ext->timestamp = gethrtime(); 157 (void) snprintf(ext->id, sizeof (ext->id), "PLAYBACK"); 158 odev->d_play_grp = odev->d_nctrl; 159 odev->d_nctrl++; 160 } 161 scope = MIXEXT_SCOPE_OUTPUT; 162 parent = odev->d_play_grp; 163 } else if (desc.acd_flags & AUDIO_CTRL_FLAG_REC) { 164 if (!odev->d_rec_grp) { 165 ext = &odev->d_exts[odev->d_nctrl]; 166 ext->ctrl = odev->d_nctrl; 167 ext->control_no = -1; 168 ext->type = MIXT_GROUP; 169 ext->desc = MIXEXT_SCOPE_INPUT; 170 ext->timestamp = gethrtime(); 171 (void) snprintf(ext->id, sizeof (ext->id), "RECORD"); 172 odev->d_rec_grp = odev->d_nctrl; 173 odev->d_nctrl++; 174 } 175 scope = MIXEXT_SCOPE_INPUT; 176 parent = odev->d_rec_grp; 177 } else if (desc.acd_flags & AUDIO_CTRL_FLAG_MONITOR) { 178 if (!odev->d_mon_grp) { 179 ext = &odev->d_exts[odev->d_nctrl]; 180 ext->ctrl = odev->d_nctrl; 181 ext->control_no = -1; 182 ext->type = MIXT_GROUP; 183 ext->desc = MIXEXT_SCOPE_MONITOR; 184 ext->timestamp = gethrtime(); 185 (void) snprintf(ext->id, sizeof (ext->id), "MONITOR"); 186 odev->d_mon_grp = odev->d_nctrl; 187 odev->d_nctrl++; 188 } 189 scope = MIXEXT_SCOPE_MONITOR; 190 parent = odev->d_mon_grp; 191 } else { 192 if (!odev->d_misc_grp) { 193 ext = &odev->d_exts[odev->d_nctrl]; 194 ext->ctrl = odev->d_nctrl; 195 ext->control_no = -1; 196 ext->type = MIXT_GROUP; 197 ext->desc = MIXEXT_SCOPE_OTHER; 198 ext->timestamp = gethrtime(); 199 (void) snprintf(ext->id, sizeof (ext->id), "MISC"); 200 odev->d_misc_grp = odev->d_nctrl; 201 odev->d_nctrl++; 202 } 203 scope = MIXEXT_SCOPE_OTHER; 204 parent = odev->d_misc_grp; 205 } 206 207 name = desc.acd_name ? desc.acd_name : ""; 208 209 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 210 ext = &odev->d_exts[odev->d_nctrl]; 211 ext->ctrl = odev->d_nctrl; 212 ext->control_no = -1; 213 ext->type = MIXT_GROUP; 214 ext->timestamp = gethrtime(); 215 ext->parent = parent; 216 ext->desc = scope; 217 (void) snprintf(ext->id, sizeof (ext->id), "%s", name); 218 (void) snprintf(ext->extname, sizeof (ext->extname), 219 "%s", name); 220 parent = odev->d_nctrl++; 221 } 222 223 /* Next available open entry */ 224 ext = &odev->d_exts[odev->d_nctrl]; 225 226 /* Record the underlying control handle */ 227 odev->d_ctrls[odev->d_nctrl] = ctrl; 228 229 /* 230 * Now setup the oss entry 231 */ 232 233 ext->ctrl = odev->d_nctrl; 234 ext->control_no = -1; 235 ext->maxvalue = (int)desc.acd_maxvalue; 236 ext->minvalue = (int)desc.acd_minvalue; 237 ext->timestamp = gethrtime(); 238 ext->parent = parent; 239 ext->desc = scope; 240 /* all controls should be pollable for now */ 241 flags = MIXF_POLL; 242 243 /* 244 * The following flags are intended to help out applications 245 * which need to figure out where to place certain controls. 246 * A few further words of guidance: 247 * 248 * Apps that just want a single master volume control should 249 * adjust the control(s) that are labelled with MIXF_PCMVOL if 250 * present. They can fall back to adjusting all MAINVOL 251 * levels instead, if no PCMVOL is present. 252 * 253 * Controls that are one type on a certain device might be a 254 * different type on another device. For example, 255 * audiopci/ak4531 can adjust input gains for individual 256 * levels, but lacks a master record gain. AC'97, on the 257 * other hand, has individual monitor gains for inputs, but 258 * only a single master recording gain. 259 */ 260 if (desc.acd_flags & AUDIO_CTRL_FLAG_READABLE) 261 flags |= MIXF_READABLE; 262 if (desc.acd_flags & AUDIO_CTRL_FLAG_WRITEABLE) 263 flags |= MIXF_WRITEABLE; 264 if (desc.acd_flags & AUDIO_CTRL_FLAG_CENTIBEL) 265 flags |= MIXF_CENTIBEL; 266 if (desc.acd_flags & AUDIO_CTRL_FLAG_DECIBEL) 267 flags |= MIXF_DECIBEL; 268 if (desc.acd_flags & AUDIO_CTRL_FLAG_MAINVOL) 269 flags |= MIXF_MAINVOL; 270 if (desc.acd_flags & AUDIO_CTRL_FLAG_PCMVOL) 271 flags |= MIXF_PCMVOL; 272 if (desc.acd_flags & AUDIO_CTRL_FLAG_RECVOL) 273 flags |= MIXF_RECVOL; 274 if (desc.acd_flags & AUDIO_CTRL_FLAG_MONVOL) 275 flags |= MIXF_MONVOL; 276 ext->flags = flags; 277 278 (void) snprintf(ext->id, sizeof (ext->id), "%s", name); 279 280 /* 281 * For now just use the same extname as the real name. 282 */ 283 (void) snprintf(ext->extname, sizeof (ext->extname), name); 284 285 /* 286 * Now we deal with various control types. 287 */ 288 switch (desc.acd_type) { 289 case AUDIO_CTRL_TYPE_BOOLEAN: 290 ext->type = MIXT_ONOFF; 291 ext->enumbit = -1; 292 break; 293 case AUDIO_CTRL_TYPE_STEREO: 294 ext->type = MIXT_STEREOSLIDER; 295 break; 296 case AUDIO_CTRL_TYPE_MONO: 297 ext->type = MIXT_MONOSLIDER; 298 break; 299 case AUDIO_CTRL_TYPE_ENUM: 300 301 if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) { 302 /* 303 * We turn AUDIO_CTRL_FLAG_MULTI into a group 304 * of checkboxes, since OSS can't represent it 305 * natively. 306 */ 307 mask = desc.acd_maxvalue; 308 bit = 0; 309 while (mask) { 310 if (mask & 1) { 311 ext = &odev->d_exts[odev->d_nctrl]; 312 (void) snprintf(ext->extname, 313 sizeof (ext->extname), "%s.%s", 314 name, desc.acd_enum[bit]); 315 (void) snprintf(ext->id, 316 sizeof (ext->id), "%s", 317 desc.acd_enum[bit]); 318 ext->ctrl = odev->d_nctrl; 319 ext->control_no = -1; 320 ext->parent = parent; 321 ext->timestamp = gethrtime(); 322 ext->type = MIXT_ONOFF; 323 ext->minvalue = 0; 324 ext->maxvalue = 1; 325 ext->enumbit = bit; 326 ext->flags = flags; 327 odev->d_ctrls[odev->d_nctrl] = ctrl; 328 odev->d_nctrl++; 329 } 330 bit++; 331 mask >>= 1; 332 } 333 return (AUDIO_WALK_CONTINUE); 334 } else { 335 /* 336 * NB: This is sufficient only for controls 337 * with a single value. It cannot express the 338 * richer bitmask capabilities. 339 */ 340 ext->type = MIXT_ENUM; 341 ext->minvalue = 0; 342 343 /* 344 * For an enumaration, we need to figure out 345 * which values are present, and set the 346 * appropriate mask and max value. 347 */ 348 bzero(ext->enum_present, sizeof (ext->enum_present)); 349 mask = desc.acd_maxvalue; 350 bit = 0; 351 while (mask) { 352 if (mask & 1) { 353 ext->enum_present[bit / 8] |= 354 (1 << (bit % 8)); 355 } 356 mask >>= 1; 357 bit++; 358 } 359 ext->maxvalue = bit; 360 } 361 break; 362 363 case AUDIO_CTRL_TYPE_METER: 364 default: 365 /* Its an unknown or unsupported (for now) control, skip */ 366 return (AUDIO_WALK_CONTINUE); 367 } 368 369 odev->d_nctrl++; 370 371 return (AUDIO_WALK_CONTINUE); 372 } 373 374 /* 375 * Free up an OSS user land control to internal control, 376 * helper table. 377 */ 378 static void 379 oss_free_controls(ossdev_t *odev) 380 { 381 kmem_free(odev->d_ctrls, sizeof (audio_ctrl_t *) * odev->d_nalloc); 382 kmem_free(odev->d_exts, sizeof (oss_mixext) * odev->d_nalloc); 383 odev->d_nctrl = 0; 384 odev->d_nalloc = 0; 385 } 386 387 /* 388 * Allocate and fill in an OSS user land controls to internal controls 389 * helper table. This is done on one audio_dev device. 390 */ 391 static void 392 oss_alloc_controls(ossdev_t *odev) 393 { 394 audio_dev_t *d = odev->d_dev; 395 int nctrl = 0; 396 oss_mixext *ext; 397 oss_mixext_root *root_data; 398 399 /* Find out who many entries we need */ 400 auclnt_walk_controls(d, oss_cnt_controls, &nctrl); 401 nctrl++; /* Needs space for the device root node */ 402 nctrl++; /* Needs space for the device ext marker */ 403 nctrl++; /* Needs space for the play group */ 404 nctrl++; /* Needs space for the record group */ 405 nctrl++; /* Needs space for the monitor group */ 406 nctrl++; /* Needs space for the tone group */ 407 nctrl++; /* Needs space for the 3D group */ 408 nctrl++; /* Needs space for the misc group */ 409 410 /* Allocate the OSS to boomer helper table */ 411 odev->d_nalloc = nctrl; 412 odev->d_ctrls = kmem_zalloc(sizeof (audio_ctrl_t *) * nctrl, KM_SLEEP); 413 odev->d_exts = kmem_zalloc(sizeof (oss_mixext) * nctrl, KM_SLEEP); 414 415 /* 416 * Setup special case outputs to output OSS routes helper tables 417 */ 418 419 /* 420 * Root node is first, that way all others parent is this one 421 */ 422 ext = &odev->d_exts[odev->d_nctrl]; 423 ext->ctrl = 0; 424 ext->parent = -1; 425 ext->type = MIXT_DEVROOT; 426 ext->timestamp = gethrtime(); 427 (void) snprintf(ext->id, sizeof (ext->id), "DEVROOT"); 428 /* 429 * Root data... nobody should be using this though. 430 */ 431 root_data = (oss_mixext_root *)&ext->data; 432 (void) snprintf(root_data->name, sizeof (root_data->name), "%s", 433 auclnt_get_dev_name(d)); 434 (void) snprintf(root_data->id, sizeof (root_data->id), "%s", 435 auclnt_get_dev_name(d)); 436 437 odev->d_nctrl++; 438 439 /* 440 * Insert an extra marker -- needed to keep layout apps hapy. 441 * This prevents some apps from assuming we are in "LEGACY" mode. 442 */ 443 ext = &odev->d_exts[odev->d_nctrl]; 444 ext->ctrl = odev->d_nctrl; 445 ext->control_no = -1; 446 ext->type = MIXT_MARKER; 447 ext->timestamp = gethrtime(); 448 ext->parent = 0; 449 odev->d_nctrl++; 450 451 /* Fill in the complete table now */ 452 auclnt_walk_controls(d, oss_add_control, odev); 453 454 /* Update the update_counter reference counter for groups */ 455 for (nctrl = 0; nctrl < odev->d_nctrl; nctrl++) { 456 int i; 457 458 ext = &odev->d_exts[nctrl]; 459 i = ext->parent; 460 while ((i >= 0) && (i < odev->d_nctrl)) { 461 462 ext = &odev->d_exts[i]; 463 ASSERT(ext->parent < i); 464 ASSERT((ext->type == MIXT_GROUP) || 465 (ext->type == MIXT_DEVROOT)); 466 ext->update_counter++; 467 i = ext->parent; 468 } 469 } 470 471 ASSERT(odev->d_nctrl <= odev->d_nalloc); 472 } 473 474 static int 475 oss_open(audio_client_t *c, int oflag) 476 { 477 int rv; 478 ossdev_t *odev; 479 ossclient_t *sc; 480 audio_stream_t *isp, *osp; 481 482 isp = auclnt_input_stream(c); 483 osp = auclnt_output_stream(c); 484 485 /* note that OSS always uses nonblocking open() semantics */ 486 if ((rv = auclnt_open(c, oflag | FNDELAY)) != 0) { 487 return (rv); 488 } 489 490 if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) { 491 auclnt_close(c); 492 return (ENOMEM); 493 } 494 auclnt_set_private(c, sc); 495 496 odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP); 497 498 /* set a couple of common fields */ 499 sc->o_client = c; 500 sc->o_ossdev = odev; 501 502 /* set all default parameters */ 503 if (oflag & FWRITE) { 504 if (((rv = auclnt_set_format(osp, OSS_FMT)) != 0) || 505 ((rv = auclnt_set_rate(osp, OSS_RATE)) != 0) || 506 ((rv = auclnt_set_channels(osp, OSS_CHANNELS)) != 0)) { 507 goto failed; 508 } 509 /* default to 5 fragments to provide reasonable latency */ 510 auclnt_set_latency(osp, 5, 0); 511 } 512 513 if (oflag & FREAD) { 514 if (((rv = auclnt_set_format(isp, OSS_FMT)) != 0) || 515 ((rv = auclnt_set_rate(isp, OSS_RATE)) != 0) || 516 ((rv = auclnt_set_channels(isp, OSS_CHANNELS)) != 0)) { 517 goto failed; 518 } 519 /* default to 5 fragments to provide reasonable latency */ 520 auclnt_set_latency(isp, 5, 0); 521 } 522 523 return (0); 524 525 failed: 526 auclnt_close(c); 527 return (rv); 528 } 529 530 static void 531 oss_close(audio_client_t *c) 532 { 533 ossclient_t *sc; 534 535 sc = auclnt_get_private(c); 536 537 if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) { 538 (void) auclnt_drain(c); 539 } 540 541 kmem_free(sc, sizeof (*sc)); 542 543 auclnt_close(c); 544 } 545 546 /* 547 * This is used to generate an array of names for an enumeration 548 */ 549 static ushort_t 550 oss_set_enum(oss_mixer_enuminfo *ei, ushort_t nxt, const char *name) 551 { 552 uint32_t n; 553 554 /* Get current entry to fill in */ 555 n = ei->nvalues; 556 (void) snprintf(&ei->strings[nxt], ((sizeof (ei->strings) - nxt) - 1), 557 "%s", name); 558 ei->strindex[n] = nxt; 559 560 /* Adjust everything for next entry */ 561 nxt += strnlen(name, ((sizeof (ei->strings) - nxt) - 1)); 562 ei->strings[nxt++] = '\0'; 563 564 ei->nvalues++; 565 return (nxt); 566 } 567 568 /* 569 * The following two functions are used to count the number of devices 570 * in under the boomer framework. 571 * 572 * We actually report the highest "index", and then if an audio device 573 * is not found, we report a bogus removed device for it in the actual 574 * ioctls. This goofiness is required to make the OSS API happy. 575 */ 576 int 577 oss_dev_walker(audio_dev_t *d, void *arg) 578 { 579 int *pcnt = arg; 580 int cnt; 581 int index; 582 583 cnt = *pcnt; 584 index = auclnt_get_dev_index(d); 585 if ((index + 1) > cnt) { 586 cnt = index + 1; 587 *pcnt = cnt; 588 } 589 590 return (AUDIO_WALK_CONTINUE); 591 } 592 593 static int 594 oss_cnt_devs(void) 595 { 596 int cnt = 0; 597 598 auclnt_walk_devs(oss_dev_walker, &cnt); 599 return (cnt); 600 } 601 602 static int 603 sndctl_dsp_speed(audio_client_t *c, int *ratep) 604 { 605 int rate; 606 int oflag; 607 608 rate = *ratep; 609 610 oflag = auclnt_get_oflag(c); 611 if (oflag & FREAD) { 612 (void) auclnt_set_rate(auclnt_input_stream(c), rate); 613 *ratep = auclnt_get_rate(auclnt_input_stream(c)); 614 } 615 616 if (oflag & FWRITE) { 617 (void) auclnt_set_rate(auclnt_output_stream(c), rate); 618 *ratep = auclnt_get_rate(auclnt_output_stream(c)); 619 } 620 621 return (0); 622 } 623 624 static int 625 sndctl_dsp_setfmt(audio_client_t *c, int *fmtp) 626 { 627 int fmt; 628 int i; 629 int oflag; 630 631 oflag = auclnt_get_oflag(c); 632 633 if (*fmtp != AFMT_QUERY) { 634 /* convert from OSS */ 635 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 636 if (oss_formats[i].oss == *fmtp) { 637 fmt = oss_formats[i].fmt; 638 break; 639 } 640 } 641 if (fmt == AUDIO_FORMAT_NONE) { 642 /* if format not known, return */ 643 goto done; 644 } 645 646 if (oflag & FWRITE) { 647 (void) auclnt_set_format(auclnt_output_stream(c), fmt); 648 } 649 650 if (oflag & FREAD) { 651 (void) auclnt_set_format(auclnt_input_stream(c), fmt); 652 } 653 } 654 655 done: 656 if (oflag & FWRITE) { 657 fmt = auclnt_get_format(auclnt_output_stream(c)); 658 } else if (oflag & FREAD) { 659 fmt = auclnt_get_format(auclnt_input_stream(c)); 660 } 661 662 /* convert back to OSS */ 663 *(int *)fmtp = AFMT_QUERY; 664 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 665 if (oss_formats[i].fmt == fmt) { 666 *(int *)fmtp = oss_formats[i].oss; 667 } 668 } 669 670 return (0); 671 } 672 673 static int 674 sndctl_dsp_getfmts(audio_client_t *c, int *fmtsp) 675 { 676 _NOTE(ARGUNUSED(c)); 677 678 /* 679 * For now, we support all the standard ones. Later we might 680 * add in conditional support for AC3. 681 */ 682 *fmtsp = (AFMT_MU_LAW | AFMT_A_LAW | 683 AFMT_U8 | AFMT_S8 | 684 AFMT_S16_LE |AFMT_S16_BE | 685 AFMT_S24_LE | AFMT_S24_BE | 686 AFMT_S32_LE | AFMT_S32_BE | 687 AFMT_S24_PACKED); 688 689 return (0); 690 } 691 692 static int 693 sndctl_dsp_channels(audio_client_t *c, int *chanp) 694 { 695 int nchan; 696 int oflag; 697 698 oflag = auclnt_get_oflag(c); 699 700 nchan = *chanp; 701 if (nchan != 0) { 702 if (oflag & FWRITE) { 703 (void) auclnt_set_channels(auclnt_output_stream(c), 704 nchan); 705 } 706 707 if (oflag & FREAD) { 708 (void) auclnt_set_channels(auclnt_input_stream(c), 709 nchan); 710 } 711 } 712 713 if (oflag & FWRITE) { 714 nchan = auclnt_get_channels(auclnt_output_stream(c)); 715 } else if (oflag & FREAD) { 716 nchan = auclnt_get_channels(auclnt_input_stream(c)); 717 } 718 *chanp = nchan; 719 return (0); 720 } 721 722 static int 723 sndctl_dsp_stereo(audio_client_t *c, int *onoff) 724 { 725 int nchan; 726 727 switch (*onoff) { 728 case 0: 729 nchan = 1; 730 break; 731 case 1: 732 nchan = 2; 733 break; 734 default: 735 return (EINVAL); 736 } 737 738 return (sndctl_dsp_channels(c, &nchan)); 739 } 740 741 static int 742 sndctl_dsp_post(audio_client_t *c) 743 { 744 if (auclnt_get_oflag(c) & FWRITE) { 745 audio_stream_t *sp = auclnt_output_stream(c); 746 auclnt_flush(sp); 747 auclnt_clear_paused(sp); 748 } 749 return (0); 750 } 751 752 static int 753 sndctl_dsp_getcaps(audio_client_t *c, int *capsp) 754 { 755 int ncaps; 756 int osscaps = 0; 757 758 ncaps = auclnt_get_dev_capab(auclnt_get_dev(c)); 759 760 if (ncaps & AUDIO_CLIENT_CAP_PLAY) 761 osscaps |= PCM_CAP_OUTPUT; 762 if (ncaps & AUDIO_CLIENT_CAP_RECORD) 763 osscaps |= PCM_CAP_INPUT; 764 if (ncaps & AUDIO_CLIENT_CAP_DUPLEX) 765 osscaps |= PCM_CAP_DUPLEX; 766 767 if (osscaps != 0) { 768 osscaps |= PCM_CAP_TRIGGER | PCM_CAP_BATCH; 769 if (!(ncaps & AUDIO_CLIENT_CAP_OPAQUE)) { 770 osscaps |= PCM_CAP_FREERATE | PCM_CAP_MULTI; 771 } 772 } else { 773 /* This is the sndstat device! */ 774 osscaps = PCM_CAP_VIRTUAL; 775 } 776 777 *capsp = osscaps; 778 return (0); 779 } 780 781 static int 782 sndctl_dsp_gettrigger(audio_client_t *c, int *trigp) 783 { 784 int triggers = 0; 785 int oflag; 786 787 oflag = auclnt_get_oflag(c); 788 789 if (oflag & FWRITE) { 790 if (!auclnt_is_paused(auclnt_output_stream(c))) { 791 triggers |= PCM_ENABLE_OUTPUT; 792 } 793 } 794 795 if (oflag & FREAD) { 796 if (!auclnt_is_paused(auclnt_input_stream(c))) { 797 triggers |= PCM_ENABLE_INPUT; 798 } 799 } 800 *trigp = triggers; 801 802 return (0); 803 } 804 805 static int 806 sndctl_dsp_settrigger(audio_client_t *c, int *trigp) 807 { 808 int triggers; 809 int oflag; 810 audio_stream_t *sp; 811 812 oflag = auclnt_get_oflag(c); 813 triggers = *trigp; 814 815 if ((oflag & FWRITE) && (triggers & PCM_ENABLE_OUTPUT)) { 816 sp = auclnt_output_stream(c); 817 auclnt_clear_paused(sp); 818 auclnt_start(sp); 819 } 820 821 if ((oflag & FREAD) && (triggers & PCM_ENABLE_INPUT)) { 822 sp = auclnt_input_stream(c); 823 auclnt_clear_paused(sp); 824 auclnt_start(sp); 825 } 826 827 return (0); 828 } 829 830 struct oss_legacy_volume { 831 pid_t pid; 832 uint8_t ogain; 833 uint8_t igain; 834 }; 835 836 static int 837 oss_legacy_volume_walker(audio_client_t *c, void *arg) 838 { 839 struct oss_legacy_volume *olv = arg; 840 841 if (auclnt_get_pid(c) == olv->pid) { 842 if (olv->ogain <= 100) { 843 auclnt_set_gain(auclnt_output_stream(c), olv->ogain); 844 } 845 if (olv->igain <= 100) { 846 auclnt_set_gain(auclnt_input_stream(c), olv->igain); 847 } 848 } 849 return (AUDIO_WALK_CONTINUE); 850 } 851 852 static void 853 oss_set_legacy_volume(audio_client_t *c, uint8_t ogain, uint8_t igain) 854 { 855 struct oss_legacy_volume olv; 856 857 olv.pid = auclnt_get_pid(c); 858 olv.ogain = ogain; 859 olv.igain = igain; 860 auclnt_dev_walk_clients(auclnt_get_dev(c), 861 oss_legacy_volume_walker, &olv); 862 } 863 864 static int 865 sndctl_dsp_getplayvol(audio_client_t *c, int *volp) 866 { 867 int vol; 868 869 /* convert monophonic soft value to OSS stereo value */ 870 vol = auclnt_get_gain(auclnt_output_stream(c)); 871 *volp = vol | (vol << 8); 872 return (0); 873 } 874 875 static int 876 sndctl_dsp_setplayvol(audio_client_t *c, int *volp) 877 { 878 uint8_t vol; 879 880 vol = *volp & 0xff; 881 if (vol > 100) { 882 return (EINVAL); 883 } 884 885 auclnt_set_gain(auclnt_output_stream(c), vol); 886 *volp = (vol | (vol << 8)); 887 888 return (0); 889 } 890 891 static int 892 sndctl_dsp_getrecvol(audio_client_t *c, int *volp) 893 { 894 int vol; 895 896 vol = auclnt_get_gain(auclnt_input_stream(c)); 897 *volp = (vol | (vol << 8)); 898 return (0); 899 } 900 901 static int 902 sndctl_dsp_setrecvol(audio_client_t *c, int *volp) 903 { 904 uint8_t vol; 905 906 vol = *volp & 0xff; 907 if (vol > 100) { 908 return (EINVAL); 909 } 910 911 auclnt_set_gain(auclnt_input_stream(c), vol); 912 *volp = (vol | (vol << 8)); 913 914 return (0); 915 } 916 917 static int 918 sound_mixer_write_ogain(audio_client_t *c, int *volp) 919 { 920 uint8_t vol; 921 922 vol = *volp & 0xff; 923 if (vol > 100) { 924 return (EINVAL); 925 } 926 oss_set_legacy_volume(c, vol, 255); 927 *volp = (vol | (vol << 8)); 928 return (0); 929 } 930 931 static int 932 sound_mixer_write_igain(audio_client_t *c, int *volp) 933 { 934 uint8_t vol; 935 936 vol = *volp & 0xff; 937 if (vol > 100) { 938 return (EINVAL); 939 } 940 oss_set_legacy_volume(c, 255, vol); 941 *volp = (vol | (vol << 8)); 942 return (0); 943 } 944 945 static int 946 sndctl_dsp_readctl(audio_client_t *c, oss_digital_control *ctl) 947 { 948 /* SPDIF: need to add support with spdif */ 949 _NOTE(ARGUNUSED(c)); 950 _NOTE(ARGUNUSED(ctl)); 951 return (ENOTSUP); 952 } 953 954 static int 955 sndctl_dsp_writectl(audio_client_t *c, oss_digital_control *ctl) 956 { 957 /* SPDIF: need to add support with spdif */ 958 _NOTE(ARGUNUSED(c)); 959 _NOTE(ARGUNUSED(ctl)); 960 return (ENOTSUP); 961 } 962 963 static int 964 sndctl_dsp_cookedmode(audio_client_t *c, int *rvp) 965 { 966 _NOTE(ARGUNUSED(c)); 967 968 /* We are *always* in cooked mode -- at least until we have AC3. */ 969 if (*rvp == 0) { 970 return (ENOTSUP); 971 } else { 972 return (0); 973 } 974 } 975 976 static int 977 sndctl_dsp_silence(audio_client_t *c) 978 { 979 if (auclnt_get_oflag(c) & FWRITE) { 980 audio_stream_t *sp = auclnt_output_stream(c); 981 auclnt_set_paused(sp); 982 auclnt_flush(sp); 983 } 984 return (0); 985 } 986 987 static int 988 sndctl_dsp_skip(audio_client_t *c) 989 { 990 if (auclnt_get_oflag(c) & FWRITE) { 991 audio_stream_t *sp = auclnt_output_stream(c); 992 auclnt_set_paused(sp); 993 auclnt_flush(sp); 994 auclnt_clear_paused(sp); 995 } 996 return (0); 997 } 998 999 static int 1000 sndctl_dsp_halt_input(audio_client_t *c) 1001 { 1002 if (auclnt_get_oflag(c) & FREAD) { 1003 audio_stream_t *sp = auclnt_input_stream(c); 1004 auclnt_set_paused(sp); 1005 auclnt_flush(sp); 1006 } 1007 return (0); 1008 } 1009 1010 static int 1011 sndctl_dsp_halt_output(audio_client_t *c) 1012 { 1013 if (auclnt_get_oflag(c) & FWRITE) { 1014 audio_stream_t *sp = auclnt_output_stream(c); 1015 auclnt_set_paused(sp); 1016 auclnt_flush(sp); 1017 } 1018 return (0); 1019 } 1020 1021 static int 1022 sndctl_dsp_halt(audio_client_t *c) 1023 { 1024 (void) sndctl_dsp_halt_input(c); 1025 (void) sndctl_dsp_halt_output(c); 1026 return (0); 1027 } 1028 1029 static int 1030 sndctl_dsp_sync(audio_client_t *c) 1031 { 1032 return (auclnt_drain(c)); 1033 } 1034 1035 static int 1036 sndctl_dsp_setfragment(audio_client_t *c, int *fragp) 1037 { 1038 int bufsz; 1039 int nfrags; 1040 int fragsz; 1041 1042 nfrags = (*fragp) >> 16; 1043 if ((nfrags >= 0x7fffU) || (nfrags < 2)) { 1044 /* use infinite setting... no change */ 1045 return (0); 1046 } 1047 1048 fragsz = (*fragp) & 0xffff; 1049 if (fragsz > 16) { 1050 /* basically too big, so, no change */ 1051 return (0); 1052 } 1053 bufsz = (1U << fragsz) * nfrags; 1054 1055 /* 1056 * Now we have our desired buffer size, but we have to 1057 * make sure we have a whole number of fragments >= 2, and 1058 * less than the maximum. 1059 */ 1060 bufsz = ((*fragp) >> 16) * (1U << (*fragp)); 1061 if (bufsz >= 65536) { 1062 return (0); 1063 } 1064 1065 /* 1066 * We set the latency hints in terms of bytes, not fragments. 1067 */ 1068 auclnt_set_latency(auclnt_output_stream(c), 0, bufsz); 1069 auclnt_set_latency(auclnt_input_stream(c), 0, bufsz); 1070 1071 /* 1072 * According to the OSS API documentation, the values provided 1073 * are nothing more than a "hint" and not to be relied upon 1074 * anyway. And we aren't obligated to report the actual 1075 * values back! 1076 */ 1077 return (0); 1078 } 1079 1080 static int 1081 sndctl_dsp_policy(audio_client_t *c, int *policy) 1082 { 1083 int hint = *policy; 1084 if ((hint >= 2) && (hint <= 10)) { 1085 auclnt_set_latency(auclnt_input_stream(c), hint, 0); 1086 auclnt_set_latency(auclnt_output_stream(c), hint, 0); 1087 } 1088 return (0); 1089 } 1090 1091 /* 1092 * A word about recsrc, and playtgt ioctls: We don't allow ordinary DSP 1093 * applications to change port configurations, because these could have a 1094 * bad effect for other applications. Instead, these settings have to 1095 * be changed using the master mixer panel. In order to make applications 1096 * happy, we just present a single "default" source/target. 1097 */ 1098 static int 1099 sndctl_dsp_get_recsrc_names(audio_client_t *c, oss_mixer_enuminfo *ei) 1100 { 1101 _NOTE(ARGUNUSED(c)); 1102 1103 ei->nvalues = 1; 1104 (void) snprintf(ei->strings, sizeof (ei->strings), "default"); 1105 ei->strindex[0] = 0; 1106 1107 return (0); 1108 } 1109 1110 static int 1111 sndctl_dsp_get_recsrc(audio_client_t *c, int *srcp) 1112 { 1113 _NOTE(ARGUNUSED(c)); 1114 *srcp = 0; 1115 return (0); 1116 } 1117 1118 static int 1119 sndctl_dsp_set_recsrc(audio_client_t *c, int *srcp) 1120 { 1121 _NOTE(ARGUNUSED(c)); 1122 *srcp = 0; 1123 return (0); 1124 } 1125 1126 static int 1127 sndctl_dsp_get_playtgt_names(audio_client_t *c, oss_mixer_enuminfo *ei) 1128 { 1129 _NOTE(ARGUNUSED(c)); 1130 1131 ei->nvalues = 1; 1132 (void) snprintf(ei->strings, sizeof (ei->strings), "default"); 1133 ei->strindex[0] = 0; 1134 1135 return (0); 1136 } 1137 1138 static int 1139 sndctl_dsp_get_playtgt(audio_client_t *c, int *tgtp) 1140 { 1141 _NOTE(ARGUNUSED(c)); 1142 *tgtp = 0; 1143 return (0); 1144 } 1145 1146 static int 1147 sndctl_dsp_set_playtgt(audio_client_t *c, int *tgtp) 1148 { 1149 _NOTE(ARGUNUSED(c)); 1150 *tgtp = 0; 1151 return (0); 1152 } 1153 1154 static int 1155 sndctl_sysinfo(oss_sysinfo *si) 1156 { 1157 bzero(si, sizeof (*si)); 1158 (void) snprintf(si->product, sizeof (si->product), "SunOS Audio"); 1159 (void) snprintf(si->version, sizeof (si->version), "4.0"); 1160 si->versionnum = OSS_VERSION; 1161 si->numcards = oss_cnt_devs(); 1162 si->nummixers = si->numcards - 1; 1163 si->numaudios = si->numcards - 1; 1164 si->numaudioengines = si->numaudios; 1165 (void) snprintf(si->license, sizeof (si->license), "CDDL"); 1166 return (0); 1167 } 1168 1169 static int 1170 sndctl_cardinfo(audio_client_t *c, oss_card_info *ci) 1171 { 1172 audio_dev_t *d; 1173 void *iter; 1174 const char *info; 1175 int n; 1176 boolean_t release; 1177 1178 if ((n = ci->card) == -1) { 1179 release = B_FALSE; 1180 d = auclnt_get_dev(c); 1181 n = auclnt_get_dev_index(d); 1182 } else { 1183 release = B_TRUE; 1184 d = auclnt_hold_dev_by_index(n); 1185 } 1186 1187 bzero(ci, sizeof (*ci)); 1188 ci->card = n; 1189 1190 if (d == NULL) { 1191 /* 1192 * If device removed (e.g. for DR), then 1193 * report a bogus removed entry. 1194 */ 1195 (void) snprintf(ci->shortname, sizeof (ci->shortname), 1196 "<removed>"); 1197 (void) snprintf(ci->longname, sizeof (ci->longname), 1198 "<removed>"); 1199 return (0); 1200 } 1201 1202 (void) snprintf(ci->shortname, sizeof (ci->shortname), 1203 "%s", auclnt_get_dev_name(d)); 1204 (void) snprintf(ci->longname, sizeof (ci->longname), 1205 "%s (%s)", auclnt_get_dev_description(d), 1206 auclnt_get_dev_version(d)); 1207 1208 iter = NULL; 1209 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 1210 (void) strlcat(ci->hw_info, info, sizeof (ci->hw_info)); 1211 (void) strlcat(ci->hw_info, "\n", sizeof (ci->hw_info)); 1212 } 1213 1214 /* 1215 * We don't report interrupt counts, ack counts (which are 1216 * just "read" interrupts, not spurious), or any other flags. 1217 * Nothing should be using any of this data anyway ... these 1218 * values were intended for 4Front's debugging purposes. In 1219 * Solaris, drivers should use interrupt kstats to report 1220 * interrupt related statistics. 1221 */ 1222 if (release) 1223 auclnt_release_dev(d); 1224 return (0); 1225 } 1226 1227 static int 1228 audioinfo_walker(audio_engine_t *e, void *a) 1229 { 1230 oss_audioinfo *si = a; 1231 int fmt, nchan, rate, cap; 1232 1233 fmt = auclnt_engine_get_format(e); 1234 nchan = auclnt_engine_get_channels(e); 1235 rate = auclnt_engine_get_rate(e); 1236 cap = auclnt_engine_get_capab(e); 1237 1238 for (int i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 1239 if (fmt == oss_formats[i].fmt) { 1240 if (cap & AUDIO_CLIENT_CAP_PLAY) { 1241 si->oformats |= oss_formats[i].oss; 1242 } 1243 if (cap & AUDIO_CLIENT_CAP_RECORD) { 1244 si->iformats |= oss_formats[i].oss; 1245 } 1246 break; 1247 } 1248 } 1249 si->max_channels = max(nchan, si->max_channels); 1250 si->max_rate = max(rate, si->max_rate); 1251 1252 return (AUDIO_WALK_CONTINUE); 1253 } 1254 1255 static int 1256 sndctl_audioinfo(audio_client_t *c, oss_audioinfo *si) 1257 { 1258 audio_dev_t *d; 1259 const char *name; 1260 int n; 1261 boolean_t release; 1262 unsigned cap; 1263 1264 if ((n = si->dev) == -1) { 1265 release = B_FALSE; 1266 d = auclnt_get_dev(c); 1267 n = auclnt_get_dev_index(d); 1268 } else { 1269 release = B_TRUE; 1270 n++; /* skip pseudo device */ 1271 d = auclnt_hold_dev_by_index(n); 1272 } 1273 1274 bzero(si, sizeof (*si)); 1275 si->dev = n - 1; 1276 1277 if (d == NULL) { 1278 /* if device not present, forge a false entry */ 1279 si->card_number = n; 1280 si->mixer_dev = n - 1; 1281 si->legacy_device = -1; 1282 si->enabled = 0; 1283 (void) snprintf(si->name, sizeof (si->name), "<removed>"); 1284 return (0); 1285 } 1286 1287 name = auclnt_get_dev_name(d); 1288 (void) snprintf(si->name, sizeof (si->name), "%s", name); 1289 1290 si->legacy_device = auclnt_get_dev_number(d); 1291 si->caps = 0; 1292 1293 auclnt_dev_walk_engines(d, audioinfo_walker, si); 1294 1295 cap = auclnt_get_dev_capab(d); 1296 1297 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 1298 si->caps |= PCM_CAP_DUPLEX; 1299 } 1300 if (cap & AUDIO_CLIENT_CAP_PLAY) { 1301 si->caps |= PCM_CAP_OUTPUT; 1302 } 1303 if (cap & AUDIO_CLIENT_CAP_RECORD) { 1304 si->caps |= PCM_CAP_INPUT; 1305 } 1306 1307 if (si->caps != 0) { 1308 /* MMAP: we add PCM_CAP_MMAP when we we support it */ 1309 si->caps |= PCM_CAP_TRIGGER | PCM_CAP_BATCH; 1310 si->enabled = 1; 1311 si->rate_source = si->dev; 1312 1313 /* we can convert and mix PCM formats */ 1314 if (!(cap & AUDIO_CLIENT_CAP_OPAQUE)) { 1315 si->min_channels = min(2, si->max_channels); 1316 si->min_rate = min(5000, si->max_rate); 1317 si->caps |= PCM_CAP_FREERATE | PCM_CAP_MULTI; 1318 } 1319 (void) snprintf(si->devnode, sizeof (si->devnode), 1320 "/dev/sound/%s:%ddsp", 1321 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1322 } else { 1323 si->enabled = 0; /* stops apps from using us directly */ 1324 si->caps = PCM_CAP_VIRTUAL; 1325 (void) snprintf(si->devnode, sizeof (si->devnode), 1326 "/dev/sndstat"); 1327 } 1328 1329 si->pid = -1; 1330 (void) snprintf(si->handle, sizeof (si->handle), "%s", name); 1331 (void) snprintf(si->label, sizeof (si->label), "%s", name); 1332 si->latency = -1; 1333 si->card_number = n; 1334 si->mixer_dev = n - 1; 1335 1336 if (release) 1337 auclnt_release_dev(d); 1338 1339 return (0); 1340 } 1341 1342 static int 1343 sound_mixer_info(audio_client_t *c, mixer_info *mi) 1344 { 1345 audio_dev_t *d; 1346 const char *name; 1347 1348 d = auclnt_get_dev(c); 1349 1350 name = auclnt_get_dev_name(d); 1351 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1352 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1353 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1354 mi->modify_counter = (int)auclnt_dev_get_serial(d); 1355 mi->card_number = auclnt_get_dev_index(d); 1356 mi->port_number = 0; 1357 return (0); 1358 } 1359 1360 static int 1361 sound_mixer_read_devmask(audio_client_t *c, int *devmask) 1362 { 1363 _NOTE(ARGUNUSED(c)); 1364 *devmask = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_IGAIN; 1365 return (0); 1366 } 1367 1368 static int 1369 sound_mixer_read_recmask(audio_client_t *c, int *recmask) 1370 { 1371 _NOTE(ARGUNUSED(c)); 1372 *recmask = 0; 1373 return (0); 1374 } 1375 1376 static int 1377 sound_mixer_read_recsrc(audio_client_t *c, int *recsrc) 1378 { 1379 _NOTE(ARGUNUSED(c)); 1380 *recsrc = 0; 1381 return (0); 1382 } 1383 1384 static int 1385 sound_mixer_read_caps(audio_client_t *c, int *caps) 1386 { 1387 _NOTE(ARGUNUSED(c)); 1388 /* single recording source... sort of */ 1389 *caps = SOUND_CAP_EXCL_INPUT; 1390 return (0); 1391 } 1392 1393 static int 1394 sndctl_mixerinfo(audio_client_t *c, oss_mixerinfo *mi) 1395 { 1396 audio_dev_t *d; 1397 ossdev_t *odev; 1398 const char *name; 1399 int n; 1400 boolean_t release = B_FALSE; 1401 1402 if ((n = mi->dev) == -1) { 1403 release = B_FALSE; 1404 d = auclnt_get_dev(c); 1405 n = auclnt_get_dev_index(d); 1406 } else { 1407 release = B_TRUE; 1408 n++; 1409 d = auclnt_hold_dev_by_index(n); 1410 } 1411 1412 bzero(mi, sizeof (*mi)); 1413 mi->dev = n - 1; 1414 1415 if (d == NULL) { 1416 mi->card_number = n; 1417 mi->enabled = 0; 1418 mi->legacy_device = -1; 1419 (void) snprintf(mi->name, sizeof (mi->name), "<removed>"); 1420 (void) snprintf(mi->id, sizeof (mi->id), "<removed>"); 1421 return (0); 1422 } 1423 1424 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1425 if (release) 1426 auclnt_release_dev(d); 1427 return (EINVAL); 1428 } 1429 1430 name = auclnt_get_dev_name(d); 1431 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1432 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1433 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1434 mi->modify_counter = (int)auclnt_dev_get_serial(d); 1435 mi->card_number = auclnt_get_dev_index(d); 1436 mi->legacy_device = auclnt_get_dev_number(d); 1437 if (mi->legacy_device >= 0) { 1438 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1439 "/dev/sound/%s:%dmixer", 1440 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1441 mi->enabled = 1; 1442 } else { 1443 /* special nodes use generic sndstat node */ 1444 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1445 "/dev/sndstat"); 1446 mi->enabled = 0; 1447 } 1448 mi->nrext = odev->d_nctrl; 1449 1450 if (release) 1451 auclnt_release_dev(d); 1452 1453 return (0); 1454 } 1455 1456 static int 1457 sndctl_dsp_getblksize(audio_client_t *c, int *fragsz) 1458 { 1459 int oflag = auclnt_get_oflag(c); 1460 1461 if (oflag & FWRITE) 1462 *fragsz = auclnt_get_fragsz(auclnt_output_stream(c)); 1463 else if (oflag & FREAD) 1464 *fragsz = auclnt_get_fragsz(auclnt_input_stream(c)); 1465 1466 return (0); 1467 } 1468 1469 static int 1470 sndctl_dsp_getospace(audio_client_t *c, audio_buf_info *bi) 1471 { 1472 audio_stream_t *sp; 1473 unsigned n; 1474 1475 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1476 return (EACCES); 1477 } 1478 1479 sp = auclnt_output_stream(c); 1480 n = auclnt_get_nframes(sp) - auclnt_get_count(sp); 1481 1482 bi->fragsize = auclnt_get_fragsz(sp); 1483 bi->fragstotal = auclnt_get_nfrags(sp); 1484 bi->bytes = (n * auclnt_get_framesz(sp)); 1485 bi->fragments = bi->bytes / bi->fragsize; 1486 1487 return (0); 1488 } 1489 1490 static int 1491 sndctl_dsp_getispace(audio_client_t *c, audio_buf_info *bi) 1492 { 1493 audio_stream_t *sp; 1494 unsigned n; 1495 1496 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1497 return (EACCES); 1498 } 1499 1500 sp = auclnt_input_stream(c); 1501 n = auclnt_get_count(sp); 1502 1503 bi->fragsize = auclnt_get_fragsz(sp); 1504 bi->fragstotal = auclnt_get_nfrags(sp); 1505 bi->bytes = (n * auclnt_get_framesz(sp)); 1506 bi->fragments = bi->bytes / bi->fragsize; 1507 1508 return (0); 1509 } 1510 1511 static int 1512 sndctl_dsp_getodelay(audio_client_t *c, int *bytes) 1513 { 1514 unsigned framesz; 1515 unsigned slen, flen; 1516 1517 if (auclnt_get_oflag(c) & FWRITE) { 1518 audio_stream_t *sp = auclnt_output_stream(c); 1519 framesz = auclnt_get_framesz(sp); 1520 auclnt_get_output_qlen(c, &slen, &flen); 1521 *bytes = (slen + flen) * framesz; 1522 } else { 1523 *bytes = 0; 1524 } 1525 return (0); 1526 } 1527 1528 static int 1529 sndctl_dsp_current_iptr(audio_client_t *c, oss_count_t *count) 1530 { 1531 if (auclnt_get_oflag(c) & FREAD) { 1532 count->samples = auclnt_get_samples(auclnt_input_stream(c)); 1533 count->fifo_samples = 0; /* not quite accurate */ 1534 } else { 1535 count->samples = 0; 1536 count->fifo_samples = 0; 1537 } 1538 return (0); 1539 } 1540 1541 static int 1542 sndctl_dsp_current_optr(audio_client_t *c, oss_count_t *count) 1543 { 1544 unsigned samples, fifo; 1545 1546 if (auclnt_get_oflag(c) & FWRITE) { 1547 auclnt_get_output_qlen(c, &samples, &fifo); 1548 count->samples = samples; 1549 count->fifo_samples = fifo; 1550 } else { 1551 count->samples = 0; 1552 count->fifo_samples = 0; 1553 } 1554 return (0); 1555 } 1556 1557 static int 1558 sndctl_dsp_getoptr(audio_client_t *c, count_info *ci) 1559 { 1560 audio_stream_t *sp; 1561 unsigned framesz; 1562 unsigned fragsz; 1563 1564 bzero(ci, sizeof (*ci)); 1565 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1566 return (0); 1567 } 1568 sp = auclnt_output_stream(c); 1569 framesz = auclnt_get_framesz(sp); 1570 fragsz = auclnt_get_fragsz(sp); 1571 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1572 auclnt_set_samples(sp, 0); 1573 ci->bytes = auclnt_get_tail(sp) * framesz; 1574 ci->ptr = auclnt_get_tidx(sp) * framesz; 1575 return (0); 1576 } 1577 1578 static int 1579 sndctl_dsp_getiptr(audio_client_t *c, count_info *ci) 1580 { 1581 audio_stream_t *sp; 1582 unsigned framesz; 1583 unsigned fragsz; 1584 1585 bzero(ci, sizeof (*ci)); 1586 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1587 return (0); 1588 } 1589 sp = auclnt_input_stream(c); 1590 framesz = auclnt_get_framesz(sp); 1591 fragsz = auclnt_get_fragsz(sp); 1592 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1593 auclnt_set_samples(sp, 0); 1594 ci->bytes = auclnt_get_head(sp) * framesz; 1595 ci->ptr = auclnt_get_hidx(sp) * framesz; 1596 return (0); 1597 } 1598 1599 static int 1600 sndctl_dsp_geterror(audio_client_t *c, audio_errinfo *bi) 1601 { 1602 audio_stream_t *sp; 1603 unsigned fragsz; 1604 /* 1605 * Note: The use of this structure is unsafe... different 1606 * meanings for error codes are used by different implementations, 1607 * according to the spec. (Even different versions of the same 1608 * implementation could have different values.) 1609 * 1610 * Rather than try to come up with a reliable solution here, we 1611 * don't use it. If you want to report errors, or see the result 1612 * of errors, use syslog. 1613 */ 1614 bzero(bi, sizeof (*bi)); 1615 1616 sp = auclnt_output_stream(c); 1617 fragsz = max(auclnt_get_fragsz(sp), 1); 1618 bi->play_underruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1619 fragsz); 1620 auclnt_set_errors(sp, 0); 1621 1622 sp = auclnt_input_stream(c); 1623 fragsz = max(auclnt_get_fragsz(sp), 1); 1624 bi->rec_overruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1625 fragsz); 1626 auclnt_set_errors(sp, 0); 1627 1628 return (0); 1629 } 1630 1631 static int 1632 sndctl_sun_send_number(audio_client_t *c, int *num, cred_t *cr) 1633 { 1634 audio_dev_t *dev; 1635 int rv; 1636 1637 if ((rv = drv_priv(cr)) != 0) { 1638 return (rv); 1639 } 1640 1641 dev = auclnt_get_dev(c); 1642 auclnt_set_dev_number(dev, *num); 1643 return (0); 1644 } 1645 1646 static int 1647 oss_getversion(int *versp) 1648 { 1649 *versp = OSS_VERSION; 1650 return (0); 1651 } 1652 1653 static int 1654 oss_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 1655 int *rvalp) 1656 { 1657 int sz; 1658 void *data; 1659 int rv = 0; 1660 1661 _NOTE(ARGUNUSED(credp)); 1662 1663 sz = OSSIOC_GETSZ(cmd); 1664 1665 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 1666 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 1667 return (ENOMEM); 1668 } 1669 } else { 1670 sz = 0; 1671 } 1672 1673 if (cmd & OSSIOC_IN) { 1674 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 1675 goto done; 1676 } 1677 } 1678 1679 switch (cmd) { 1680 /* 1681 * DSP specific ioctls 1682 */ 1683 case SNDCTL_DSP_HALT: 1684 rv = sndctl_dsp_halt(c); 1685 break; 1686 1687 case SNDCTL_DSP_SYNC: 1688 rv = sndctl_dsp_sync(c); 1689 break; 1690 1691 case SNDCTL_DSP_SPEED: 1692 rv = sndctl_dsp_speed(c, (int *)data); 1693 break; 1694 case SNDCTL_DSP_SETFMT: 1695 rv = sndctl_dsp_setfmt(c, (int *)data); 1696 break; 1697 case SNDCTL_DSP_GETFMTS: 1698 rv = sndctl_dsp_getfmts(c, (int *)data); 1699 break; 1700 case SNDCTL_DSP_STEREO: 1701 rv = sndctl_dsp_stereo(c, (int *)data); 1702 break; 1703 case SNDCTL_DSP_CHANNELS: 1704 rv = sndctl_dsp_channels(c, (int *)data); 1705 break; 1706 case SNDCTL_DSP_POST: 1707 rv = sndctl_dsp_post(c); 1708 break; 1709 case SNDCTL_DSP_GETCAPS: 1710 rv = sndctl_dsp_getcaps(c, (int *)data); 1711 break; 1712 case SNDCTL_DSP_GETTRIGGER: 1713 rv = sndctl_dsp_gettrigger(c, (int *)data); 1714 break; 1715 case SNDCTL_DSP_SETTRIGGER: 1716 rv = sndctl_dsp_settrigger(c, (int *)data); 1717 break; 1718 case SNDCTL_DSP_GETPLAYVOL: 1719 case SOUND_MIXER_READ_VOLUME: /* legacy mixer on dsp */ 1720 case SOUND_MIXER_READ_PCM: /* legacy mixer on dsp */ 1721 case SOUND_MIXER_READ_OGAIN: /* legacy mixer on dsp */ 1722 rv = sndctl_dsp_getplayvol(c, (int *)data); 1723 break; 1724 case SOUND_MIXER_WRITE_VOLUME: /* legacy mixer on dsp */ 1725 case SOUND_MIXER_WRITE_PCM: /* legacy mixer on dsp */ 1726 case SOUND_MIXER_WRITE_OGAIN: /* legacy mixer on dsp */ 1727 rv = sound_mixer_write_ogain(c, (int *)data); 1728 break; 1729 case SNDCTL_DSP_SETPLAYVOL: 1730 rv = sndctl_dsp_setplayvol(c, (int *)data); 1731 break; 1732 case SNDCTL_DSP_READCTL: 1733 rv = sndctl_dsp_readctl(c, (oss_digital_control *)data); 1734 break; 1735 case SNDCTL_DSP_WRITECTL: 1736 rv = sndctl_dsp_writectl(c, (oss_digital_control *)data); 1737 break; 1738 case SNDCTL_DSP_COOKEDMODE: 1739 rv = sndctl_dsp_cookedmode(c, (int *)data); 1740 break; 1741 case SNDCTL_DSP_SILENCE: 1742 rv = sndctl_dsp_silence(c); 1743 break; 1744 case SNDCTL_DSP_SKIP: 1745 rv = sndctl_dsp_skip(c); 1746 break; 1747 case SNDCTL_DSP_HALT_INPUT: 1748 rv = sndctl_dsp_halt_input(c); 1749 break; 1750 case SNDCTL_DSP_HALT_OUTPUT: 1751 rv = sndctl_dsp_halt_output(c); 1752 break; 1753 case SNDCTL_DSP_GET_RECSRC_NAMES: 1754 rv = sndctl_dsp_get_recsrc_names(c, (oss_mixer_enuminfo *)data); 1755 break; 1756 case SNDCTL_DSP_SETFRAGMENT: 1757 rv = sndctl_dsp_setfragment(c, (int *)data); 1758 break; 1759 case SNDCTL_DSP_GET_RECSRC: 1760 rv = sndctl_dsp_get_recsrc(c, (int *)data); 1761 break; 1762 case SNDCTL_DSP_SET_RECSRC: 1763 rv = sndctl_dsp_set_recsrc(c, (int *)data); 1764 break; 1765 case SNDCTL_DSP_GET_PLAYTGT_NAMES: 1766 rv = sndctl_dsp_get_playtgt_names(c, 1767 (oss_mixer_enuminfo *)data); 1768 break; 1769 case SNDCTL_DSP_GET_PLAYTGT: 1770 rv = sndctl_dsp_get_playtgt(c, (int *)data); 1771 break; 1772 case SNDCTL_DSP_SET_PLAYTGT: 1773 rv = sndctl_dsp_set_playtgt(c, (int *)data); 1774 break; 1775 case SNDCTL_DSP_GETRECVOL: 1776 case SOUND_MIXER_READ_RECGAIN: /* legacy mixer on dsp */ 1777 case SOUND_MIXER_READ_RECLEV: /* legacy mixer on dsp */ 1778 case SOUND_MIXER_READ_IGAIN: /* legacy mixer on dsp */ 1779 rv = sndctl_dsp_getrecvol(c, (int *)data); 1780 break; 1781 case SOUND_MIXER_WRITE_RECGAIN: /* legacy mixer on dsp */ 1782 case SOUND_MIXER_WRITE_RECLEV: /* legacy mixer on dsp */ 1783 case SOUND_MIXER_WRITE_IGAIN: /* legacy mixer on dsp */ 1784 rv = sound_mixer_write_igain(c, (int *)data); 1785 break; 1786 case SNDCTL_DSP_SETRECVOL: 1787 rv = sndctl_dsp_setrecvol(c, (int *)data); 1788 break; 1789 case SNDCTL_DSP_SUBDIVIDE: /* Ignored */ 1790 case SNDCTL_DSP_SETDUPLEX: /* Ignored */ 1791 case SNDCTL_DSP_LOW_WATER: /* Ignored */ 1792 case SNDCTL_DSP_PROFILE: /* Ignored */ 1793 rv = 0; 1794 break; 1795 case SNDCTL_DSP_POLICY: 1796 rv = sndctl_dsp_policy(c, (int *)data); 1797 break; 1798 case SNDCTL_DSP_GETBLKSIZE: 1799 rv = sndctl_dsp_getblksize(c, (int *)data); 1800 break; 1801 case SNDCTL_DSP_GETOSPACE: 1802 rv = sndctl_dsp_getospace(c, (audio_buf_info *)data); 1803 break; 1804 case SNDCTL_DSP_GETISPACE: 1805 rv = sndctl_dsp_getispace(c, (audio_buf_info *)data); 1806 break; 1807 case SNDCTL_DSP_GETODELAY: 1808 rv = sndctl_dsp_getodelay(c, (int *)data); 1809 break; 1810 case SNDCTL_DSP_GETOPTR: 1811 rv = sndctl_dsp_getoptr(c, (count_info *)data); 1812 break; 1813 case SNDCTL_DSP_GETIPTR: 1814 rv = sndctl_dsp_getiptr(c, (count_info *)data); 1815 break; 1816 case SNDCTL_DSP_GETERROR: 1817 rv = sndctl_dsp_geterror(c, (audio_errinfo *)data); 1818 break; 1819 case SNDCTL_DSP_CURRENT_IPTR: 1820 rv = sndctl_dsp_current_iptr(c, (oss_count_t *)data); 1821 break; 1822 case SNDCTL_DSP_CURRENT_OPTR: 1823 rv = sndctl_dsp_current_optr(c, (oss_count_t *)data); 1824 break; 1825 1826 /* 1827 * Shared ioctls with /dev/mixer. 1828 */ 1829 case OSS_GETVERSION: 1830 rv = oss_getversion((int *)data); 1831 break; 1832 case SNDCTL_CARDINFO: 1833 rv = sndctl_cardinfo(c, (oss_card_info *)data); 1834 break; 1835 case SNDCTL_ENGINEINFO: 1836 case SNDCTL_AUDIOINFO: 1837 case SNDCTL_AUDIOINFO_EX: 1838 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 1839 break; 1840 case SNDCTL_SYSINFO: 1841 rv = sndctl_sysinfo((oss_sysinfo *)data); 1842 break; 1843 case SNDCTL_MIXERINFO: 1844 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 1845 break; 1846 case SOUND_MIXER_INFO: 1847 rv = sound_mixer_info(c, (mixer_info *)data); 1848 break; 1849 1850 /* 1851 * These are mixer ioctls that are virtualized for the DSP 1852 * device. They are accessible via either /dev/mixer or 1853 * /dev/dsp. 1854 */ 1855 case SOUND_MIXER_READ_RECSRC: 1856 case SOUND_MIXER_WRITE_RECSRC: 1857 rv = sound_mixer_read_recsrc(c, (int *)data); 1858 break; 1859 1860 case SOUND_MIXER_READ_DEVMASK: 1861 case SOUND_MIXER_READ_STEREODEVS: 1862 rv = sound_mixer_read_devmask(c, (int *)data); 1863 break; 1864 1865 case SOUND_MIXER_READ_RECMASK: 1866 rv = sound_mixer_read_recmask(c, (int *)data); 1867 break; 1868 1869 case SOUND_MIXER_READ_CAPS: 1870 rv = sound_mixer_read_caps(c, (int *)data); 1871 break; 1872 1873 /* 1874 * Ioctls we have chosen not to support for now. Some 1875 * of these are of legacy interest only. 1876 */ 1877 case SNDCTL_SETSONG: 1878 case SNDCTL_GETSONG: 1879 case SNDCTL_DSP_SYNCGROUP: 1880 case SNDCTL_DSP_SYNCSTART: 1881 case SNDCTL_DSP_GET_CHNORDER: 1882 case SNDCTL_DSP_SET_CHNORDER: 1883 case SNDCTL_DSP_GETIPEAKS: 1884 case SNDCTL_DSP_GETOPEAKS: 1885 case SNDCTL_DSP_GETCHANNELMASK: 1886 case SNDCTL_DSP_BIND_CHANNEL: 1887 case SNDCTL_DSP_SETSYNCRO: 1888 case SNDCTL_DSP_NONBLOCK: 1889 default: 1890 rv = EINVAL; 1891 break; 1892 } 1893 1894 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 1895 rv = ddi_copyout(data, (void *)arg, sz, mode); 1896 } 1897 if (rv == 0) { 1898 *rvalp = 0; 1899 } 1900 1901 done: 1902 if (sz) { 1903 kmem_free(data, sz); 1904 } 1905 return (rv); 1906 } 1907 1908 static void 1909 oss_output(audio_client_t *c) 1910 { 1911 auclnt_pollwakeup(c, POLLOUT); 1912 } 1913 1914 static void 1915 oss_input(audio_client_t *c) 1916 { 1917 auclnt_pollwakeup(c, POLLIN | POLLRDNORM); 1918 } 1919 1920 static int 1921 ossmix_open(audio_client_t *c, int oflag) 1922 { 1923 int rv; 1924 ossclient_t *sc; 1925 ossdev_t *odev; 1926 1927 _NOTE(ARGUNUSED(oflag)); 1928 1929 if ((rv = auclnt_open(c, 0)) != 0) { 1930 return (rv); 1931 } 1932 1933 if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) { 1934 return (ENOMEM); 1935 } 1936 sc->o_ss_sz = 8192; 1937 if ((sc->o_ss_buf = kmem_zalloc(sc->o_ss_sz, KM_NOSLEEP)) == NULL) { 1938 kmem_free(sc, sizeof (*sc)); 1939 return (ENOMEM); 1940 } 1941 auclnt_set_private(c, sc); 1942 1943 odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP); 1944 1945 /* set a couple of common fields */ 1946 sc->o_client = c; 1947 sc->o_ossdev = odev; 1948 1949 return (rv); 1950 } 1951 1952 static void 1953 ossmix_close(audio_client_t *c) 1954 { 1955 ossclient_t *sc; 1956 1957 sc = auclnt_get_private(c); 1958 1959 kmem_free(sc->o_ss_buf, sc->o_ss_sz); 1960 kmem_free(sc, sizeof (*sc)); 1961 1962 auclnt_close(c); 1963 } 1964 1965 static int 1966 sndctl_mix_nrext(audio_client_t *c, int *ncp) 1967 { 1968 audio_dev_t *d; 1969 ossdev_t *odev; 1970 1971 d = auclnt_get_dev(c); 1972 1973 if ((*ncp != -1) && (*ncp != (auclnt_get_dev_index(d) - 1))) { 1974 return (ENXIO); 1975 } 1976 1977 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1978 return (EINVAL); 1979 } 1980 1981 *ncp = odev->d_nctrl; 1982 1983 return (0); 1984 } 1985 1986 static int 1987 sndctl_mix_extinfo(audio_client_t *c, oss_mixext *pext) 1988 { 1989 audio_dev_t *d; 1990 ossdev_t *odev; 1991 int rv = 0; 1992 int dev; 1993 1994 d = auclnt_get_dev(c); 1995 1996 if (((dev = pext->dev) != -1) && (dev != (auclnt_get_dev_index(d) - 1))) 1997 return (ENXIO); 1998 1999 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2000 (pext->ctrl >= odev->d_nctrl)) { 2001 return (EINVAL); 2002 } 2003 2004 bcopy(&odev->d_exts[pext->ctrl], pext, sizeof (*pext)); 2005 pext->enumbit = 0; 2006 pext->dev = dev; 2007 2008 return (rv); 2009 } 2010 2011 static int 2012 sndctl_mix_enuminfo(audio_client_t *c, oss_mixer_enuminfo *ei) 2013 { 2014 audio_dev_t *d; 2015 audio_ctrl_desc_t desc; 2016 audio_ctrl_t *ctrl; 2017 ossdev_t *odev; 2018 uint64_t mask; 2019 int bit; 2020 ushort_t nxt; 2021 2022 d = auclnt_get_dev(c); 2023 2024 if ((ei->dev != -1) && (ei->dev != (auclnt_get_dev_index(d) - 1))) 2025 return (ENXIO); 2026 2027 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2028 (ei->ctrl >= odev->d_nctrl) || 2029 (odev->d_exts[ei->ctrl].type != MIXT_ENUM) || 2030 ((ctrl = odev->d_ctrls[ei->ctrl]) == NULL) || 2031 (auclnt_control_describe(ctrl, &desc) != 0)) { 2032 return (EINVAL); 2033 } 2034 2035 mask = desc.acd_maxvalue; 2036 bit = 0; 2037 nxt = 0; 2038 ei->nvalues = 0; 2039 bzero(ei->strings, sizeof (ei->strings)); 2040 bzero(ei->strindex, sizeof (ei->strindex)); 2041 2042 while (mask) { 2043 const char *name = desc.acd_enum[bit]; 2044 nxt = oss_set_enum(ei, nxt, name ? name : ""); 2045 mask >>= 1; 2046 bit++; 2047 } 2048 2049 return (0); 2050 } 2051 2052 static int 2053 sndctl_mix_read(audio_client_t *c, oss_mixer_value *vr) 2054 { 2055 int rv; 2056 uint64_t v; 2057 audio_dev_t *d; 2058 audio_ctrl_t *ctrl; 2059 ossdev_t *odev; 2060 2061 d = auclnt_get_dev(c); 2062 2063 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2064 return (ENXIO); 2065 2066 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2067 (vr->ctrl >= odev->d_nctrl) || 2068 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2069 return (EINVAL); 2070 } 2071 if ((rv = auclnt_control_read(ctrl, &v)) == 0) { 2072 switch (odev->d_exts[vr->ctrl].type) { 2073 case MIXT_ENUM: 2074 /* translate this from an enum style bit mask */ 2075 vr->value = ddi_ffs((unsigned long)v) - 1; 2076 break; 2077 case MIXT_STEREOSLIDER: 2078 vr->value = (int)ddi_swap16(v & 0xffff); 2079 break; 2080 case MIXT_MONOSLIDER: 2081 vr->value = (int)(v | (v << 8)); 2082 break; 2083 case MIXT_ONOFF: 2084 /* this could be simple, or could be part of a multi */ 2085 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2086 uint64_t mask; 2087 mask = 1; 2088 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2089 vr->value = (v & mask) ? 1 : 0; 2090 } else { 2091 vr->value = v ? 1 : 0; 2092 } 2093 break; 2094 2095 default: 2096 vr->value = (int)v; 2097 break; 2098 } 2099 } 2100 2101 return (rv); 2102 } 2103 2104 static int 2105 sndctl_mix_write(audio_client_t *c, oss_mixer_value *vr) 2106 { 2107 int rv; 2108 uint64_t v; 2109 audio_dev_t *d; 2110 audio_ctrl_t *ctrl; 2111 ossdev_t *odev; 2112 2113 d = auclnt_get_dev(c); 2114 2115 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2116 return (ENXIO); 2117 2118 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2119 (vr->ctrl >= odev->d_nctrl) || 2120 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2121 return (EINVAL); 2122 } 2123 2124 switch (odev->d_exts[vr->ctrl].type) { 2125 case MIXT_ONOFF: 2126 /* this could be standalone, or it could be part of a multi */ 2127 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2128 uint64_t mask; 2129 if ((rv = auclnt_control_read(ctrl, &v)) != 0) { 2130 return (EINVAL); 2131 } 2132 mask = 1; 2133 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2134 if (vr->value) { 2135 v |= mask; 2136 } else { 2137 v &= ~mask; 2138 } 2139 } else { 2140 v = vr->value; 2141 } 2142 break; 2143 case MIXT_ENUM: 2144 /* translate this to an enum style bit mask */ 2145 v = 1U << vr->value; 2146 break; 2147 case MIXT_MONOSLIDER: 2148 /* mask off high order bits */ 2149 v = vr->value & 0xff; 2150 break; 2151 case MIXT_STEREOSLIDER: 2152 /* OSS uses reverse byte ordering */ 2153 v = vr->value; 2154 v = ddi_swap16(vr->value & 0xffff); 2155 break; 2156 default: 2157 v = vr->value; 2158 } 2159 rv = auclnt_control_write(ctrl, v); 2160 2161 return (rv); 2162 } 2163 2164 static int 2165 sndctl_mix_nrmix(audio_client_t *c, int *nmixp) 2166 { 2167 _NOTE(ARGUNUSED(c)); 2168 *nmixp = oss_cnt_devs() - 1; 2169 return (0); 2170 } 2171 2172 static int 2173 ossmix_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 2174 int *rvalp) 2175 { 2176 int sz; 2177 void *data; 2178 int rv = 0; 2179 2180 sz = OSSIOC_GETSZ(cmd); 2181 2182 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 2183 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 2184 return (ENOMEM); 2185 } 2186 } else { 2187 sz = 0; 2188 } 2189 2190 if (cmd & OSSIOC_IN) { 2191 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 2192 goto done; 2193 } 2194 } 2195 2196 switch (cmd) { 2197 /* 2198 * Mixer specific ioctls 2199 */ 2200 case SNDCTL_MIX_NREXT: 2201 rv = sndctl_mix_nrext(c, (int *)data); 2202 break; 2203 case SNDCTL_MIX_EXTINFO: 2204 rv = sndctl_mix_extinfo(c, (oss_mixext *)data); 2205 break; 2206 case SNDCTL_MIX_ENUMINFO: 2207 rv = sndctl_mix_enuminfo(c, (oss_mixer_enuminfo *)data); 2208 break; 2209 case SNDCTL_MIX_READ: 2210 rv = sndctl_mix_read(c, (oss_mixer_value *)data); 2211 break; 2212 case SNDCTL_MIX_WRITE: 2213 rv = sndctl_mix_write(c, (oss_mixer_value *)data); 2214 break; 2215 case SNDCTL_MIX_NRMIX: 2216 rv = sndctl_mix_nrmix(c, (int *)data); 2217 break; 2218 2219 /* 2220 * Legacy ioctls. These are treated as soft values only, 2221 * and do not affect global hardware state. For use by 2222 * legacy DSP applications. 2223 */ 2224 case SOUND_MIXER_READ_VOLUME: 2225 case SOUND_MIXER_READ_PCM: 2226 case SOUND_MIXER_READ_OGAIN: 2227 rv = sndctl_dsp_getplayvol(c, (int *)data); 2228 break; 2229 2230 case SOUND_MIXER_WRITE_VOLUME: 2231 case SOUND_MIXER_WRITE_PCM: 2232 case SOUND_MIXER_WRITE_OGAIN: 2233 rv = sound_mixer_write_ogain(c, (int *)data); 2234 break; 2235 2236 case SOUND_MIXER_READ_RECGAIN: 2237 case SOUND_MIXER_READ_RECLEV: 2238 case SOUND_MIXER_READ_IGAIN: 2239 rv = sndctl_dsp_getrecvol(c, (int *)data); 2240 break; 2241 2242 case SOUND_MIXER_WRITE_RECGAIN: 2243 case SOUND_MIXER_WRITE_RECLEV: 2244 case SOUND_MIXER_WRITE_IGAIN: 2245 rv = sound_mixer_write_igain(c, (int *)data); 2246 break; 2247 2248 case SOUND_MIXER_READ_RECSRC: 2249 case SOUND_MIXER_WRITE_RECSRC: 2250 rv = sound_mixer_read_recsrc(c, (int *)data); 2251 break; 2252 2253 case SOUND_MIXER_READ_DEVMASK: 2254 case SOUND_MIXER_READ_STEREODEVS: 2255 rv = sound_mixer_read_devmask(c, (int *)data); 2256 break; 2257 2258 case SOUND_MIXER_READ_RECMASK: 2259 rv = sound_mixer_read_recmask(c, (int *)data); 2260 break; 2261 2262 case SOUND_MIXER_READ_CAPS: 2263 rv = sound_mixer_read_caps(c, (int *)data); 2264 break; 2265 2266 /* 2267 * Common ioctls shared with DSP 2268 */ 2269 case OSS_GETVERSION: 2270 rv = oss_getversion((int *)data); 2271 break; 2272 2273 case SNDCTL_CARDINFO: 2274 rv = sndctl_cardinfo(c, (oss_card_info *)data); 2275 break; 2276 2277 case SNDCTL_ENGINEINFO: 2278 case SNDCTL_AUDIOINFO: 2279 case SNDCTL_AUDIOINFO_EX: 2280 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 2281 break; 2282 2283 case SNDCTL_SYSINFO: 2284 rv = sndctl_sysinfo((oss_sysinfo *)data); 2285 break; 2286 2287 case SNDCTL_MIXERINFO: 2288 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 2289 break; 2290 2291 case SOUND_MIXER_INFO: 2292 rv = sound_mixer_info(c, (mixer_info *)data); 2293 break; 2294 2295 case SNDCTL_MIX_DESCRIPTION: /* NOT SUPPORTED: tooltip */ 2296 rv = EIO; /* OSS returns EIO for this one */ 2297 break; 2298 2299 /* 2300 * Special implementation-private ioctls. 2301 */ 2302 case SNDCTL_SUN_SEND_NUMBER: 2303 rv = sndctl_sun_send_number(c, (int *)data, credp); 2304 break; 2305 2306 /* 2307 * Legacy ioctls we don't support. 2308 */ 2309 case SOUND_MIXER_WRITE_MONGAIN: 2310 case SOUND_MIXER_READ_MONGAIN: 2311 case SOUND_MIXER_READ_BASS: 2312 case SOUND_MIXER_READ_TREBLE: 2313 case SOUND_MIXER_READ_SPEAKER: 2314 case SOUND_MIXER_READ_LINE: 2315 case SOUND_MIXER_READ_MIC: 2316 case SOUND_MIXER_READ_CD: 2317 case SOUND_MIXER_READ_IMIX: 2318 case SOUND_MIXER_READ_ALTPCM: 2319 case SOUND_MIXER_READ_SYNTH: 2320 case SOUND_MIXER_READ_LINE1: 2321 case SOUND_MIXER_READ_LINE2: 2322 case SOUND_MIXER_READ_LINE3: 2323 case SOUND_MIXER_WRITE_BASS: 2324 case SOUND_MIXER_WRITE_TREBLE: 2325 case SOUND_MIXER_WRITE_SPEAKER: 2326 case SOUND_MIXER_WRITE_LINE: 2327 case SOUND_MIXER_WRITE_MIC: 2328 case SOUND_MIXER_WRITE_CD: 2329 case SOUND_MIXER_WRITE_IMIX: 2330 case SOUND_MIXER_WRITE_ALTPCM: 2331 case SOUND_MIXER_WRITE_SYNTH: 2332 case SOUND_MIXER_WRITE_LINE1: 2333 case SOUND_MIXER_WRITE_LINE2: 2334 case SOUND_MIXER_WRITE_LINE3: 2335 /* 2336 * Additional ioctls we *could* support, but don't. 2337 */ 2338 case SNDCTL_SETSONG: 2339 case SNDCTL_SETLABEL: 2340 case SNDCTL_GETSONG: 2341 case SNDCTL_GETLABEL: 2342 case SNDCTL_MIDIINFO: 2343 case SNDCTL_SETNAME: 2344 default: 2345 rv = EINVAL; 2346 break; 2347 } 2348 2349 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 2350 rv = ddi_copyout(data, (void *)arg, sz, mode); 2351 } 2352 if (rv == 0) { 2353 *rvalp = 0; 2354 } 2355 2356 done: 2357 if (sz) { 2358 kmem_free(data, sz); 2359 } 2360 return (rv); 2361 } 2362 2363 static void * 2364 oss_dev_init(audio_dev_t *dev) 2365 { 2366 ossdev_t *odev; 2367 2368 odev = kmem_zalloc(sizeof (*odev), KM_SLEEP); 2369 odev->d_dev = dev; 2370 2371 mutex_init(&odev->d_mx, NULL, MUTEX_DRIVER, NULL); 2372 cv_init(&odev->d_cv, NULL, CV_DRIVER, NULL); 2373 oss_alloc_controls(odev); 2374 2375 return (odev); 2376 } 2377 2378 static void 2379 oss_dev_fini(void *arg) 2380 { 2381 ossdev_t *odev = arg; 2382 2383 if (odev != NULL) { 2384 oss_free_controls(odev); 2385 mutex_destroy(&odev->d_mx); 2386 cv_destroy(&odev->d_cv); 2387 kmem_free(odev, sizeof (*odev)); 2388 } 2389 } 2390 2391 static void 2392 sndstat_printf(ossclient_t *oc, const char *fmt, ...) 2393 { 2394 va_list va; 2395 2396 va_start(va, fmt); 2397 (void) vsnprintf(oc->o_ss_buf + oc->o_ss_len, 2398 oc->o_ss_sz - oc->o_ss_len, fmt, va); 2399 va_end(va); 2400 oc->o_ss_len = strlen(oc->o_ss_buf); 2401 } 2402 2403 static int 2404 sndstat_dev_walker(audio_dev_t *d, void *arg) 2405 { 2406 ossclient_t *oc = arg; 2407 const char *capstr; 2408 unsigned cap; 2409 2410 cap = auclnt_get_dev_capab(d); 2411 2412 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 2413 capstr = "DUPLEX"; 2414 } else if ((cap & AUDIO_CLIENT_CAP_PLAY) && 2415 (cap & AUDIO_CLIENT_CAP_RECORD)) { 2416 capstr = "INPUT,OUTPUT"; 2417 } else if (cap & AUDIO_CLIENT_CAP_PLAY) { 2418 capstr = "OUTPUT"; 2419 } else if (cap & AUDIO_CLIENT_CAP_RECORD) { 2420 capstr = "INPUT"; 2421 } else { 2422 capstr = NULL; 2423 } 2424 2425 if (capstr == NULL) 2426 return (AUDIO_WALK_CONTINUE); 2427 2428 sndstat_printf(oc, "%d: %s %s, %s (%s)\n", 2429 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2430 auclnt_get_dev_description(d), auclnt_get_dev_version(d), capstr); 2431 2432 return (AUDIO_WALK_CONTINUE); 2433 } 2434 2435 static int 2436 sndstat_mixer_walker(audio_dev_t *d, void *arg) 2437 { 2438 ossclient_t *oc = arg; 2439 unsigned cap; 2440 void *iter; 2441 const char *info; 2442 2443 cap = auclnt_get_dev_capab(d); 2444 2445 if ((cap & (AUDIO_CLIENT_CAP_PLAY|AUDIO_CLIENT_CAP_RECORD)) == 0) 2446 return (AUDIO_WALK_CONTINUE); 2447 2448 sndstat_printf(oc, "%d: %s %s, %s\n", 2449 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2450 auclnt_get_dev_description(d), auclnt_get_dev_version(d)); 2451 iter = NULL; 2452 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 2453 sndstat_printf(oc, "\t%s\n", info); 2454 } 2455 return (AUDIO_WALK_CONTINUE); 2456 } 2457 2458 static int 2459 ossmix_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2460 { 2461 /* write on sndstat is a no-op */ 2462 _NOTE(ARGUNUSED(c)); 2463 _NOTE(ARGUNUSED(uio)); 2464 _NOTE(ARGUNUSED(cr)); 2465 2466 return (0); 2467 } 2468 2469 static int 2470 ossmix_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2471 { 2472 ossclient_t *oc; 2473 unsigned n; 2474 int rv; 2475 2476 _NOTE(ARGUNUSED(cr)); 2477 2478 if (uio->uio_resid == 0) { 2479 return (0); 2480 } 2481 2482 oc = auclnt_get_private(c); 2483 2484 mutex_enter(&oc->o_ss_lock); 2485 2486 if (oc->o_ss_off == 0) { 2487 2488 sndstat_printf(oc, "SunOS Audio Framework\n"); 2489 2490 sndstat_printf(oc, "\nAudio Devices:\n"); 2491 auclnt_walk_devs_by_number(sndstat_dev_walker, oc); 2492 2493 sndstat_printf(oc, "\nMixers:\n"); 2494 auclnt_walk_devs_by_number(sndstat_mixer_walker, oc); 2495 } 2496 2497 /* 2498 * For simplicity's sake, we implement a non-seekable device. We could 2499 * support seekability, but offsets would be rather meaningless between 2500 * changes. 2501 */ 2502 n = min(uio->uio_resid, (oc->o_ss_len - oc->o_ss_off)); 2503 2504 rv = uiomove(oc->o_ss_buf + oc->o_ss_off, n, UIO_READ, uio); 2505 if (rv != 0) { 2506 n = 0; 2507 } 2508 oc->o_ss_off += n; 2509 2510 if (n == 0) { 2511 /* 2512 * end-of-file reached... clear the sndstat buffer so that 2513 * subsequent reads will get the latest data. 2514 */ 2515 oc->o_ss_off = oc->o_ss_len = 0; 2516 } 2517 mutex_exit(&oc->o_ss_lock); 2518 return (rv); 2519 } 2520 2521 int 2522 oss_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2523 { 2524 _NOTE(ARGUNUSED(cr)); 2525 2526 auclnt_clear_paused(auclnt_input_stream(c)); 2527 2528 return (auclnt_read(c, uio)); 2529 } 2530 2531 int 2532 oss_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2533 { 2534 _NOTE(ARGUNUSED(cr)); 2535 2536 auclnt_clear_paused(auclnt_output_stream(c)); 2537 2538 return (auclnt_write(c, uio)); 2539 } 2540 2541 int 2542 oss_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp, 2543 struct pollhead **phpp) 2544 { 2545 return (auclnt_chpoll(c, events, anyyet, reventsp, phpp)); 2546 } 2547 2548 static struct audio_client_ops oss_ops = { 2549 "sound,dsp", 2550 oss_dev_init, 2551 oss_dev_fini, 2552 oss_open, 2553 oss_close, 2554 oss_read, 2555 oss_write, 2556 oss_ioctl, 2557 oss_chpoll, 2558 NULL, /* mmap */ 2559 oss_input, 2560 oss_output, 2561 NULL, /* drain */ 2562 }; 2563 2564 static struct audio_client_ops ossmix_ops = { 2565 "sound,mixer", 2566 NULL, 2567 NULL, 2568 ossmix_open, 2569 ossmix_close, 2570 ossmix_read, 2571 ossmix_write, 2572 ossmix_ioctl, 2573 NULL, /* chpoll */ 2574 NULL, /* mmap */ 2575 NULL, /* input */ 2576 NULL, /* output */ 2577 NULL, /* drain */ 2578 NULL, /* wput */ 2579 NULL, /* wsrv */ 2580 }; 2581 2582 /* nearly the same as ossxmix; different minor name helps devfsadm */ 2583 static struct audio_client_ops sndstat_ops = { 2584 "sound,sndstat", 2585 NULL, /* dev_init */ 2586 NULL, /* dev_fini */ 2587 ossmix_open, 2588 ossmix_close, 2589 ossmix_read, 2590 ossmix_write, 2591 ossmix_ioctl, 2592 NULL, /* chpoll */ 2593 NULL, /* mmap */ 2594 NULL, /* input */ 2595 NULL, /* output */ 2596 NULL, /* drain */ 2597 NULL, /* wput */ 2598 NULL, /* wsrv */ 2599 }; 2600 2601 void 2602 auimpl_oss_init(void) 2603 { 2604 auclnt_register_ops(AUDIO_MINOR_DSP, &oss_ops); 2605 auclnt_register_ops(AUDIO_MINOR_MIXER, &ossmix_ops); 2606 auclnt_register_ops(AUDIO_MINOR_SNDSTAT, &sndstat_ops); 2607 } 2608