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 } 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 } 520 521 return (0); 522 523 failed: 524 auclnt_close(c); 525 return (rv); 526 } 527 528 static void 529 oss_close(audio_client_t *c) 530 { 531 ossclient_t *sc; 532 533 sc = auclnt_get_private(c); 534 535 if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) { 536 (void) auclnt_drain(c); 537 } 538 539 kmem_free(sc, sizeof (*sc)); 540 541 auclnt_close(c); 542 } 543 544 /* 545 * This is used to generate an array of names for an enumeration 546 */ 547 static ushort_t 548 oss_set_enum(oss_mixer_enuminfo *ei, ushort_t nxt, const char *name) 549 { 550 uint32_t n; 551 552 /* Get current entry to fill in */ 553 n = ei->nvalues; 554 (void) snprintf(&ei->strings[nxt], ((sizeof (ei->strings) - nxt) - 1), 555 "%s", name); 556 ei->strindex[n] = nxt; 557 558 /* Adjust everything for next entry */ 559 nxt += strnlen(name, ((sizeof (ei->strings) - nxt) - 1)); 560 ei->strings[nxt++] = '\0'; 561 562 ei->nvalues++; 563 return (nxt); 564 } 565 566 /* 567 * The following two functions are used to count the number of devices 568 * in under the boomer framework. 569 * 570 * We actually report the highest "index", and then if an audio device 571 * is not found, we report a bogus removed device for it in the actual 572 * ioctls. This goofiness is required to make the OSS API happy. 573 */ 574 int 575 oss_dev_walker(audio_dev_t *d, void *arg) 576 { 577 int *pcnt = arg; 578 int cnt; 579 int index; 580 581 cnt = *pcnt; 582 index = auclnt_get_dev_index(d); 583 if ((index + 1) > cnt) { 584 cnt = index + 1; 585 *pcnt = cnt; 586 } 587 588 return (AUDIO_WALK_CONTINUE); 589 } 590 591 static int 592 oss_cnt_devs(void) 593 { 594 int cnt = 0; 595 596 auclnt_walk_devs(oss_dev_walker, &cnt); 597 return (cnt); 598 } 599 600 static int 601 sndctl_dsp_speed(audio_client_t *c, int *ratep) 602 { 603 int rv; 604 int rate; 605 int oflag; 606 607 rate = *ratep; 608 609 oflag = auclnt_get_oflag(c); 610 if (oflag & FREAD) { 611 if ((rv = auclnt_set_rate(auclnt_input_stream(c), rate)) != 0) 612 return (rv); 613 } 614 615 if (oflag & FWRITE) { 616 if ((rv = auclnt_set_rate(auclnt_output_stream(c), rate)) != 0) 617 return (rv); 618 } 619 620 return (0); 621 } 622 623 static int 624 sndctl_dsp_setfmt(audio_client_t *c, int *fmtp) 625 { 626 int rv; 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 ENOTSUP */ 643 return (ENOTSUP); 644 } 645 646 if (oflag & FWRITE) { 647 rv = auclnt_set_format(auclnt_output_stream(c), fmt); 648 if (rv != 0) 649 return (rv); 650 } 651 652 if (oflag & FREAD) { 653 rv = auclnt_set_format(auclnt_input_stream(c), fmt); 654 if (rv != 0) 655 return (rv); 656 } 657 } 658 659 if (oflag & FWRITE) { 660 fmt = auclnt_get_format(auclnt_output_stream(c)); 661 } else if (oflag & FREAD) { 662 fmt = auclnt_get_format(auclnt_input_stream(c)); 663 } 664 665 /* convert back to OSS */ 666 *(int *)fmtp = AFMT_QUERY; 667 for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 668 if (oss_formats[i].fmt == fmt) { 669 *(int *)fmtp = oss_formats[i].oss; 670 } 671 } 672 673 return (0); 674 } 675 676 static int 677 sndctl_dsp_getfmts(audio_client_t *c, int *fmtsp) 678 { 679 _NOTE(ARGUNUSED(c)); 680 681 /* 682 * For now, we support all the standard ones. Later we might 683 * add in conditional support for AC3. 684 */ 685 *fmtsp = (AFMT_MU_LAW | AFMT_A_LAW | 686 AFMT_U8 | AFMT_S8 | 687 AFMT_S16_LE |AFMT_S16_BE | 688 AFMT_S24_LE | AFMT_S24_BE | 689 AFMT_S32_LE | AFMT_S32_BE | 690 AFMT_S24_PACKED); 691 692 return (0); 693 } 694 695 static int 696 sndctl_dsp_channels(audio_client_t *c, int *chanp) 697 { 698 int rv; 699 int nchan; 700 int oflag; 701 702 oflag = auclnt_get_oflag(c); 703 704 nchan = *chanp; 705 if (nchan != 0) { 706 if (oflag & FWRITE) { 707 rv = auclnt_set_channels(auclnt_output_stream(c), 708 nchan); 709 if (rv != 0) 710 return (rv); 711 } 712 713 if (oflag & FREAD) { 714 rv = auclnt_set_channels(auclnt_input_stream(c), nchan); 715 if (rv != 0) 716 return (rv); 717 } 718 } 719 720 if (oflag & FWRITE) { 721 nchan = auclnt_get_channels(auclnt_output_stream(c)); 722 } else if (oflag & FREAD) { 723 nchan = auclnt_get_channels(auclnt_input_stream(c)); 724 } 725 *chanp = nchan; 726 return (0); 727 } 728 729 static int 730 sndctl_dsp_stereo(audio_client_t *c, int *onoff) 731 { 732 int nchan; 733 734 switch (*onoff) { 735 case 0: 736 nchan = 1; 737 break; 738 case 1: 739 nchan = 2; 740 break; 741 default: 742 return (EINVAL); 743 } 744 745 return (sndctl_dsp_channels(c, &nchan)); 746 } 747 748 static int 749 sndctl_dsp_post(audio_client_t *c) 750 { 751 if (auclnt_get_oflag(c) & FWRITE) { 752 audio_stream_t *sp = auclnt_output_stream(c); 753 auclnt_flush(sp); 754 auclnt_clear_paused(sp); 755 } 756 return (0); 757 } 758 759 static int 760 sndctl_dsp_getcaps(audio_client_t *c, int *capsp) 761 { 762 int ncaps; 763 int osscaps = 0; 764 765 ncaps = auclnt_get_dev_capab(auclnt_get_dev(c)); 766 767 if (ncaps & AUDIO_CLIENT_CAP_PLAY) 768 osscaps |= PCM_CAP_OUTPUT; 769 if (ncaps & AUDIO_CLIENT_CAP_RECORD) 770 osscaps |= PCM_CAP_INPUT; 771 if (ncaps & AUDIO_CLIENT_CAP_DUPLEX) 772 osscaps |= PCM_CAP_DUPLEX; 773 774 *capsp = osscaps; 775 return (0); 776 } 777 778 static int 779 sndctl_dsp_gettrigger(audio_client_t *c, int *trigp) 780 { 781 int triggers = 0; 782 int oflag; 783 784 oflag = auclnt_get_oflag(c); 785 786 if (oflag & FWRITE) { 787 if (!auclnt_is_paused(auclnt_output_stream(c))) { 788 triggers |= PCM_ENABLE_OUTPUT; 789 } 790 } 791 792 if (oflag & FREAD) { 793 if (!auclnt_is_paused(auclnt_input_stream(c))) { 794 triggers |= PCM_ENABLE_INPUT; 795 } 796 } 797 *trigp = triggers; 798 799 return (0); 800 } 801 802 static int 803 sndctl_dsp_settrigger(audio_client_t *c, int *trigp) 804 { 805 int triggers; 806 int oflag; 807 808 oflag = auclnt_get_oflag(c); 809 triggers = *trigp; 810 811 if ((oflag & FWRITE) && (triggers & PCM_ENABLE_OUTPUT)) { 812 auclnt_clear_paused(auclnt_output_stream(c)); 813 } 814 815 if ((oflag & FREAD) && (triggers & PCM_ENABLE_INPUT)) { 816 auclnt_clear_paused(auclnt_input_stream(c)); 817 } 818 819 return (0); 820 } 821 822 struct oss_legacy_volume { 823 pid_t pid; 824 uint8_t ogain; 825 uint8_t igain; 826 }; 827 828 static int 829 oss_legacy_volume_walker(audio_client_t *c, void *arg) 830 { 831 struct oss_legacy_volume *olv = arg; 832 833 if (auclnt_get_pid(c) == olv->pid) { 834 if (olv->ogain <= 100) { 835 auclnt_set_gain(auclnt_output_stream(c), olv->ogain); 836 } 837 if (olv->igain <= 100) { 838 auclnt_set_gain(auclnt_input_stream(c), olv->igain); 839 } 840 } 841 return (AUDIO_WALK_CONTINUE); 842 } 843 844 static void 845 oss_set_legacy_volume(audio_client_t *c, uint8_t ogain, uint8_t igain) 846 { 847 struct oss_legacy_volume olv; 848 849 olv.pid = auclnt_get_pid(c); 850 olv.ogain = ogain; 851 olv.igain = igain; 852 auclnt_dev_walk_clients(auclnt_get_dev(c), 853 oss_legacy_volume_walker, &olv); 854 } 855 856 static int 857 sndctl_dsp_getplayvol(audio_client_t *c, int *volp) 858 { 859 int vol; 860 861 /* convert monophonic soft value to OSS stereo value */ 862 vol = auclnt_get_gain(auclnt_output_stream(c)); 863 *volp = vol | (vol << 8); 864 return (0); 865 } 866 867 static int 868 sndctl_dsp_setplayvol(audio_client_t *c, int *volp) 869 { 870 uint8_t vol; 871 872 vol = *volp & 0xff; 873 if (vol > 100) { 874 return (EINVAL); 875 } 876 877 auclnt_set_gain(auclnt_output_stream(c), vol); 878 *volp = (vol | (vol << 8)); 879 880 return (0); 881 } 882 883 static int 884 sndctl_dsp_getrecvol(audio_client_t *c, int *volp) 885 { 886 int vol; 887 888 vol = auclnt_get_gain(auclnt_input_stream(c)); 889 *volp = (vol | (vol << 8)); 890 return (0); 891 } 892 893 static int 894 sndctl_dsp_setrecvol(audio_client_t *c, int *volp) 895 { 896 uint8_t vol; 897 898 vol = *volp & 0xff; 899 if (vol > 100) { 900 return (EINVAL); 901 } 902 903 auclnt_set_gain(auclnt_input_stream(c), vol); 904 *volp = (vol | (vol << 8)); 905 906 return (0); 907 } 908 909 static int 910 sound_mixer_write_ogain(audio_client_t *c, int *volp) 911 { 912 uint8_t vol; 913 914 vol = *volp & 0xff; 915 if (vol > 100) { 916 return (EINVAL); 917 } 918 oss_set_legacy_volume(c, vol, 255); 919 *volp = (vol | (vol << 8)); 920 return (0); 921 } 922 923 static int 924 sound_mixer_write_igain(audio_client_t *c, int *volp) 925 { 926 uint8_t vol; 927 928 vol = *volp & 0xff; 929 if (vol > 100) { 930 return (EINVAL); 931 } 932 oss_set_legacy_volume(c, 255, vol); 933 *volp = (vol | (vol << 8)); 934 return (0); 935 } 936 937 static int 938 sndctl_dsp_readctl(audio_client_t *c, oss_digital_control *ctl) 939 { 940 /* SPDIF: need to add support with spdif */ 941 _NOTE(ARGUNUSED(c)); 942 _NOTE(ARGUNUSED(ctl)); 943 return (ENOTSUP); 944 } 945 946 static int 947 sndctl_dsp_writectl(audio_client_t *c, oss_digital_control *ctl) 948 { 949 /* SPDIF: need to add support with spdif */ 950 _NOTE(ARGUNUSED(c)); 951 _NOTE(ARGUNUSED(ctl)); 952 return (ENOTSUP); 953 } 954 955 static int 956 sndctl_dsp_cookedmode(audio_client_t *c, int *rvp) 957 { 958 _NOTE(ARGUNUSED(c)); 959 960 /* We are *always* in cooked mode -- at least until we have AC3. */ 961 if (*rvp == 0) { 962 return (ENOTSUP); 963 } else { 964 return (0); 965 } 966 } 967 968 static int 969 sndctl_dsp_silence(audio_client_t *c) 970 { 971 if (auclnt_get_oflag(c) & FWRITE) { 972 audio_stream_t *sp = auclnt_output_stream(c); 973 auclnt_set_paused(sp); 974 auclnt_flush(sp); 975 } 976 return (0); 977 } 978 979 static int 980 sndctl_dsp_skip(audio_client_t *c) 981 { 982 if (auclnt_get_oflag(c) & FWRITE) { 983 audio_stream_t *sp = auclnt_output_stream(c); 984 auclnt_set_paused(sp); 985 auclnt_flush(sp); 986 auclnt_clear_paused(sp); 987 } 988 return (0); 989 } 990 991 static int 992 sndctl_dsp_halt_input(audio_client_t *c) 993 { 994 if (auclnt_get_oflag(c) & FREAD) { 995 audio_stream_t *sp = auclnt_input_stream(c); 996 auclnt_set_paused(sp); 997 auclnt_flush(sp); 998 } 999 return (0); 1000 } 1001 1002 static int 1003 sndctl_dsp_halt_output(audio_client_t *c) 1004 { 1005 if (auclnt_get_oflag(c) & FWRITE) { 1006 audio_stream_t *sp = auclnt_output_stream(c); 1007 auclnt_set_paused(sp); 1008 auclnt_flush(sp); 1009 } 1010 return (0); 1011 } 1012 1013 static int 1014 sndctl_dsp_halt(audio_client_t *c) 1015 { 1016 (void) sndctl_dsp_halt_input(c); 1017 (void) sndctl_dsp_halt_output(c); 1018 return (0); 1019 } 1020 1021 static int 1022 sndctl_dsp_sync(audio_client_t *c) 1023 { 1024 return (auclnt_drain(c)); 1025 } 1026 1027 static int 1028 sndctl_dsp_setfragment(audio_client_t *c, int *fragp) 1029 { 1030 _NOTE(ARGUNUSED(c)); 1031 _NOTE(ARGUNUSED(fragp)); 1032 /* 1033 * We don't really implement this "properly" at this time. 1034 * The problems with this ioctl are various: the API insists 1035 * that fragment sizes be a power of two -- and we can't cope 1036 * with accurately reporting fragment sizes in the face of 1037 * mixing and format conversion. 1038 * 1039 * Well behaved applications should really not use this API. 1040 * 1041 * According to the OSS API documentation, the values provided 1042 * are nothing more than a "hint" and not to be relied upon 1043 * anyway. And we aren't obligated to report the actual 1044 * values back! 1045 */ 1046 return (0); 1047 } 1048 1049 /* 1050 * A word about recsrc, and playtgt ioctls: We don't allow ordinary DSP 1051 * applications to change port configurations, because these could have a 1052 * bad effect for other applications. Instead, these settings have to 1053 * be changed using the master mixer panel. In order to make applications 1054 * happy, we just present a single "default" source/target. 1055 */ 1056 static int 1057 sndctl_dsp_get_recsrc_names(audio_client_t *c, oss_mixer_enuminfo *ei) 1058 { 1059 _NOTE(ARGUNUSED(c)); 1060 1061 ei->nvalues = 1; 1062 (void) snprintf(ei->strings, sizeof (ei->strings), "default"); 1063 ei->strindex[0] = 0; 1064 1065 return (0); 1066 } 1067 1068 static int 1069 sndctl_dsp_get_recsrc(audio_client_t *c, int *srcp) 1070 { 1071 _NOTE(ARGUNUSED(c)); 1072 *srcp = 0; 1073 return (0); 1074 } 1075 1076 static int 1077 sndctl_dsp_set_recsrc(audio_client_t *c, int *srcp) 1078 { 1079 _NOTE(ARGUNUSED(c)); 1080 *srcp = 0; 1081 return (0); 1082 } 1083 1084 static int 1085 sndctl_dsp_get_playtgt_names(audio_client_t *c, oss_mixer_enuminfo *ei) 1086 { 1087 _NOTE(ARGUNUSED(c)); 1088 1089 ei->nvalues = 1; 1090 (void) snprintf(ei->strings, sizeof (ei->strings), "default"); 1091 ei->strindex[0] = 0; 1092 1093 return (0); 1094 } 1095 1096 static int 1097 sndctl_dsp_get_playtgt(audio_client_t *c, int *tgtp) 1098 { 1099 _NOTE(ARGUNUSED(c)); 1100 *tgtp = 0; 1101 return (0); 1102 } 1103 1104 static int 1105 sndctl_dsp_set_playtgt(audio_client_t *c, int *tgtp) 1106 { 1107 _NOTE(ARGUNUSED(c)); 1108 *tgtp = 0; 1109 return (0); 1110 } 1111 1112 static int 1113 sndctl_sysinfo(oss_sysinfo *si) 1114 { 1115 bzero(si, sizeof (*si)); 1116 (void) snprintf(si->product, sizeof (si->product), "SunOS Audio"); 1117 (void) snprintf(si->version, sizeof (si->version), "4.0"); 1118 si->versionnum = OSS_VERSION; 1119 si->numcards = oss_cnt_devs(); 1120 si->nummixers = si->numcards - 1; 1121 si->numaudios = si->numcards - 1; 1122 si->numaudioengines = si->numaudios; 1123 (void) snprintf(si->license, sizeof (si->license), "CDDL"); 1124 return (0); 1125 } 1126 1127 static int 1128 sndctl_cardinfo(audio_client_t *c, oss_card_info *ci) 1129 { 1130 audio_dev_t *d; 1131 void *iter; 1132 const char *info; 1133 int n; 1134 boolean_t release; 1135 1136 if ((n = ci->card) == -1) { 1137 release = B_FALSE; 1138 d = auclnt_get_dev(c); 1139 n = auclnt_get_dev_index(d); 1140 } else { 1141 release = B_TRUE; 1142 d = auclnt_hold_dev_by_index(n); 1143 } 1144 1145 bzero(ci, sizeof (*ci)); 1146 ci->card = n; 1147 1148 if (d == NULL) { 1149 /* 1150 * If device removed (e.g. for DR), then 1151 * report a bogus removed entry. 1152 */ 1153 (void) snprintf(ci->shortname, sizeof (ci->shortname), 1154 "<removed>"); 1155 (void) snprintf(ci->longname, sizeof (ci->longname), 1156 "<removed>"); 1157 return (0); 1158 } 1159 1160 (void) snprintf(ci->shortname, sizeof (ci->shortname), 1161 "%s", auclnt_get_dev_name(d)); 1162 (void) snprintf(ci->longname, sizeof (ci->longname), 1163 "%s (%s)", auclnt_get_dev_description(d), 1164 auclnt_get_dev_version(d)); 1165 1166 iter = NULL; 1167 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 1168 (void) strlcat(ci->hw_info, info, sizeof (ci->hw_info)); 1169 (void) strlcat(ci->hw_info, "\n", sizeof (ci->hw_info)); 1170 } 1171 1172 /* 1173 * We don't report interrupt counts, ack counts (which are 1174 * just "read" interrupts, not spurious), or any other flags. 1175 * Nothing should be using any of this data anyway ... these 1176 * values were intended for 4Front's debugging purposes. In 1177 * Solaris, drivers should use interrupt kstats to report 1178 * interrupt related statistics. 1179 */ 1180 if (release) 1181 auclnt_release_dev(d); 1182 return (0); 1183 } 1184 1185 static int 1186 audioinfo_walker(audio_engine_t *e, void *a) 1187 { 1188 oss_audioinfo *si = a; 1189 int fmt, nchan, rate, cap; 1190 1191 fmt = auclnt_engine_get_format(e); 1192 nchan = auclnt_engine_get_channels(e); 1193 rate = auclnt_engine_get_rate(e); 1194 cap = auclnt_engine_get_capab(e); 1195 1196 for (int i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) { 1197 if (fmt == oss_formats[i].fmt) { 1198 if (cap & AUDIO_CLIENT_CAP_PLAY) { 1199 si->oformats |= oss_formats[i].oss; 1200 } 1201 if (cap & AUDIO_CLIENT_CAP_RECORD) { 1202 si->iformats |= oss_formats[i].oss; 1203 } 1204 break; 1205 } 1206 } 1207 si->max_channels = max(nchan, si->max_channels); 1208 si->max_rate = max(rate, si->max_rate); 1209 1210 return (AUDIO_WALK_CONTINUE); 1211 } 1212 1213 static int 1214 sndctl_audioinfo(audio_client_t *c, oss_audioinfo *si) 1215 { 1216 audio_dev_t *d; 1217 const char *name; 1218 int n; 1219 boolean_t release; 1220 unsigned cap; 1221 1222 if ((n = si->dev) == -1) { 1223 release = B_FALSE; 1224 d = auclnt_get_dev(c); 1225 n = auclnt_get_dev_index(d); 1226 } else { 1227 release = B_TRUE; 1228 n++; /* skip pseudo device */ 1229 d = auclnt_hold_dev_by_index(n); 1230 } 1231 1232 bzero(si, sizeof (*si)); 1233 si->dev = n - 1; 1234 1235 if (d == NULL) { 1236 /* if device not present, forge a false entry */ 1237 si->card_number = n; 1238 si->mixer_dev = n - 1; 1239 si->legacy_device = -1; 1240 si->enabled = 0; 1241 (void) snprintf(si->name, sizeof (si->name), "<removed>"); 1242 return (0); 1243 } 1244 1245 name = auclnt_get_dev_name(d); 1246 (void) snprintf(si->name, sizeof (si->name), "%s", name); 1247 1248 si->legacy_device = auclnt_get_dev_number(d); 1249 si->caps = 0; 1250 1251 auclnt_dev_walk_engines(d, audioinfo_walker, si); 1252 1253 cap = auclnt_get_dev_capab(d); 1254 1255 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 1256 si->caps |= PCM_CAP_DUPLEX; 1257 } 1258 if (cap & AUDIO_CLIENT_CAP_PLAY) { 1259 si->caps |= PCM_CAP_OUTPUT; 1260 } 1261 if (cap & AUDIO_CLIENT_CAP_RECORD) { 1262 si->caps |= PCM_CAP_INPUT; 1263 } 1264 1265 if (si->caps != 0) { 1266 /* AC3: PCM_CAP_MULTI would be wrong for an AC3 only device */ 1267 si->caps |= PCM_CAP_BATCH | PCM_CAP_TRIGGER | PCM_CAP_MULTI; 1268 /* MMAP: we add PCM_CAP_MMAP when we we support it */ 1269 si->enabled = 1; 1270 si->rate_source = si->dev; 1271 1272 /* we can convert PCM formats */ 1273 if ((si->iformats | si->oformats) & 1274 AUDIO_FORMAT_PCM) { 1275 si->min_channels = min(2, si->max_channels); 1276 si->min_rate = min(5000, si->max_rate); 1277 si->caps |= PCM_CAP_FREERATE; 1278 } 1279 (void) snprintf(si->devnode, sizeof (si->devnode), 1280 "/dev/sound/%s:%ddsp", 1281 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1282 } else { 1283 si->enabled = 0; /* stops apps from using us directly */ 1284 si->caps = PCM_CAP_VIRTUAL; 1285 (void) snprintf(si->devnode, sizeof (si->devnode), 1286 "/dev/sndstat"); 1287 } 1288 1289 si->pid = -1; 1290 (void) snprintf(si->handle, sizeof (si->handle), "%s", name); 1291 (void) snprintf(si->label, sizeof (si->label), "%s", name); 1292 si->latency = -1; 1293 si->card_number = n; 1294 si->mixer_dev = n - 1; 1295 1296 if (release) 1297 auclnt_release_dev(d); 1298 1299 return (0); 1300 } 1301 1302 static int 1303 sound_mixer_info(audio_client_t *c, mixer_info *mi) 1304 { 1305 audio_dev_t *d; 1306 ossdev_t *odev; 1307 ossclient_t *sc; 1308 const char *name; 1309 1310 sc = auclnt_get_private(c); 1311 odev = sc->o_ossdev; 1312 1313 d = auclnt_get_dev(c); 1314 1315 name = auclnt_get_dev_name(d); 1316 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1317 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1318 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1319 mi->modify_counter = odev->d_modify_cnt; 1320 mi->card_number = auclnt_get_dev_index(d); 1321 mi->port_number = 0; 1322 return (0); 1323 } 1324 1325 static int 1326 sound_mixer_read_devmask(audio_client_t *c, int *devmask) 1327 { 1328 _NOTE(ARGUNUSED(c)); 1329 *devmask = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_IGAIN; 1330 return (0); 1331 } 1332 1333 static int 1334 sound_mixer_read_recmask(audio_client_t *c, int *recmask) 1335 { 1336 _NOTE(ARGUNUSED(c)); 1337 *recmask = 0; 1338 return (0); 1339 } 1340 1341 static int 1342 sound_mixer_read_recsrc(audio_client_t *c, int *recsrc) 1343 { 1344 _NOTE(ARGUNUSED(c)); 1345 *recsrc = 0; 1346 return (0); 1347 } 1348 1349 static int 1350 sound_mixer_read_caps(audio_client_t *c, int *caps) 1351 { 1352 _NOTE(ARGUNUSED(c)); 1353 /* single recording source... sort of */ 1354 *caps = SOUND_CAP_EXCL_INPUT; 1355 return (0); 1356 } 1357 1358 static int 1359 sndctl_mixerinfo(audio_client_t *c, oss_mixerinfo *mi) 1360 { 1361 audio_dev_t *d; 1362 ossdev_t *odev; 1363 const char *name; 1364 int n; 1365 boolean_t release = B_FALSE; 1366 1367 if ((n = mi->dev) == -1) { 1368 release = B_FALSE; 1369 d = auclnt_get_dev(c); 1370 n = auclnt_get_dev_index(d); 1371 } else { 1372 release = B_TRUE; 1373 n++; 1374 d = auclnt_hold_dev_by_index(n); 1375 } 1376 1377 bzero(mi, sizeof (*mi)); 1378 mi->dev = n - 1; 1379 1380 if (d == NULL) { 1381 mi->card_number = n; 1382 mi->enabled = 0; 1383 mi->legacy_device = -1; 1384 (void) snprintf(mi->name, sizeof (mi->name), "<removed>"); 1385 (void) snprintf(mi->id, sizeof (mi->id), "<removed>"); 1386 return (0); 1387 } 1388 1389 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1390 if (release) 1391 auclnt_release_dev(d); 1392 return (EINVAL); 1393 } 1394 1395 name = auclnt_get_dev_name(d); 1396 (void) snprintf(mi->name, sizeof (mi->name), "%s", name); 1397 (void) snprintf(mi->id, sizeof (mi->id), "%s", name); 1398 (void) snprintf(mi->handle, sizeof (mi->handle), "%s", name); 1399 mi->modify_counter = odev->d_modify_cnt; 1400 mi->card_number = auclnt_get_dev_index(d); 1401 mi->legacy_device = auclnt_get_dev_number(d); 1402 if (mi->legacy_device >= 0) { 1403 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1404 "/dev/sound/%s:%dmixer", 1405 auclnt_get_dev_driver(d), auclnt_get_dev_instance(d)); 1406 mi->enabled = 1; 1407 } else { 1408 /* special nodes use generic sndstat node */ 1409 (void) snprintf(mi->devnode, sizeof (mi->devnode), 1410 "/dev/sndstat"); 1411 mi->enabled = 0; 1412 } 1413 mi->nrext = odev->d_nctrl; 1414 1415 if (release) 1416 auclnt_release_dev(d); 1417 1418 return (0); 1419 } 1420 1421 static int 1422 sndctl_dsp_getblksize(audio_client_t *c, int *fragsz) 1423 { 1424 int oflag = auclnt_get_oflag(c); 1425 1426 if (oflag & FWRITE) 1427 *fragsz = auclnt_get_fragsz(auclnt_output_stream(c)); 1428 else if (oflag & FREAD) 1429 *fragsz = auclnt_get_fragsz(auclnt_input_stream(c)); 1430 1431 return (0); 1432 } 1433 1434 static int 1435 sndctl_dsp_getospace(audio_client_t *c, audio_buf_info *bi) 1436 { 1437 audio_stream_t *sp; 1438 unsigned n; 1439 1440 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1441 return (EACCES); 1442 } 1443 1444 sp = auclnt_output_stream(c); 1445 n = auclnt_get_nframes(sp) - auclnt_get_count(sp); 1446 1447 bi->fragsize = auclnt_get_fragsz(sp); 1448 bi->fragstotal = auclnt_get_nfrags(sp); 1449 bi->bytes = (n * auclnt_get_framesz(sp)); 1450 bi->fragments = bi->bytes / bi->fragsize; 1451 1452 return (0); 1453 } 1454 1455 static int 1456 sndctl_dsp_getispace(audio_client_t *c, audio_buf_info *bi) 1457 { 1458 audio_stream_t *sp; 1459 unsigned n; 1460 1461 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1462 return (EACCES); 1463 } 1464 1465 sp = auclnt_input_stream(c); 1466 n = auclnt_get_count(sp); 1467 1468 bi->fragsize = auclnt_get_fragsz(sp); 1469 bi->fragstotal = auclnt_get_nfrags(sp); 1470 bi->bytes = (n * auclnt_get_framesz(sp)); 1471 bi->fragments = bi->bytes / bi->fragsize; 1472 1473 return (0); 1474 } 1475 1476 static int 1477 sndctl_dsp_getodelay(audio_client_t *c, int *bytes) 1478 { 1479 unsigned framesz; 1480 unsigned slen, flen; 1481 1482 if (auclnt_get_oflag(c) & FWRITE) { 1483 audio_stream_t *sp = auclnt_output_stream(c); 1484 framesz = auclnt_get_framesz(sp); 1485 auclnt_get_output_qlen(c, &slen, &flen); 1486 *bytes = (slen + flen) * framesz; 1487 } else { 1488 *bytes = 0; 1489 } 1490 return (0); 1491 } 1492 1493 static int 1494 sndctl_dsp_current_iptr(audio_client_t *c, oss_count_t *count) 1495 { 1496 if (auclnt_get_oflag(c) & FREAD) { 1497 count->samples = auclnt_get_samples(auclnt_input_stream(c)); 1498 count->fifo_samples = 0; /* not quite accurate */ 1499 } else { 1500 count->samples = 0; 1501 count->fifo_samples = 0; 1502 } 1503 return (0); 1504 } 1505 1506 static int 1507 sndctl_dsp_current_optr(audio_client_t *c, oss_count_t *count) 1508 { 1509 unsigned samples, fifo; 1510 1511 if (auclnt_get_oflag(c) & FWRITE) { 1512 auclnt_get_output_qlen(c, &samples, &fifo); 1513 count->samples = samples; 1514 count->fifo_samples = fifo; 1515 } else { 1516 count->samples = 0; 1517 count->fifo_samples = 0; 1518 } 1519 return (0); 1520 } 1521 1522 static int 1523 sndctl_dsp_getoptr(audio_client_t *c, count_info *ci) 1524 { 1525 audio_stream_t *sp; 1526 unsigned framesz; 1527 unsigned fragsz; 1528 1529 bzero(ci, sizeof (*ci)); 1530 if ((auclnt_get_oflag(c) & FWRITE) == 0) { 1531 return (0); 1532 } 1533 sp = auclnt_output_stream(c); 1534 framesz = auclnt_get_framesz(sp); 1535 fragsz = auclnt_get_fragsz(sp); 1536 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1537 auclnt_set_samples(sp, 0); 1538 ci->bytes = auclnt_get_tail(sp) * framesz; 1539 ci->ptr = auclnt_get_tidx(sp) * framesz; 1540 return (0); 1541 } 1542 1543 static int 1544 sndctl_dsp_getiptr(audio_client_t *c, count_info *ci) 1545 { 1546 audio_stream_t *sp; 1547 unsigned framesz; 1548 unsigned fragsz; 1549 1550 bzero(ci, sizeof (*ci)); 1551 if ((auclnt_get_oflag(c) & FREAD) == 0) { 1552 return (0); 1553 } 1554 sp = auclnt_input_stream(c); 1555 framesz = auclnt_get_framesz(sp); 1556 fragsz = auclnt_get_fragsz(sp); 1557 ci->blocks = auclnt_get_samples(sp) * framesz / fragsz; 1558 auclnt_set_samples(sp, 0); 1559 ci->bytes = auclnt_get_head(sp) * framesz; 1560 ci->ptr = auclnt_get_hidx(sp) * framesz; 1561 return (0); 1562 } 1563 1564 static int 1565 sndctl_dsp_geterror(audio_client_t *c, audio_errinfo *bi) 1566 { 1567 audio_stream_t *sp; 1568 unsigned fragsz; 1569 /* 1570 * Note: The use of this structure is unsafe... different 1571 * meanings for error codes are used by different implementations, 1572 * according to the spec. (Even different versions of the same 1573 * implementation could have different values.) 1574 * 1575 * Rather than try to come up with a reliable solution here, we 1576 * don't use it. If you want to report errors, or see the result 1577 * of errors, use syslog. 1578 */ 1579 bzero(bi, sizeof (*bi)); 1580 1581 sp = auclnt_output_stream(c); 1582 fragsz = max(auclnt_get_fragsz(sp), 1); 1583 bi->play_underruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1584 fragsz); 1585 auclnt_set_errors(sp, 0); 1586 1587 sp = auclnt_input_stream(c); 1588 fragsz = max(auclnt_get_fragsz(sp), 1); 1589 bi->rec_overruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) / 1590 fragsz); 1591 auclnt_set_errors(sp, 0); 1592 1593 return (0); 1594 } 1595 1596 static int 1597 sndctl_sun_send_number(audio_client_t *c, int *num, cred_t *cr) 1598 { 1599 audio_dev_t *dev; 1600 int rv; 1601 1602 if ((rv = drv_priv(cr)) != 0) { 1603 return (rv); 1604 } 1605 1606 dev = auclnt_get_dev(c); 1607 auclnt_set_dev_number(dev, *num); 1608 return (0); 1609 } 1610 1611 static int 1612 oss_getversion(int *versp) 1613 { 1614 *versp = OSS_VERSION; 1615 return (0); 1616 } 1617 1618 static int 1619 oss_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 1620 int *rvalp) 1621 { 1622 int sz; 1623 void *data; 1624 int rv = 0; 1625 1626 _NOTE(ARGUNUSED(credp)); 1627 1628 sz = OSSIOC_GETSZ(cmd); 1629 1630 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 1631 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 1632 return (ENOMEM); 1633 } 1634 } else { 1635 sz = 0; 1636 } 1637 1638 if (cmd & OSSIOC_IN) { 1639 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 1640 goto done; 1641 } 1642 } 1643 1644 switch (cmd) { 1645 /* 1646 * DSP specific ioctls 1647 */ 1648 case SNDCTL_DSP_HALT: 1649 rv = sndctl_dsp_halt(c); 1650 break; 1651 1652 case SNDCTL_DSP_SYNC: 1653 rv = sndctl_dsp_sync(c); 1654 break; 1655 1656 case SNDCTL_DSP_SPEED: 1657 rv = sndctl_dsp_speed(c, (int *)data); 1658 break; 1659 case SNDCTL_DSP_SETFMT: 1660 rv = sndctl_dsp_setfmt(c, (int *)data); 1661 break; 1662 case SNDCTL_DSP_GETFMTS: 1663 rv = sndctl_dsp_getfmts(c, (int *)data); 1664 break; 1665 case SNDCTL_DSP_STEREO: 1666 rv = sndctl_dsp_stereo(c, (int *)data); 1667 break; 1668 case SNDCTL_DSP_CHANNELS: 1669 rv = sndctl_dsp_channels(c, (int *)data); 1670 break; 1671 case SNDCTL_DSP_POST: 1672 rv = sndctl_dsp_post(c); 1673 break; 1674 case SNDCTL_DSP_GETCAPS: 1675 rv = sndctl_dsp_getcaps(c, (int *)data); 1676 break; 1677 case SNDCTL_DSP_GETTRIGGER: 1678 rv = sndctl_dsp_gettrigger(c, (int *)data); 1679 break; 1680 case SNDCTL_DSP_SETTRIGGER: 1681 rv = sndctl_dsp_settrigger(c, (int *)data); 1682 break; 1683 case SNDCTL_DSP_GETPLAYVOL: 1684 case SOUND_MIXER_READ_VOLUME: /* legacy mixer on dsp */ 1685 case SOUND_MIXER_READ_PCM: /* legacy mixer on dsp */ 1686 case SOUND_MIXER_READ_OGAIN: /* legacy mixer on dsp */ 1687 rv = sndctl_dsp_getplayvol(c, (int *)data); 1688 break; 1689 case SOUND_MIXER_WRITE_VOLUME: /* legacy mixer on dsp */ 1690 case SOUND_MIXER_WRITE_PCM: /* legacy mixer on dsp */ 1691 case SOUND_MIXER_WRITE_OGAIN: /* legacy mixer on dsp */ 1692 rv = sound_mixer_write_ogain(c, (int *)data); 1693 break; 1694 case SNDCTL_DSP_SETPLAYVOL: 1695 rv = sndctl_dsp_setplayvol(c, (int *)data); 1696 break; 1697 case SNDCTL_DSP_READCTL: 1698 rv = sndctl_dsp_readctl(c, (oss_digital_control *)data); 1699 break; 1700 case SNDCTL_DSP_WRITECTL: 1701 rv = sndctl_dsp_writectl(c, (oss_digital_control *)data); 1702 break; 1703 case SNDCTL_DSP_COOKEDMODE: 1704 rv = sndctl_dsp_cookedmode(c, (int *)data); 1705 break; 1706 case SNDCTL_DSP_SILENCE: 1707 rv = sndctl_dsp_silence(c); 1708 break; 1709 case SNDCTL_DSP_SKIP: 1710 rv = sndctl_dsp_skip(c); 1711 break; 1712 case SNDCTL_DSP_HALT_INPUT: 1713 rv = sndctl_dsp_halt_input(c); 1714 break; 1715 case SNDCTL_DSP_HALT_OUTPUT: 1716 rv = sndctl_dsp_halt_output(c); 1717 break; 1718 case SNDCTL_DSP_GET_RECSRC_NAMES: 1719 rv = sndctl_dsp_get_recsrc_names(c, (oss_mixer_enuminfo *)data); 1720 break; 1721 case SNDCTL_DSP_SUBDIVIDE: 1722 case SNDCTL_DSP_SETFRAGMENT: 1723 rv = sndctl_dsp_setfragment(c, (int *)data); 1724 break; 1725 case SNDCTL_DSP_GET_RECSRC: 1726 rv = sndctl_dsp_get_recsrc(c, (int *)data); 1727 break; 1728 case SNDCTL_DSP_SET_RECSRC: 1729 rv = sndctl_dsp_set_recsrc(c, (int *)data); 1730 break; 1731 case SNDCTL_DSP_GET_PLAYTGT_NAMES: 1732 rv = sndctl_dsp_get_playtgt_names(c, 1733 (oss_mixer_enuminfo *)data); 1734 break; 1735 case SNDCTL_DSP_GET_PLAYTGT: 1736 rv = sndctl_dsp_get_playtgt(c, (int *)data); 1737 break; 1738 case SNDCTL_DSP_SET_PLAYTGT: 1739 rv = sndctl_dsp_set_playtgt(c, (int *)data); 1740 break; 1741 case SNDCTL_DSP_GETRECVOL: 1742 case SOUND_MIXER_READ_RECGAIN: /* legacy mixer on dsp */ 1743 case SOUND_MIXER_READ_RECLEV: /* legacy mixer on dsp */ 1744 case SOUND_MIXER_READ_IGAIN: /* legacy mixer on dsp */ 1745 rv = sndctl_dsp_getrecvol(c, (int *)data); 1746 break; 1747 case SOUND_MIXER_WRITE_RECGAIN: /* legacy mixer on dsp */ 1748 case SOUND_MIXER_WRITE_RECLEV: /* legacy mixer on dsp */ 1749 case SOUND_MIXER_WRITE_IGAIN: /* legacy mixer on dsp */ 1750 rv = sound_mixer_write_igain(c, (int *)data); 1751 break; 1752 case SNDCTL_DSP_SETRECVOL: 1753 rv = sndctl_dsp_setrecvol(c, (int *)data); 1754 break; 1755 case SNDCTL_DSP_SETDUPLEX: /* Ignored */ 1756 case SNDCTL_DSP_LOW_WATER: /* Ignored */ 1757 case SNDCTL_DSP_POLICY: /* Ignored */ 1758 case SNDCTL_DSP_PROFILE: /* Ignored */ 1759 rv = 0; 1760 break; 1761 case SNDCTL_DSP_GETBLKSIZE: 1762 rv = sndctl_dsp_getblksize(c, (int *)data); 1763 break; 1764 case SNDCTL_DSP_GETOSPACE: 1765 rv = sndctl_dsp_getospace(c, (audio_buf_info *)data); 1766 break; 1767 case SNDCTL_DSP_GETISPACE: 1768 rv = sndctl_dsp_getispace(c, (audio_buf_info *)data); 1769 break; 1770 case SNDCTL_DSP_GETODELAY: 1771 rv = sndctl_dsp_getodelay(c, (int *)data); 1772 break; 1773 case SNDCTL_DSP_GETOPTR: 1774 rv = sndctl_dsp_getoptr(c, (count_info *)data); 1775 break; 1776 case SNDCTL_DSP_GETIPTR: 1777 rv = sndctl_dsp_getiptr(c, (count_info *)data); 1778 break; 1779 case SNDCTL_DSP_GETERROR: 1780 rv = sndctl_dsp_geterror(c, (audio_errinfo *)data); 1781 break; 1782 case SNDCTL_DSP_CURRENT_IPTR: 1783 rv = sndctl_dsp_current_iptr(c, (oss_count_t *)data); 1784 break; 1785 case SNDCTL_DSP_CURRENT_OPTR: 1786 rv = sndctl_dsp_current_optr(c, (oss_count_t *)data); 1787 break; 1788 1789 /* 1790 * Shared ioctls with /dev/mixer. 1791 */ 1792 case OSS_GETVERSION: 1793 rv = oss_getversion((int *)data); 1794 break; 1795 case SNDCTL_CARDINFO: 1796 rv = sndctl_cardinfo(c, (oss_card_info *)data); 1797 break; 1798 case SNDCTL_ENGINEINFO: 1799 case SNDCTL_AUDIOINFO: 1800 case SNDCTL_AUDIOINFO_EX: 1801 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 1802 break; 1803 case SNDCTL_SYSINFO: 1804 rv = sndctl_sysinfo((oss_sysinfo *)data); 1805 break; 1806 case SNDCTL_MIXERINFO: 1807 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 1808 break; 1809 case SOUND_MIXER_INFO: 1810 rv = sound_mixer_info(c, (mixer_info *)data); 1811 break; 1812 1813 /* 1814 * These are mixer ioctls that are virtualized for the DSP 1815 * device. They are accessible via either /dev/mixer or 1816 * /dev/dsp. 1817 */ 1818 case SOUND_MIXER_READ_RECSRC: 1819 case SOUND_MIXER_WRITE_RECSRC: 1820 rv = sound_mixer_read_recsrc(c, (int *)data); 1821 break; 1822 1823 case SOUND_MIXER_READ_DEVMASK: 1824 case SOUND_MIXER_READ_STEREODEVS: 1825 rv = sound_mixer_read_devmask(c, (int *)data); 1826 break; 1827 1828 case SOUND_MIXER_READ_RECMASK: 1829 rv = sound_mixer_read_recmask(c, (int *)data); 1830 break; 1831 1832 case SOUND_MIXER_READ_CAPS: 1833 rv = sound_mixer_read_caps(c, (int *)data); 1834 break; 1835 1836 /* 1837 * Ioctls we have chosen not to support for now. Some 1838 * of these are of legacy interest only. 1839 */ 1840 case SNDCTL_SETSONG: 1841 case SNDCTL_GETSONG: 1842 case SNDCTL_DSP_SYNCGROUP: 1843 case SNDCTL_DSP_SYNCSTART: 1844 case SNDCTL_DSP_GET_CHNORDER: 1845 case SNDCTL_DSP_SET_CHNORDER: 1846 case SNDCTL_DSP_GETIPEAKS: 1847 case SNDCTL_DSP_GETOPEAKS: 1848 case SNDCTL_DSP_GETCHANNELMASK: 1849 case SNDCTL_DSP_BIND_CHANNEL: 1850 case SNDCTL_DSP_SETSYNCRO: 1851 default: 1852 rv = EINVAL; 1853 break; 1854 } 1855 1856 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 1857 rv = ddi_copyout(data, (void *)arg, sz, mode); 1858 } 1859 if (rv == 0) { 1860 *rvalp = 0; 1861 } 1862 1863 done: 1864 if (sz) { 1865 kmem_free(data, sz); 1866 } 1867 return (rv); 1868 } 1869 1870 static void 1871 oss_output(audio_client_t *c) 1872 { 1873 auclnt_pollwakeup(c, POLLOUT); 1874 } 1875 1876 static void 1877 oss_input(audio_client_t *c) 1878 { 1879 auclnt_pollwakeup(c, POLLIN | POLLRDNORM); 1880 } 1881 1882 static void 1883 oss_notify(audio_client_t *c) 1884 { 1885 audio_dev_t *d; 1886 ossdev_t *odev; 1887 1888 d = auclnt_get_dev(c); 1889 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1890 return; 1891 } 1892 odev->d_modify_cnt++; 1893 } 1894 1895 static int 1896 ossmix_open(audio_client_t *c, int oflag) 1897 { 1898 int rv; 1899 ossclient_t *sc; 1900 ossdev_t *odev; 1901 1902 _NOTE(ARGUNUSED(oflag)); 1903 1904 if ((rv = auclnt_open(c, AUDIO_FORMAT_NONE, 0)) != 0) { 1905 return (rv); 1906 } 1907 1908 if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) { 1909 return (ENOMEM); 1910 } 1911 sc->o_ss_sz = 8192; 1912 if ((sc->o_ss_buf = kmem_zalloc(sc->o_ss_sz, KM_NOSLEEP)) == NULL) { 1913 kmem_free(sc, sizeof (*sc)); 1914 return (ENOMEM); 1915 } 1916 auclnt_set_private(c, sc); 1917 1918 odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP); 1919 1920 /* set a couple of common fields */ 1921 sc->o_client = c; 1922 sc->o_ossdev = odev; 1923 1924 return (rv); 1925 } 1926 1927 static void 1928 ossmix_close(audio_client_t *c) 1929 { 1930 ossclient_t *sc; 1931 1932 sc = auclnt_get_private(c); 1933 1934 kmem_free(sc->o_ss_buf, sc->o_ss_sz); 1935 kmem_free(sc, sizeof (*sc)); 1936 1937 auclnt_close(c); 1938 } 1939 1940 static int 1941 sndctl_mix_nrext(audio_client_t *c, int *ncp) 1942 { 1943 audio_dev_t *d; 1944 ossdev_t *odev; 1945 1946 d = auclnt_get_dev(c); 1947 1948 if ((*ncp != -1) && (*ncp != (auclnt_get_dev_index(d) - 1))) { 1949 return (ENXIO); 1950 } 1951 1952 if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) { 1953 return (EINVAL); 1954 } 1955 1956 *ncp = odev->d_nctrl; 1957 1958 return (0); 1959 } 1960 1961 static int 1962 sndctl_mix_extinfo(audio_client_t *c, oss_mixext *pext) 1963 { 1964 audio_dev_t *d; 1965 ossdev_t *odev; 1966 int rv = 0; 1967 int dev; 1968 1969 d = auclnt_get_dev(c); 1970 1971 if (((dev = pext->dev) != -1) && (dev != (auclnt_get_dev_index(d) - 1))) 1972 return (ENXIO); 1973 1974 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 1975 (pext->ctrl >= odev->d_nctrl)) { 1976 return (EINVAL); 1977 } 1978 1979 bcopy(&odev->d_exts[pext->ctrl], pext, sizeof (*pext)); 1980 pext->enumbit = 0; 1981 pext->dev = dev; 1982 1983 return (rv); 1984 } 1985 1986 static int 1987 sndctl_mix_enuminfo(audio_client_t *c, oss_mixer_enuminfo *ei) 1988 { 1989 audio_dev_t *d; 1990 audio_ctrl_desc_t desc; 1991 audio_ctrl_t *ctrl; 1992 ossdev_t *odev; 1993 uint64_t mask; 1994 int bit; 1995 ushort_t nxt; 1996 1997 d = auclnt_get_dev(c); 1998 1999 if ((ei->dev != -1) && (ei->dev != (auclnt_get_dev_index(d) - 1))) 2000 return (ENXIO); 2001 2002 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2003 (ei->ctrl >= odev->d_nctrl) || 2004 (odev->d_exts[ei->ctrl].type != MIXT_ENUM) || 2005 ((ctrl = odev->d_ctrls[ei->ctrl]) == NULL) || 2006 (auclnt_control_describe(ctrl, &desc) != 0)) { 2007 return (EINVAL); 2008 } 2009 2010 mask = desc.acd_maxvalue; 2011 bit = 0; 2012 nxt = 0; 2013 ei->nvalues = 0; 2014 bzero(ei->strings, sizeof (ei->strings)); 2015 bzero(ei->strindex, sizeof (ei->strindex)); 2016 2017 while (mask) { 2018 const char *name = desc.acd_enum[bit]; 2019 nxt = oss_set_enum(ei, nxt, name ? name : ""); 2020 mask >>= 1; 2021 bit++; 2022 } 2023 2024 return (0); 2025 } 2026 2027 static int 2028 sndctl_mix_read(audio_client_t *c, oss_mixer_value *vr) 2029 { 2030 int rv; 2031 uint64_t v; 2032 audio_dev_t *d; 2033 audio_ctrl_t *ctrl; 2034 ossdev_t *odev; 2035 2036 d = auclnt_get_dev(c); 2037 2038 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2039 return (ENXIO); 2040 2041 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2042 (vr->ctrl >= odev->d_nctrl) || 2043 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2044 return (EINVAL); 2045 } 2046 if ((rv = auclnt_control_read(ctrl, &v)) == 0) { 2047 switch (odev->d_exts[vr->ctrl].type) { 2048 case MIXT_ENUM: 2049 /* translate this from an enum style bit mask */ 2050 vr->value = ddi_ffs((unsigned long)v) - 1; 2051 break; 2052 case MIXT_STEREOSLIDER: 2053 vr->value = (int)ddi_swap16(v & 0xffff); 2054 break; 2055 case MIXT_MONOSLIDER: 2056 vr->value = (int)(v | (v << 8)); 2057 break; 2058 case MIXT_ONOFF: 2059 /* this could be simple, or could be part of a multi */ 2060 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2061 uint64_t mask; 2062 mask = 1; 2063 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2064 vr->value = (v & mask) ? 1 : 0; 2065 } else { 2066 vr->value = v ? 1 : 0; 2067 } 2068 break; 2069 2070 default: 2071 vr->value = (int)v; 2072 break; 2073 } 2074 } 2075 2076 return (rv); 2077 } 2078 2079 static int 2080 sndctl_mix_write(audio_client_t *c, oss_mixer_value *vr) 2081 { 2082 int rv; 2083 uint64_t v; 2084 audio_dev_t *d; 2085 audio_ctrl_t *ctrl; 2086 ossdev_t *odev; 2087 2088 d = auclnt_get_dev(c); 2089 2090 if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1))) 2091 return (ENXIO); 2092 2093 if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) || 2094 (vr->ctrl >= odev->d_nctrl) || 2095 ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) { 2096 return (EINVAL); 2097 } 2098 2099 switch (odev->d_exts[vr->ctrl].type) { 2100 case MIXT_ONOFF: 2101 /* this could be standalone, or it could be part of a multi */ 2102 if (odev->d_exts[vr->ctrl].enumbit >= 0) { 2103 uint64_t mask; 2104 if ((rv = auclnt_control_read(ctrl, &v)) != 0) { 2105 return (EINVAL); 2106 } 2107 mask = 1; 2108 mask <<= (odev->d_exts[vr->ctrl].enumbit); 2109 if (vr->value) { 2110 v |= mask; 2111 } else { 2112 v &= ~mask; 2113 } 2114 } else { 2115 v = vr->value; 2116 } 2117 break; 2118 case MIXT_ENUM: 2119 /* translate this to an enum style bit mask */ 2120 v = 1U << vr->value; 2121 break; 2122 case MIXT_MONOSLIDER: 2123 /* mask off high order bits */ 2124 v = vr->value & 0xff; 2125 break; 2126 case MIXT_STEREOSLIDER: 2127 /* OSS uses reverse byte ordering */ 2128 v = vr->value; 2129 v = ddi_swap16(vr->value & 0xffff); 2130 break; 2131 default: 2132 v = vr->value; 2133 } 2134 rv = auclnt_control_write(ctrl, v); 2135 2136 return (rv); 2137 } 2138 2139 static int 2140 sndctl_mix_nrmix(audio_client_t *c, int *nmixp) 2141 { 2142 _NOTE(ARGUNUSED(c)); 2143 *nmixp = oss_cnt_devs() - 1; 2144 return (0); 2145 } 2146 2147 static int 2148 ossmix_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp, 2149 int *rvalp) 2150 { 2151 int sz; 2152 void *data; 2153 int rv = 0; 2154 2155 sz = OSSIOC_GETSZ(cmd); 2156 2157 if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) { 2158 if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 2159 return (ENOMEM); 2160 } 2161 } else { 2162 sz = 0; 2163 } 2164 2165 if (cmd & OSSIOC_IN) { 2166 if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) { 2167 goto done; 2168 } 2169 } 2170 2171 switch (cmd) { 2172 /* 2173 * Mixer specific ioctls 2174 */ 2175 case SNDCTL_MIX_NREXT: 2176 rv = sndctl_mix_nrext(c, (int *)data); 2177 break; 2178 case SNDCTL_MIX_EXTINFO: 2179 rv = sndctl_mix_extinfo(c, (oss_mixext *)data); 2180 break; 2181 case SNDCTL_MIX_ENUMINFO: 2182 rv = sndctl_mix_enuminfo(c, (oss_mixer_enuminfo *)data); 2183 break; 2184 case SNDCTL_MIX_READ: 2185 rv = sndctl_mix_read(c, (oss_mixer_value *)data); 2186 break; 2187 case SNDCTL_MIX_WRITE: 2188 rv = sndctl_mix_write(c, (oss_mixer_value *)data); 2189 break; 2190 case SNDCTL_MIX_NRMIX: 2191 rv = sndctl_mix_nrmix(c, (int *)data); 2192 break; 2193 2194 /* 2195 * Legacy ioctls. These are treated as soft values only, 2196 * and do not affect global hardware state. For use by 2197 * legacy DSP applications. 2198 */ 2199 case SOUND_MIXER_READ_VOLUME: 2200 case SOUND_MIXER_READ_PCM: 2201 case SOUND_MIXER_READ_OGAIN: 2202 rv = sndctl_dsp_getplayvol(c, (int *)data); 2203 break; 2204 2205 case SOUND_MIXER_WRITE_VOLUME: 2206 case SOUND_MIXER_WRITE_PCM: 2207 case SOUND_MIXER_WRITE_OGAIN: 2208 rv = sound_mixer_write_ogain(c, (int *)data); 2209 break; 2210 2211 case SOUND_MIXER_READ_RECGAIN: 2212 case SOUND_MIXER_READ_RECLEV: 2213 case SOUND_MIXER_READ_IGAIN: 2214 rv = sndctl_dsp_getrecvol(c, (int *)data); 2215 break; 2216 2217 case SOUND_MIXER_WRITE_RECGAIN: 2218 case SOUND_MIXER_WRITE_RECLEV: 2219 case SOUND_MIXER_WRITE_IGAIN: 2220 rv = sound_mixer_write_igain(c, (int *)data); 2221 break; 2222 2223 case SOUND_MIXER_READ_RECSRC: 2224 case SOUND_MIXER_WRITE_RECSRC: 2225 rv = sound_mixer_read_recsrc(c, (int *)data); 2226 break; 2227 2228 case SOUND_MIXER_READ_DEVMASK: 2229 case SOUND_MIXER_READ_STEREODEVS: 2230 rv = sound_mixer_read_devmask(c, (int *)data); 2231 break; 2232 2233 case SOUND_MIXER_READ_RECMASK: 2234 rv = sound_mixer_read_recmask(c, (int *)data); 2235 break; 2236 2237 /* 2238 * Common ioctls shared with DSP 2239 */ 2240 case OSS_GETVERSION: 2241 rv = oss_getversion((int *)data); 2242 break; 2243 2244 case SNDCTL_CARDINFO: 2245 rv = sndctl_cardinfo(c, (oss_card_info *)data); 2246 break; 2247 2248 case SNDCTL_ENGINEINFO: 2249 case SNDCTL_AUDIOINFO: 2250 case SNDCTL_AUDIOINFO_EX: 2251 rv = sndctl_audioinfo(c, (oss_audioinfo *)data); 2252 break; 2253 2254 case SNDCTL_SYSINFO: 2255 rv = sndctl_sysinfo((oss_sysinfo *)data); 2256 break; 2257 2258 case SNDCTL_MIXERINFO: 2259 rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data); 2260 break; 2261 2262 case SOUND_MIXER_INFO: 2263 rv = sound_mixer_info(c, (mixer_info *)data); 2264 break; 2265 2266 case SNDCTL_MIX_DESCRIPTION: /* NOT SUPPORTED: tooltip */ 2267 rv = EIO; /* OSS returns EIO for this one */ 2268 break; 2269 2270 /* 2271 * Special implementation-private ioctls. 2272 */ 2273 case SNDCTL_SUN_SEND_NUMBER: 2274 rv = sndctl_sun_send_number(c, (int *)data, credp); 2275 break; 2276 2277 /* 2278 * Legacy ioctls we don't support. 2279 */ 2280 case SOUND_MIXER_WRITE_MONGAIN: 2281 case SOUND_MIXER_READ_MONGAIN: 2282 case SOUND_MIXER_READ_BASS: 2283 case SOUND_MIXER_READ_TREBLE: 2284 case SOUND_MIXER_READ_SPEAKER: 2285 case SOUND_MIXER_READ_LINE: 2286 case SOUND_MIXER_READ_MIC: 2287 case SOUND_MIXER_READ_CD: 2288 case SOUND_MIXER_READ_IMIX: 2289 case SOUND_MIXER_READ_ALTPCM: 2290 case SOUND_MIXER_READ_SYNTH: 2291 case SOUND_MIXER_READ_LINE1: 2292 case SOUND_MIXER_READ_LINE2: 2293 case SOUND_MIXER_READ_LINE3: 2294 case SOUND_MIXER_WRITE_BASS: 2295 case SOUND_MIXER_WRITE_TREBLE: 2296 case SOUND_MIXER_WRITE_SPEAKER: 2297 case SOUND_MIXER_WRITE_LINE: 2298 case SOUND_MIXER_WRITE_MIC: 2299 case SOUND_MIXER_WRITE_CD: 2300 case SOUND_MIXER_WRITE_IMIX: 2301 case SOUND_MIXER_WRITE_ALTPCM: 2302 case SOUND_MIXER_WRITE_SYNTH: 2303 case SOUND_MIXER_WRITE_LINE1: 2304 case SOUND_MIXER_WRITE_LINE2: 2305 case SOUND_MIXER_WRITE_LINE3: 2306 /* 2307 * Additional ioctls we *could* support, but don't. 2308 */ 2309 case SNDCTL_SETSONG: 2310 case SNDCTL_SETLABEL: 2311 case SNDCTL_GETSONG: 2312 case SNDCTL_GETLABEL: 2313 case SNDCTL_MIDIINFO: 2314 case SNDCTL_SETNAME: 2315 default: 2316 rv = EINVAL; 2317 break; 2318 } 2319 2320 if ((rv == 0) && (cmd & OSSIOC_OUT)) { 2321 rv = ddi_copyout(data, (void *)arg, sz, mode); 2322 } 2323 if (rv == 0) { 2324 *rvalp = 0; 2325 } 2326 2327 done: 2328 if (sz) { 2329 kmem_free(data, sz); 2330 } 2331 return (rv); 2332 } 2333 2334 static void * 2335 oss_dev_init(audio_dev_t *dev) 2336 { 2337 ossdev_t *odev; 2338 2339 odev = kmem_zalloc(sizeof (*odev), KM_SLEEP); 2340 odev->d_dev = dev; 2341 2342 mutex_init(&odev->d_mx, NULL, MUTEX_DRIVER, NULL); 2343 cv_init(&odev->d_cv, NULL, CV_DRIVER, NULL); 2344 oss_alloc_controls(odev); 2345 2346 return (odev); 2347 } 2348 2349 static void 2350 oss_dev_fini(void *arg) 2351 { 2352 ossdev_t *odev = arg; 2353 2354 if (odev != NULL) { 2355 oss_free_controls(odev); 2356 mutex_destroy(&odev->d_mx); 2357 cv_destroy(&odev->d_cv); 2358 kmem_free(odev, sizeof (*odev)); 2359 } 2360 } 2361 2362 static void 2363 sndstat_printf(ossclient_t *oc, const char *fmt, ...) 2364 { 2365 va_list va; 2366 2367 va_start(va, fmt); 2368 (void) vsnprintf(oc->o_ss_buf + oc->o_ss_len, 2369 oc->o_ss_sz - oc->o_ss_len, fmt, va); 2370 va_end(va); 2371 oc->o_ss_len = strlen(oc->o_ss_buf); 2372 } 2373 2374 static int 2375 sndstat_dev_walker(audio_dev_t *d, void *arg) 2376 { 2377 ossclient_t *oc = arg; 2378 const char *capstr; 2379 unsigned cap; 2380 2381 cap = auclnt_get_dev_capab(d); 2382 2383 if (cap & AUDIO_CLIENT_CAP_DUPLEX) { 2384 capstr = "DUPLEX"; 2385 } else if ((cap & AUDIO_CLIENT_CAP_PLAY) && 2386 (cap & AUDIO_CLIENT_CAP_RECORD)) { 2387 capstr = "INPUT,OUTPUT"; 2388 } else if (cap & AUDIO_CLIENT_CAP_PLAY) { 2389 capstr = "OUTPUT"; 2390 } else if (cap & AUDIO_CLIENT_CAP_RECORD) { 2391 capstr = "INPUT"; 2392 } else { 2393 capstr = NULL; 2394 } 2395 2396 if (capstr == NULL) 2397 return (AUDIO_WALK_CONTINUE); 2398 2399 sndstat_printf(oc, "%d: %s %s, %s (%s)\n", 2400 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2401 auclnt_get_dev_description(d), auclnt_get_dev_version(d), capstr); 2402 2403 return (AUDIO_WALK_CONTINUE); 2404 } 2405 2406 static int 2407 sndstat_mixer_walker(audio_dev_t *d, void *arg) 2408 { 2409 ossclient_t *oc = arg; 2410 unsigned cap; 2411 void *iter; 2412 const char *info; 2413 2414 cap = auclnt_get_dev_capab(d); 2415 2416 if ((cap & (AUDIO_CLIENT_CAP_PLAY|AUDIO_CLIENT_CAP_RECORD)) == 0) 2417 return (AUDIO_WALK_CONTINUE); 2418 2419 sndstat_printf(oc, "%d: %s %s, %s\n", 2420 auclnt_get_dev_number(d), auclnt_get_dev_name(d), 2421 auclnt_get_dev_description(d), auclnt_get_dev_version(d)); 2422 iter = NULL; 2423 while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) { 2424 sndstat_printf(oc, "\t%s\n", info); 2425 } 2426 return (AUDIO_WALK_CONTINUE); 2427 } 2428 2429 static int 2430 ossmix_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2431 { 2432 /* write on sndstat is a no-op */ 2433 _NOTE(ARGUNUSED(c)); 2434 _NOTE(ARGUNUSED(uio)); 2435 _NOTE(ARGUNUSED(cr)); 2436 2437 return (0); 2438 } 2439 2440 static int 2441 ossmix_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2442 { 2443 ossclient_t *oc; 2444 unsigned n; 2445 int rv; 2446 2447 _NOTE(ARGUNUSED(cr)); 2448 2449 if (uio->uio_resid == 0) { 2450 return (0); 2451 } 2452 2453 oc = auclnt_get_private(c); 2454 2455 mutex_enter(&oc->o_ss_lock); 2456 2457 if (oc->o_ss_off == 0) { 2458 2459 sndstat_printf(oc, "SunOS Audio Framework\n"); 2460 2461 sndstat_printf(oc, "\nAudio Devices:\n"); 2462 auclnt_walk_devs_by_number(sndstat_dev_walker, oc); 2463 2464 sndstat_printf(oc, "\nMixers:\n"); 2465 auclnt_walk_devs_by_number(sndstat_mixer_walker, oc); 2466 } 2467 2468 /* 2469 * For simplicity's sake, we implement a non-seekable device. We could 2470 * support seekability, but offsets would be rather meaningless between 2471 * changes. 2472 */ 2473 n = min(uio->uio_resid, (oc->o_ss_len - oc->o_ss_off)); 2474 2475 rv = uiomove(oc->o_ss_buf + oc->o_ss_off, n, UIO_READ, uio); 2476 if (rv != 0) { 2477 n = 0; 2478 } 2479 oc->o_ss_off += n; 2480 2481 if (n == 0) { 2482 /* 2483 * end-of-file reached... clear the sndstat buffer so that 2484 * subsequent reads will get the latest data. 2485 */ 2486 oc->o_ss_off = oc->o_ss_len = 0; 2487 } 2488 mutex_exit(&oc->o_ss_lock); 2489 return (rv); 2490 } 2491 2492 int 2493 oss_read(audio_client_t *c, struct uio *uio, cred_t *cr) 2494 { 2495 _NOTE(ARGUNUSED(cr)); 2496 2497 auclnt_clear_paused(auclnt_input_stream(c)); 2498 2499 return (auclnt_read(c, uio)); 2500 } 2501 2502 int 2503 oss_write(audio_client_t *c, struct uio *uio, cred_t *cr) 2504 { 2505 _NOTE(ARGUNUSED(cr)); 2506 2507 auclnt_clear_paused(auclnt_output_stream(c)); 2508 2509 return (auclnt_write(c, uio)); 2510 } 2511 2512 int 2513 oss_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp, 2514 struct pollhead **phpp) 2515 { 2516 return (auclnt_chpoll(c, events, anyyet, reventsp, phpp)); 2517 } 2518 2519 static struct audio_client_ops oss_ops = { 2520 "sound,dsp", 2521 oss_dev_init, 2522 oss_dev_fini, 2523 oss_open, 2524 oss_close, 2525 oss_read, 2526 oss_write, 2527 oss_ioctl, 2528 oss_chpoll, 2529 NULL, /* mmap */ 2530 oss_input, 2531 oss_output, 2532 NULL, /* notify */ 2533 NULL, /* drain */ 2534 }; 2535 2536 static struct audio_client_ops ossmix_ops = { 2537 "sound,mixer", 2538 NULL, 2539 NULL, 2540 ossmix_open, 2541 ossmix_close, 2542 ossmix_read, 2543 ossmix_write, 2544 ossmix_ioctl, 2545 NULL, /* chpoll */ 2546 NULL, /* mmap */ 2547 NULL, /* input */ 2548 NULL, /* output */ 2549 oss_notify, 2550 NULL, /* drain */ 2551 }; 2552 2553 /* nearly the same as ossxmix; different minor name helps devfsadm */ 2554 static struct audio_client_ops sndstat_ops = { 2555 "sound,sndstat", 2556 NULL, /* dev_init */ 2557 NULL, /* dev_fini */ 2558 ossmix_open, 2559 ossmix_close, 2560 ossmix_read, 2561 ossmix_write, 2562 ossmix_ioctl, 2563 NULL, /* chpoll */ 2564 NULL, /* mmap */ 2565 NULL, /* input */ 2566 NULL, /* output */ 2567 NULL, /* notify */ 2568 NULL, /* drain */ 2569 }; 2570 2571 void 2572 auimpl_oss_init(void) 2573 { 2574 auclnt_register_ops(AUDIO_MINOR_DSP, &oss_ops); 2575 auclnt_register_ops(AUDIO_MINOR_MIXER, &ossmix_ops); 2576 auclnt_register_ops(AUDIO_MINOR_SNDSTAT, &sndstat_ops); 2577 } 2578