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