"Fossies" - the Fresh Open Source Software Archive

Member "alsa-oss-1.1.8/alsa/mixer.c" (7 Jan 2019, 15525 Bytes) of package /linux/misc/alsa-oss-1.1.8.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mixer.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.0.28_vs_1.1.6.

    1 /*
    2  *  OSS -> ALSA compatibility layer
    3  *  Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
    4  *
    5  *
    6  *   This program is free software; you can redistribute it and/or modify
    7  *   it under the terms of the GNU General Public License as published by
    8  *   the Free Software Foundation; either version 2 of the License, or
    9  *   (at your option) any later version.
   10  *
   11  *   This program is distributed in the hope that it will be useful,
   12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  *   GNU General Public License for more details.
   15  *
   16  *   You should have received a copy of the GNU General Public License
   17  *   along with this program; if not, write to the Free Software
   18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
   19  *
   20  */
   21 
   22 #define _GNU_SOURCE
   23 
   24 #include <sys/types.h>
   25 #include <sys/time.h>
   26 #include <sys/stat.h>
   27 #include <sys/poll.h>
   28 #include <sys/select.h>
   29 #include <sys/mman.h>
   30 #include <stdarg.h>
   31 #include <unistd.h>
   32 #include <dlfcn.h>
   33 #include <stdio.h>
   34 #include <fcntl.h>
   35 #include <limits.h>
   36 #include <errno.h>
   37 #include <assert.h>
   38 #include <linux/soundcard.h>
   39 #include <alsa/asoundlib.h>
   40 
   41 #include "alsa-local.h"
   42 
   43 typedef struct _oss_mixer {
   44     int fileno;
   45     snd_mixer_t *mix;
   46     unsigned int modify_counter;
   47     snd_mixer_elem_t *elems[SOUND_MIXER_NRDEVICES];
   48     struct _oss_mixer *next;
   49 } oss_mixer_t;
   50 
   51 static oss_mixer_t *mixer_fds = NULL;
   52 
   53 static oss_mixer_t *look_for_fd(int fd)
   54 {
   55     oss_mixer_t *result = mixer_fds;
   56     while (result) {
   57         if (result->fileno == fd)
   58             return result;
   59         result = result->next;
   60     }
   61     return NULL;
   62 }
   63 
   64 static void insert_fd(oss_mixer_t *xfd)
   65 {
   66     xfd->next = mixer_fds;
   67     mixer_fds = xfd;
   68 }
   69 
   70 static void remove_fd(oss_mixer_t *xfd)
   71 {
   72     oss_mixer_t *result = mixer_fds, *prev = NULL;
   73     while (result) {
   74         if (result == xfd) {
   75             if (prev == NULL)
   76                 mixer_fds = xfd->next;
   77             else
   78                 prev->next = xfd->next;
   79             return;
   80         }
   81         prev = result;
   82         result = result->next;
   83     }
   84     assert(0);
   85 }
   86 
   87 static int oss_mixer_dev(const char *name, unsigned int index)
   88 {
   89     static struct {
   90         char *name;
   91         unsigned int index;
   92     } id[SOUND_MIXER_NRDEVICES] = {
   93         [SOUND_MIXER_VOLUME] = { "Master", 0 },
   94         [SOUND_MIXER_BASS] = { "Tone Control - Bass", 0 },
   95         [SOUND_MIXER_TREBLE] = { "Tone Control - Treble", 0 },
   96         [SOUND_MIXER_SYNTH] = { "Synth", 0 },
   97         [SOUND_MIXER_PCM] = { "PCM", 0 },
   98         [SOUND_MIXER_SPEAKER] = { "PC Speaker", 0 },
   99         [SOUND_MIXER_LINE] = { "Line", 0 },
  100         [SOUND_MIXER_MIC] = { "Mic", 0 },
  101         [SOUND_MIXER_CD] = { "CD", 0 },
  102         [SOUND_MIXER_IMIX] = { "Monitor Mix", 0 },
  103         [SOUND_MIXER_ALTPCM] = { "PCM", 1 },
  104         [SOUND_MIXER_RECLEV] = { "-- nothing --", 0 },
  105         [SOUND_MIXER_IGAIN] = { "Capture", 0 },
  106         [SOUND_MIXER_OGAIN] = { "Playback", 0 },
  107         [SOUND_MIXER_LINE1] = { "Aux", 0 },
  108         [SOUND_MIXER_LINE2] = { "Aux", 1 },
  109         [SOUND_MIXER_LINE3] = { "Aux", 2 },
  110         [SOUND_MIXER_DIGITAL1] = { "Digital", 0 },
  111         [SOUND_MIXER_DIGITAL2] = { "Digital", 1 },
  112         [SOUND_MIXER_DIGITAL3] = { "Digital", 2 },
  113         [SOUND_MIXER_PHONEIN] = { "Phone", 0 },
  114         [SOUND_MIXER_PHONEOUT] = { "Phone", 1 },
  115         [SOUND_MIXER_VIDEO] = { "Video", 0 },
  116         [SOUND_MIXER_RADIO] = { "Radio", 0 },
  117         [SOUND_MIXER_MONITOR] = { "Monitor", 0 },
  118     };
  119     unsigned int k;
  120     for (k = 0; k < SOUND_MIXER_NRDEVICES; ++k) {
  121         if (index == id[k].index &&
  122             strcmp(name, id[k].name) == 0)
  123             return k;
  124     }
  125     return -1;
  126 }
  127 
  128 int lib_oss_mixer_close(int fd)
  129 {
  130     int err, result = 0;
  131     oss_mixer_t *mixer = look_for_fd(fd);
  132     err = snd_mixer_close(mixer->mix);
  133     if (err < 0)
  134         result = err;
  135     remove_fd(mixer);
  136     free(mixer);
  137     if (result < 0) {
  138         errno = -result;
  139         result = -1;
  140     }
  141     close(fd);
  142     DEBUG("close(%d) -> %d", fd, result);
  143     if (result < 0)
  144         DEBUG("(errno=%d)\n", errno);
  145     else
  146         DEBUG("\n");
  147     return 0;
  148 }
  149 
  150 static int oss_mixer_elem_callback(snd_mixer_elem_t *elem, unsigned int mask)
  151 {
  152     oss_mixer_t *mixer = snd_mixer_elem_get_callback_private(elem);
  153     if (mask == SND_CTL_EVENT_MASK_REMOVE) {
  154         int idx = oss_mixer_dev(snd_mixer_selem_get_name(elem),
  155                     snd_mixer_selem_get_index(elem));
  156         if (idx >= 0)
  157             mixer->elems[idx] = 0;
  158         return 0;
  159     }
  160     if (mask & SND_CTL_EVENT_MASK_VALUE) {
  161         mixer->modify_counter++;
  162     }
  163     return 0;
  164 }
  165 
  166 static int oss_mixer_callback(snd_mixer_t *mixer, unsigned int mask, 
  167                   snd_mixer_elem_t *elem)
  168 {
  169     if (mask & SND_CTL_EVENT_MASK_ADD) {
  170         oss_mixer_t *mix = snd_mixer_get_callback_private(mixer);
  171         int idx = oss_mixer_dev(snd_mixer_selem_get_name(elem),
  172                     snd_mixer_selem_get_index(elem));
  173         if (idx >= 0) {
  174             mix->elems[idx] = elem;
  175             snd_mixer_selem_set_playback_volume_range(elem, 0, 100);
  176             snd_mixer_selem_set_capture_volume_range(elem, 0, 100);
  177             snd_mixer_elem_set_callback(elem, oss_mixer_elem_callback);
  178             snd_mixer_elem_set_callback_private(elem, mix);
  179         }
  180     }
  181     return 0;
  182 }
  183 
  184 static int oss_mixer_open(int card, int device, int oflag, mode_t mode ATTRIBUTE_UNUSED)
  185 {
  186     oss_mixer_t *mixer;
  187     int fd = -1;
  188     int result;
  189     char name[64];
  190 
  191     char *s = getenv("ALSA_OSS_DEBUG");
  192     if (s) {
  193         alsa_oss_debug = 1;
  194         if (alsa_oss_debug_out == NULL) {
  195             if (snd_output_stdio_attach(&alsa_oss_debug_out, stderr, 0) < 0)
  196                 alsa_oss_debug_out = NULL;
  197         }
  198     }
  199     switch (device) {
  200     case OSS_DEVICE_MIXER:
  201         sprintf(name, "mixer%d", card);
  202         break;
  203     case OSS_DEVICE_AMIXER:
  204         sprintf(name, "amixer%d", card);
  205         break;
  206     default:
  207         errno = ENODEV;
  208         return -1;
  209     }
  210     switch (oflag & O_ACCMODE) {
  211     case O_RDONLY:
  212     case O_WRONLY:
  213     case O_RDWR:
  214         break;
  215     default:
  216         errno = EINVAL;
  217         return -1;
  218     }
  219     fd = open("/dev/null", oflag & O_ACCMODE);
  220     assert(fd >= 0);
  221     mixer = calloc(1, sizeof(oss_mixer_t));
  222     if (!mixer) {
  223         errno = -ENOMEM;
  224         return -1;
  225     }
  226     result = snd_mixer_open(&mixer->mix, 0);
  227     if (result < 0)
  228         goto _error;
  229     result = snd_mixer_attach(mixer->mix, name);
  230     if (result < 0) {
  231         /* try to open the default mixer as fallback */
  232         if (card == 0)
  233             strcpy(name, "default");
  234         else
  235             sprintf(name, "hw:%d", card);
  236         result = snd_mixer_attach(mixer->mix, name);
  237         if (result < 0)
  238             goto _error1;
  239     }
  240     result = snd_mixer_selem_register(mixer->mix, NULL, NULL);
  241     if (result < 0)
  242         goto _error1;
  243     snd_mixer_set_callback(mixer->mix, oss_mixer_callback);
  244     snd_mixer_set_callback_private(mixer->mix, mixer);
  245     result = snd_mixer_load(mixer->mix);
  246     if (result < 0)
  247         goto _error1;
  248     mixer->fileno = fd;
  249     insert_fd(mixer);
  250     return fd;
  251  _error1:
  252     snd_mixer_close(mixer->mix);
  253  _error:
  254     close(fd);
  255     errno = -result;
  256     return -1;
  257 }
  258 
  259 static int oss_mixer_read_recsrc(oss_mixer_t *mixer, unsigned int *ret)
  260 {
  261     unsigned int mask = 0;
  262     unsigned int k;
  263     int err = 0;
  264     for (k = 0; k < SOUND_MIXER_NRDEVICES; k++) {
  265         snd_mixer_elem_t *elem = mixer->elems[k];
  266         if (elem && 
  267             snd_mixer_selem_has_capture_switch(elem)) {
  268             int sw;
  269             err = snd_mixer_selem_get_capture_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, &sw);
  270             if (err < 0)
  271                 break;
  272             if (sw)
  273                 mask |= 1 << k;
  274         }
  275     }
  276     *ret = mask;
  277     return err;
  278 }
  279 
  280 
  281 int lib_oss_mixer_ioctl(int fd, unsigned long cmd, ...)
  282 {
  283     int err = 0;
  284     va_list args;
  285     void *arg;
  286     oss_mixer_t *mixer = look_for_fd(fd);
  287     snd_mixer_t *mix;
  288     unsigned int dev;
  289 
  290     if (mixer == NULL) {
  291         errno = ENODEV;
  292         return -1;
  293     }
  294     mix = mixer->mix;
  295     va_start(args, cmd);
  296     arg = va_arg(args, void *);
  297     va_end(args);
  298     DEBUG("ioctl(%d, ", fd);
  299     switch (cmd) {
  300     case OSS_GETVERSION:
  301         *(int*)arg = SOUND_VERSION;
  302         DEBUG("OSS_GETVERSION, %p) -> [%d]\n", arg, *(int*)arg);
  303         break;
  304     case SOUND_MIXER_INFO:
  305     {
  306         mixer_info *info = arg;
  307         snd_mixer_handle_events(mix);
  308         strcpy(info->id, "alsa-oss");
  309         strcpy(info->name, "alsa-oss");
  310         info->modify_counter = mixer->modify_counter;
  311         DEBUG("SOUND_MIXER_INFO, %p) -> {%s, %s, %d}\n", info, info->id, info->name, info->modify_counter);
  312         break;
  313     }
  314     case SOUND_OLD_MIXER_INFO:
  315     {
  316         _old_mixer_info *info = arg;
  317         strcpy(info->id, "alsa-oss");
  318         strcpy(info->name, "alsa-oss");
  319         DEBUG("SOUND_OLD_MIXER_INFO, %p) -> {%s, %s}\n", info, info->id, info->name);
  320         break;
  321     }
  322     case SOUND_MIXER_WRITE_RECSRC:
  323     {
  324         unsigned int k, mask = *(unsigned int *) arg;
  325         unsigned int old;
  326         int excl = 0;
  327         DEBUG("SOUND_MIXER_WRITE_RECSRC, %p) -> [%x]", arg, mask);
  328         err = oss_mixer_read_recsrc(mixer, &old);
  329         if (err < 0)
  330             break;
  331         for (k = 0; k < SOUND_MIXER_NRDEVICES; k++) {
  332             snd_mixer_elem_t *elem = mixer->elems[k];
  333             if (elem && 
  334                 snd_mixer_selem_has_capture_switch(elem)) {
  335                 if (!excl &&
  336                     snd_mixer_selem_has_capture_switch_exclusive(elem) &&
  337                     mask & ~old) {
  338                     mask &= ~old;
  339                     excl = 1;
  340                 }
  341                 err = snd_mixer_selem_set_capture_switch_all(elem, !!(mask & 1 << k));
  342                 if (err < 0)
  343                     break;
  344             }
  345         }
  346         if (err < 0)
  347             break;
  348         goto __read_recsrc;
  349     }
  350     case SOUND_MIXER_READ_RECSRC:
  351     {
  352         unsigned int mask;
  353         DEBUG("SOUND_MIXER_READ_RECSRC, %p) ->", arg);
  354     __read_recsrc:
  355         err = oss_mixer_read_recsrc(mixer, &mask);
  356         *(int *)arg = mask;
  357         DEBUG(" [%x]\n", mask);
  358         break;
  359     }
  360     case SOUND_MIXER_READ_DEVMASK:
  361     {
  362         int k, mask = 0;
  363         for (k = 0; k < SOUND_MIXER_NRDEVICES; k++) {
  364             snd_mixer_elem_t *elem = mixer->elems[k];
  365             if (elem && 
  366                 (snd_mixer_selem_has_playback_volume(elem) ||
  367                  snd_mixer_selem_has_capture_volume(elem)))
  368                 mask |= 1 << k;
  369         }
  370         *(int *)arg = mask;
  371         DEBUG("SOUND_MIXER_READ_DEVMASK, %p) -> [%x]\n", arg, mask);
  372         break;
  373     }
  374     case SOUND_MIXER_READ_RECMASK:
  375     {
  376         int k, mask = 0;
  377         for (k = 0; k < SOUND_MIXER_NRDEVICES; k++) {
  378             snd_mixer_elem_t *elem = mixer->elems[k];
  379             if (elem &&
  380                 snd_mixer_selem_has_capture_switch(elem))
  381                 mask |= 1 << k;
  382         }
  383         *(int *)arg = mask;
  384         DEBUG("SOUND_MIXER_READ_RECMASK, %p) -> [%x]\n", arg, mask);
  385         break;
  386     }
  387     case SOUND_MIXER_READ_STEREODEVS:
  388     {
  389         int k, mask = 0;
  390         for (k = 0; k < SOUND_MIXER_NRDEVICES; k++) {
  391             snd_mixer_elem_t *elem = mixer->elems[k];
  392             if (elem && 
  393                 snd_mixer_selem_has_playback_volume(elem) &&
  394                 !snd_mixer_selem_is_playback_mono(elem))
  395                 mask |= 1 << k;
  396         }
  397         *(int *)arg = mask;
  398         DEBUG("SOUND_MIXER_READ_STEREODEVS, %p) -> [%x]\n", arg, mask);
  399         break;
  400     }
  401     case SOUND_MIXER_READ_CAPS:
  402     {
  403         int k;
  404         *(int *)arg = 0;
  405         for (k = 0; k < SOUND_MIXER_NRDEVICES; k++) {
  406             snd_mixer_elem_t *elem = mixer->elems[k];
  407             if (elem && 
  408                 snd_mixer_selem_has_capture_switch_exclusive(elem)) {
  409                 * (int*) arg = SOUND_CAP_EXCL_INPUT;
  410                 break;
  411             }
  412         }
  413         DEBUG("SOUND_MIXER_READ_CAPS, %p) -> [%x]\n", arg, *(int*) arg);
  414         break;
  415     }
  416     default:
  417         if (cmd >= MIXER_WRITE(0) && cmd < MIXER_WRITE(SOUND_MIXER_NRDEVICES)) {
  418             snd_mixer_elem_t *elem;
  419             long lvol, rvol;
  420             dev = cmd & 0xff;
  421             lvol = *(int *)arg & 0xff;
  422             if (lvol > 100)
  423                 lvol = 100;
  424             rvol = (*(int *)arg >> 8) & 0xff;
  425             if (rvol > 100)
  426                 rvol = 100;
  427             DEBUG("SOUND_MIXER_WRITE[%d], %p) -> {%ld, %ld}", dev, arg, lvol, rvol);
  428             elem = mixer->elems[dev];
  429             if (!elem) {
  430                 err = -EINVAL;
  431                 break;
  432             }
  433             if (snd_mixer_selem_has_playback_volume(elem)) {
  434                 err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, lvol);
  435                 if (err < 0) 
  436                     break;
  437                 if (snd_mixer_selem_is_playback_mono(elem)) {
  438                     if (snd_mixer_selem_has_playback_switch(elem))
  439                         err = snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, lvol != 0);
  440                     if (err < 0) 
  441                         break;
  442                 } else {
  443                     err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, rvol);
  444                     if (err < 0) 
  445                         break;
  446                     if (snd_mixer_selem_has_playback_switch(elem)) {
  447                         if (snd_mixer_selem_has_playback_switch_joined(elem))
  448                             err = snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, lvol != 0 || rvol != 0);
  449                         else {
  450                             err = snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, lvol != 0);
  451                             if (err < 0) 
  452                                 break;
  453                             err = snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, rvol != 0);
  454                             if (err < 0) 
  455                                 break;
  456                         }
  457                     }
  458                 }
  459             }
  460             if (snd_mixer_selem_has_capture_volume(elem)) {
  461                 err = snd_mixer_selem_set_capture_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, lvol);
  462                 if (err < 0) 
  463                     break;
  464                 if (!snd_mixer_selem_is_capture_mono(elem)) {
  465                     err = snd_mixer_selem_set_capture_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, rvol);
  466                     if (err < 0) 
  467                         break;
  468                 }
  469             }
  470             goto __read;
  471         }
  472         if (cmd >= MIXER_READ(0) && cmd < MIXER_READ(SOUND_MIXER_NRDEVICES)) {
  473             snd_mixer_elem_t *elem;
  474             long lvol, rvol;
  475             int sw;
  476             dev = cmd & 0xff;
  477             DEBUG("SOUND_MIXER_READ[%d], %p) ->", dev, arg);
  478         __read:
  479             elem = mixer->elems[dev];
  480             if (!elem) {
  481                 err = -EINVAL;
  482                 break;
  483             }
  484             if (snd_mixer_selem_has_playback_volume(elem)) {
  485                 if (snd_mixer_selem_has_playback_switch(elem)) {
  486                     err = snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, &sw);
  487                     if (err < 0)
  488                         break;
  489                 } else {
  490                     sw = 1;
  491                 }
  492                 if (sw) {
  493                     err = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &lvol);
  494                     if (err < 0) 
  495                         break;
  496                 } else
  497                     lvol = 0;
  498                 if (snd_mixer_selem_is_playback_mono(elem)) {
  499                     rvol = lvol;
  500                 } else {
  501                     if (snd_mixer_selem_has_playback_switch(elem)) {
  502                         err = snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, &sw);
  503                         if (err < 0)
  504                             break;
  505                     } else {
  506                         sw = 1;
  507                     }
  508                     if (sw) {
  509                         err = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &rvol);
  510                         if (err < 0) 
  511                             break;
  512                     } else
  513                         rvol = 0;
  514                 }
  515                 * (int*) arg = lvol | (rvol << 8);
  516                 DEBUG("{%ld, %ld}\n", lvol, rvol);
  517                 break;
  518             }
  519             if (snd_mixer_selem_has_capture_volume(elem)) {
  520                 err = snd_mixer_selem_get_capture_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &lvol);
  521                 if (err < 0) 
  522                     break;
  523                 if (!snd_mixer_selem_is_capture_mono(elem)) {
  524                     err = snd_mixer_selem_get_capture_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &rvol);
  525                     if (err < 0) 
  526                         break;
  527                 }
  528                 * (int*) arg = lvol | (rvol << 8);
  529                 DEBUG("{%ld, %ld}\n", lvol, rvol);
  530                 break;
  531             }
  532         }
  533         DEBUG("%lx, %p)\n", cmd, arg);
  534         err = -ENXIO;
  535         break;
  536     }
  537     if (err >= 0)
  538         return 0;
  539     errno = -err;
  540     return -1;
  541 }
  542 
  543 static void error_handler(const char *file ATTRIBUTE_UNUSED,
  544               int line ATTRIBUTE_UNUSED,
  545               const char *func ATTRIBUTE_UNUSED,
  546               int err ATTRIBUTE_UNUSED,
  547               const char *fmt ATTRIBUTE_UNUSED,
  548               ...)
  549 {
  550     /* suppress the error message from alsa-lib */
  551 }
  552 
  553 int lib_oss_mixer_open(const char *file, int oflag, ...)
  554 {
  555     int result;
  556     int minor, card, device;
  557     struct stat s;
  558     mode_t mode;
  559     va_list args;
  560     va_start(args, oflag);
  561     mode = va_arg(args, mode_t);
  562     va_end(args);
  563     result = stat(file, &s);
  564     if (result < 0) {
  565         if (!strncmp(file, "/dev/mixer", 10))
  566             minor = (atoi(file + 10) << 4) | OSS_DEVICE_MIXER;
  567         else if (!strncmp(file, "/dev/amixer", 11))
  568             minor = (atoi(file + 11) << 4) | OSS_DEVICE_AMIXER;
  569         else if (!strncmp(file, "/dev/sound/mixer", 16))
  570             minor = (atoi(file + 16) << 4) | OSS_DEVICE_MIXER;
  571         else if (!strncmp(file, "/dev/sound/amixer", 17))
  572             minor = (atoi(file + 17) << 4) | OSS_DEVICE_AMIXER;
  573         else {
  574             errno = ENOENT;
  575             return -1;
  576         }
  577     } else {
  578         if (!S_ISCHR(s.st_mode) || ((s.st_rdev >> 8) & 0xff) != OSS_MAJOR) {
  579             errno = ENOENT;
  580             return -1;
  581         }
  582         minor = s.st_rdev & 0xff;
  583     }
  584     if (! alsa_oss_debug)
  585         snd_lib_error_set_handler(error_handler);
  586     card = minor >> 4;
  587     device = minor & 0x0f;
  588     switch (device) {
  589     case OSS_DEVICE_MIXER:
  590     case OSS_DEVICE_AMIXER:
  591         result = oss_mixer_open(card, device, oflag, mode);
  592         DEBUG("open(\"%s\", %d, %d) -> %d\n", file, oflag, mode, result);
  593         return result;
  594     default:
  595         errno = ENOENT;
  596         return -1;
  597     }
  598 }