~ubuntu-branches/ubuntu/vivid/oss4/vivid

« back to all changes in this revision

Viewing changes to kernel/framework/mixer/oss_mixer_core.c

  • Committer: Bazaar Package Importer
  • Author(s): Romain Beauxis, Samuel Thibault, Romain Beauxis, Sebastien NOEL
  • Date: 2011-06-14 10:06:56 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110614100656-cx4oc7u426zn812z
Tags: 4.2-build2004-1
[ Samuel Thibault ]
* debian/control: Add liboss4-salsa2, liboss4-salsa-dev and
  liboss4-salsa-asound2 packages, equivalent to (and will replace) those from
  the oss-libsalsa package (Closes: #589127).
* debian/patches/liboss4-salsa.patch: New patch to rename libsalsa into
  liboss4-salsa to avoid conflicts in the archive for no good reason.
* debian/rules: Make in libOSSlib and libsalsa.
* debian/liboss4-salsa-dev.install, debian/liboss4-salsa2.install,
  debian/liboss4-salsa-asound2.links, debian/liboss4-salsa-dev.links:
  Install liboss4-salsa libraries like was done in the oss-libsalsa package.
* include-alsa: Add a copy of ALSA 1.0.5 headers: Cf ALSA_1.0.* symbols in
  libsalsa, this is the roughly supported version.
* debian/copyright: Update for new include-alsa files.
* alsa.pc: New file for compatibility with libasound-dev.
* debian/control:
  - Add Vcs-Browser and Vcs-Svn fields.
  - Use linux-any instead of the list of Linux archs (Closes: #604679).
  - Make dkms dependency linux-any only.
* debian/patches/hurd_iot.patch: New patch to fix soundcard.h usage in
  libsalsa on hurd-i386.
* debian/patches/libsalsa_fixes.patch: New patch to fix some printf usages
  and ioctl declaration in libsalsa.
* debian/patches/no_EBADE.patch: New patch to cope with hurd-i386 not having
  EBADE.
* debian/patches/CFLAGS.patch: New patch to make oss4 take debian/rules
  CFLAGS into account.
* debian/patches/snd_asoundlib_version.patch: New patch to add
  snd_asoundlib_version().
* debian/patches/generic_srccconf.patch: New patch to fix source
  configuration on unknown archs.

[ Romain Beauxis ]
* Fixed README.Debian to only mention dkms' modules.
* Switch to dpkg-source 3.0 (quilt) format
* Added DM-Upload-Allowed: yes

[ Sebastien NOEL ]
* New upstream release (Closes: #595298, #619272).
* Fix typo in initscript (Closes: #627149).
* debian/control: adjust linux-headers dependencies (Closes: #628879).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Purpose: OSS mixer core.
 
3
 * Copyright (C) 4Front Technologies, 2002-2004. All rights reserved.
 
4
 *
 
5
 * Description:
 
6
 */
 
7
/*
 
8
 *
 
9
 * This file is part of Open Sound System.
 
10
 *
 
11
 * Copyright (C) 4Front Technologies 1996-2008.
 
12
 *
 
13
 * This this source file is released under GPL v2 license (no other versions).
 
14
 * See the COPYING file included in the main directory of this source
 
15
 * distribution for the license terms and conditions.
 
16
 *
 
17
 */
 
18
 
 
19
#include <oss_config.h>
 
20
#include <midi_core.h>
 
21
#include <stdarg.h>
 
22
oss_mutex_t oss_timing_mutex;
 
23
 
 
24
char *oss_license_string = OSS_LICENSE;
 
25
 
 
26
#ifdef DO_TIMINGS
 
27
static int timing_is_active = 0; /* 1=The readtimings utility has been active */
 
28
#endif
 
29
 
 
30
void *mixer_devs_p = NULL;
 
31
/*
 
32
 * Mixer device list
 
33
 */
 
34
mixer_operations_t **mixer_devs = NULL;
 
35
int num_mixers = 0;
 
36
int mixer_port_number = 0;
 
37
int current_mixer_card = -1;
 
38
 
 
39
/*
 
40
 * mix_cvt is used for scaling mixer levels by various drivers.
 
41
 */
 
42
char mix_cvt[101] = {
 
43
  0, 0, 3, 7, 10, 13, 16, 19, 21, 23, 26, 28, 30, 32, 34, 35, 37, 39, 40, 42,
 
44
  43, 45, 46, 47, 49, 50, 51, 52, 53, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
 
45
  65,
 
46
  65, 66, 67, 68, 69, 70, 70, 71, 72, 73, 73, 74, 75, 75, 76, 77, 77, 78, 79,
 
47
  79,
 
48
  80, 81, 81, 82, 82, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90,
 
49
  90,
 
50
  91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 96, 97, 97, 98, 98, 98, 99,
 
51
  99,
 
52
  100
 
53
};
 
54
 
 
55
static int
 
56
get_mixer_info (int dev, ioctl_arg arg)
 
57
{
 
58
  mixer_info *info = (mixer_info *) arg;
 
59
 
 
60
  memset(info, 0, sizeof(*info));
 
61
 
 
62
  if (dev < 0 || dev >= num_mixers)
 
63
    return OSS_ENXIO;
 
64
 
 
65
  strcpy (info->id, mixer_devs[dev]->id);
 
66
  strncpy (info->name, mixer_devs[dev]->name, 32);
 
67
  info->name[31] = '\0';
 
68
  info->modify_counter = mixer_devs[dev]->modify_counter;
 
69
 
 
70
  return 0;
 
71
}
 
72
 
 
73
/*
 
74
 * Legacy mixer handling
 
75
 */
 
76
 
 
77
int
 
78
oss_legacy_mixer_ioctl (int mixdev, int audiodev, unsigned int cmd,
 
79
                        ioctl_arg arg)
 
80
{
 
81
  int ret;
 
82
 
 
83
#ifdef DO_TIMINGS
 
84
    oss_timing_printf ("oss_legacy_mixer_ioctl(%d/%d, %08x) entered", mixdev,
 
85
             audiodev, cmd);
 
86
#endif
 
87
 
 
88
  if (!(cmd & SIOC_OUT) && !(cmd & SIOC_IN))
 
89
    return OSS_EINVAL;
 
90
 
 
91
  if (arg == 0)
 
92
    return OSS_EINVAL;
 
93
 
 
94
  if (((cmd >> 8) & 0xff) != 'M')       /* Not a mixer ioctl */
 
95
    return OSS_EINVAL;
 
96
 
 
97
  if (mixdev < 0 || mixdev >= num_mixers)
 
98
    {
 
99
      cmn_err (CE_WARN, "Bad mixer device %d\n", mixdev);
 
100
      return OSS_EIO;
 
101
    }
 
102
 
 
103
  if (cmd == SOUND_MIXER_INFO)
 
104
    return get_mixer_info (mixdev, arg);
 
105
 
 
106
  if (!mixer_devs[mixdev]->enabled || mixer_devs[mixdev]->unloaded)
 
107
    return OSS_ENXIO;
 
108
 
 
109
  if (mixer_devs[mixdev]->d->ioctl == NULL)
 
110
    return OSS_EINVAL;
 
111
 
 
112
  if (IOC_IS_OUTPUT (cmd))
 
113
    mixer_devs[mixdev]->modify_counter++;
 
114
 
 
115
  ret = mixer_devs[mixdev]->d->ioctl (mixdev, audiodev, cmd, arg);
 
116
 
 
117
  return ret;
 
118
}
 
119
 
 
120
/*
 
121
 * Handling of initial mixer volumes
 
122
 */
 
123
 
 
124
static int muted_mixer_levels[32] = {0};
 
125
 
 
126
static int default_mixer_levels[32] = {
 
127
  0x3232,                       /* Master Volume */
 
128
  0x3232,                       /* Bass */
 
129
  0x3232,                       /* Treble */
 
130
  0x4b4b,                       /* FM */
 
131
  0x3232,                       /* PCM */
 
132
  0x1515,                       /* PC Speaker */
 
133
  0x2020,                       /* Ext Line */
 
134
  0x2020,                       /* Mic */
 
135
  0x4b4b,                       /* CD */
 
136
  0x0000,                       /* Recording monitor */
 
137
  0x4b4b,                       /* Second PCM */
 
138
  0x4b4b,                       /* Recording level */
 
139
  0x4b4b,                       /* Input gain */
 
140
  0x4b4b,                       /* Output gain */
 
141
  0x2020,                       /* Line1 */
 
142
  0x2020,                       /* Line2 */
 
143
  0x1515                        /* Line3 (usually line in) */
 
144
};
 
145
 
 
146
/*
 
147
 * Table for configurable mixer volume handling
 
148
 */
 
149
static mixer_vol_table mixer_vols[MAX_MIXER_DEV];
 
150
static int num_mixer_volumes = 0;
 
151
 
 
152
int *
 
153
load_mixer_volumes (char *name, int *levels, int present)
 
154
{
 
155
  int i, n;
 
156
  extern int mixer_muted;
 
157
 
 
158
  if (mixer_muted)              /* Config setting from osscore.conf */
 
159
     return muted_mixer_levels;
 
160
 
 
161
  if (levels == NULL)
 
162
    levels = default_mixer_levels;
 
163
 
 
164
  for (i = 0; i < num_mixer_volumes; i++)
 
165
    if (strcmp (name, mixer_vols[i].name) == 0)
 
166
      {
 
167
        if (present)
 
168
          mixer_vols[i].num = i;
 
169
        return mixer_vols[i].levels;
 
170
      }
 
171
 
 
172
  if (num_mixer_volumes >= MAX_MIXER_DEV)
 
173
    {
 
174
      cmn_err (CE_WARN, "Too many mixers (%s/%d/%d)\n",
 
175
               name, num_mixer_volumes, MAX_MIXER_DEV);
 
176
      return levels;
 
177
    }
 
178
 
 
179
  n = num_mixer_volumes++;
 
180
 
 
181
  strcpy (mixer_vols[n].name, name);
 
182
 
 
183
  if (present)
 
184
    mixer_vols[n].num = n;
 
185
  else
 
186
    mixer_vols[n].num = -1;
 
187
 
 
188
  for (i = 0; i < 32; i++)
 
189
    mixer_vols[n].levels[i] = levels[i];
 
190
  return mixer_vols[n].levels;
 
191
}
 
192
 
 
193
/*
 
194
 * Mixer "extension" handling
 
195
 */
 
196
 
 
197
static int
 
198
oss_mixer_ext_info (oss_mixext * ent)
 
199
{
 
200
 
 
201
  int dev, ctrl;
 
202
  int extnr;
 
203
 
 
204
  if (ent == NULL)
 
205
    return OSS_EFAULT;
 
206
 
 
207
  if (ent->dev < 0 || ent->dev >= num_mixers)
 
208
    return OSS_ENXIO;
 
209
 
 
210
  dev = ent->dev;
 
211
  if (!mixer_devs[dev]->enabled || mixer_devs[dev]->unloaded)
 
212
    return OSS_ENXIO;
 
213
  touch_mixer (dev);
 
214
 
 
215
  ctrl = ent->ctrl;
 
216
  if (ent->ctrl < 0 || ent->ctrl >= mixer_devs[dev]->nr_ext)
 
217
    return OSS_EIDRM;
 
218
  extnr = ent->ctrl;
 
219
 
 
220
  memcpy ((char *) ent, (char *) &mixer_devs[dev]->extensions[extnr].ext,
 
221
          sizeof (*ent));
 
222
 
 
223
  switch (ent->type)
 
224
    {
 
225
    case MIXT_MONOPEAK:
 
226
    case MIXT_STEREOPEAK:
 
227
    case MIXT_MONOVU:
 
228
    case MIXT_STEREOVU:
 
229
      /* Peak meters will need to be polled */
 
230
      ent->flags |= MIXF_POLL;
 
231
      break;
 
232
    }
 
233
 
 
234
/*
 
235
 * Read-only controls are likely to change their value spontaneously so
 
236
 * they should be polled.
 
237
 */
 
238
  if (!(ent->flags & MIXF_WRITEABLE))
 
239
     ent->flags |= MIXF_POLL;
 
240
 
 
241
  ent->ctrl = ctrl;
 
242
  return 0;
 
243
}
 
244
 
 
245
static int
 
246
mixer_ext_get_enuminfo (oss_mixer_enuminfo * ent)
 
247
{
 
248
 
 
249
  int dev, ctrl;
 
250
 
 
251
  if (ent == NULL)
 
252
    return OSS_EFAULT;
 
253
 
 
254
  dev = ent->dev;
 
255
  ctrl = ent->ctrl;
 
256
  memset (ent, 0, sizeof (*ent));
 
257
 
 
258
  if (dev < 0 || dev >= num_mixers)
 
259
    {
 
260
      return OSS_ENXIO;
 
261
    }
 
262
 
 
263
  touch_mixer (dev);
 
264
 
 
265
  if (ctrl < 0 || ctrl >= mixer_devs[dev]->nr_ext)
 
266
    {
 
267
      return OSS_EIDRM;
 
268
    }
 
269
 
 
270
  if (mixer_devs[dev]->extensions[ctrl].enum_info == NULL)
 
271
    {
 
272
      return OSS_EIO;
 
273
    }
 
274
 
 
275
  memcpy ((char *) ent,
 
276
          (char *) mixer_devs[dev]->extensions[ctrl].enum_info,
 
277
          sizeof (*ent));
 
278
  ent->ctrl = ctrl;
 
279
  return 0;
 
280
}
 
281
 
 
282
static int
 
283
mixer_ext_get_description (oss_mixer_enuminfo * ent)
 
284
{
 
285
 
 
286
  int dev, ctrl;
 
287
  char *s;
 
288
 
 
289
  if (ent == NULL)
 
290
    return OSS_EFAULT;
 
291
 
 
292
  dev = ent->dev;
 
293
  ctrl = ent->ctrl;
 
294
  memset (ent, 0, sizeof (*ent));
 
295
 
 
296
  if (dev < 0 || dev >= num_mixers)
 
297
    {
 
298
      return OSS_ENXIO;
 
299
    }
 
300
 
 
301
  touch_mixer (dev);
 
302
 
 
303
  if (ctrl < 0 || ctrl >= mixer_devs[dev]->nr_ext)
 
304
    {
 
305
      return OSS_EIDRM;
 
306
    }
 
307
 
 
308
  if (mixer_devs[dev]->extensions[ctrl].description == NULL)
 
309
    {
 
310
      return OSS_EIO;
 
311
    }
 
312
 
 
313
  s = mixer_devs[dev]->extensions[ctrl].description;
 
314
 
 
315
  strncpy (ent->strings, s, sizeof (ent->strings));
 
316
  ent->strings [sizeof (ent->strings) - 1] = '\0';
 
317
  ent->ctrl = ctrl;
 
318
  return 0;
 
319
}
 
320
 
 
321
int
 
322
mixer_ext_set_strings (int dev, int ctl, const char *s, int version)
 
323
{
 
324
/*
 
325
 * Note! The version parameter should usually be set to 0. However if the
 
326
 *       value set can change dynamically then it must be initially set to 1
 
327
 *       and later incremented every time the value set changes.
 
328
 *       This tells the applications to poll for updated values.
 
329
 */
 
330
  static oss_mixer_enuminfo ent;
 
331
 
 
332
  memset (&ent, 0, sizeof (ent));
 
333
  ent.dev = dev;
 
334
  ent.ctrl = ctl;
 
335
  ent.version = version;
 
336
  ent.nvalues = 0;
 
337
  strcpy (ent.strings, s);
 
338
  return mixer_ext_set_enum (&ent);
 
339
}
 
340
 
 
341
static int
 
342
rebuild_list (oss_mixer_enuminfo * ent)
 
343
{
 
344
  int i, n, l;
 
345
 
 
346
  n = 1;
 
347
  ent->nvalues = 0;
 
348
  ent->strindex[0] = 0;
 
349
  l = strlen (ent->strings);
 
350
 
 
351
  for (i = 0; i < l; i++)
 
352
    if (n < OSS_ENUM_MAXVALUE)
 
353
      {
 
354
        if (ent->strings[i] == ' ')
 
355
          {
 
356
            ent->strindex[n++] = i + 1;
 
357
            ent->strings[i] = 0;
 
358
          }
 
359
      }
 
360
 
 
361
  ent->nvalues = n;
 
362
  return 0;
 
363
}
 
364
 
 
365
int
 
366
mixer_ext_set_enum (oss_mixer_enuminfo * ent)
 
367
{
 
368
  int dev;
 
369
  int extnr;
 
370
 
 
371
  if (ent == NULL)
 
372
    return OSS_EFAULT;
 
373
 
 
374
  if (ent->dev < 0 || ent->dev >= num_mixers)
 
375
    return OSS_ENXIO;
 
376
 
 
377
  dev = ent->dev;
 
378
  touch_mixer (dev);
 
379
 
 
380
  if (ent->ctrl < 0 || ent->ctrl >= mixer_devs[dev]->nr_ext)
 
381
    return OSS_EIDRM;
 
382
  extnr = ent->ctrl;
 
383
 
 
384
  if (mixer_devs[dev]->extensions[extnr].enum_info == NULL)
 
385
    mixer_devs[dev]->extensions[extnr].enum_info =
 
386
      PMALLOC (mixer_devs[dev]->osdev, sizeof (*ent));
 
387
 
 
388
  if (mixer_devs[dev]->extensions[extnr].enum_info == NULL)
 
389
    return OSS_EIO;
 
390
 
 
391
  memcpy ((char *) mixer_devs[dev]->extensions[extnr].enum_info,
 
392
          (char *) ent, sizeof (*ent));
 
393
 
 
394
  ent = mixer_devs[dev]->extensions[extnr].enum_info;
 
395
 
 
396
  if (ent->nvalues <= 0)
 
397
    return rebuild_list (ent);
 
398
 
 
399
  if (ent->nvalues >= OSS_ENUM_MAXVALUE)
 
400
    {
 
401
      mixer_devs[dev]->extensions[extnr].enum_info = NULL;
 
402
      return OSS_EIO;
 
403
    }
 
404
 
 
405
  return 0;
 
406
}
 
407
 
 
408
int
 
409
mixer_ext_set_description (int dev, int ctrl, const char *desc)
 
410
{
 
411
  int l = strlen(desc);
 
412
 
 
413
  if (dev < 0 || dev >= num_mixers)
 
414
    return OSS_ENXIO;
 
415
 
 
416
  touch_mixer (dev);
 
417
 
 
418
  if (ctrl < 0 || ctrl >= mixer_devs[dev]->nr_ext)
 
419
    return OSS_EIDRM;
 
420
 
 
421
  if (l > OSS_ENUM_STRINGSIZE) l = OSS_ENUM_STRINGSIZE;
 
422
 
 
423
    mixer_devs[dev]->extensions[ctrl].description =
 
424
      PMALLOC (mixer_devs[dev]->osdev, l);
 
425
 
 
426
  if (mixer_devs[dev]->extensions[ctrl].description == NULL)
 
427
    return OSS_EIO;
 
428
 
 
429
  strncpy (mixer_devs[dev]->extensions[ctrl].description, desc, l);
 
430
  mixer_devs[dev]->extensions[ctrl].description[l-1] = '\0';
 
431
 
 
432
  mixer_devs[dev]->extensions[ctrl].ext.flags |= MIXF_DESCR;
 
433
 
 
434
  return 0;
 
435
}
 
436
 
 
437
static int
 
438
mixer_ext_read (oss_mixer_value * val)
 
439
{
 
440
 
 
441
  int dev;
 
442
  int extnr;
 
443
  oss_mixext *ext;
 
444
  oss_mixext_desc *ext_desc;
 
445
  mixer_ext_fn func;
 
446
 
 
447
  if (val == NULL)
 
448
    return OSS_EFAULT;
 
449
 
 
450
  if (val->dev < 0 || val->dev >= num_mixers)
 
451
    return OSS_ENXIO;
 
452
 
 
453
  dev = val->dev;
 
454
 
 
455
  if (!mixer_devs[dev]->enabled || mixer_devs[dev]->unloaded)
 
456
    return OSS_ENXIO;
 
457
  touch_mixer (dev);
 
458
 
 
459
  if (val->ctrl < 0 || val->ctrl >= mixer_devs[dev]->nr_ext)
 
460
    return OSS_EIDRM;
 
461
  extnr = val->ctrl;
 
462
 
 
463
  ext_desc = &mixer_devs[dev]->extensions[extnr];
 
464
  ext = &ext_desc->ext;
 
465
 
 
466
  if (val->timestamp != ext->timestamp)
 
467
    {
 
468
      return OSS_EIDRM;
 
469
    }
 
470
 
 
471
  if (ext_desc->handler == NULL || !(ext->flags & MIXF_READABLE))
 
472
    return OSS_EFAULT;
 
473
 
 
474
  func = (mixer_ext_fn) ext_desc->handler;
 
475
  return (val->value = func (dev, ext->ctrl, SNDCTL_MIX_READ, val->value));
 
476
}
 
477
 
 
478
static int
 
479
mixer_ext_write (oss_mixer_value * val)
 
480
{
 
481
 
 
482
  int dev;
 
483
  int extnr;
 
484
  int err;
 
485
  oss_mixext *ext;
 
486
  oss_mixext_desc *ext_desc;
 
487
  mixer_ext_fn func;
 
488
 
 
489
  if (val == NULL)
 
490
    {
 
491
      cmn_err (CE_WARN, "NULL argument in mixer call\n");
 
492
      return OSS_EFAULT;
 
493
    }
 
494
 
 
495
  if (val->dev < 0 || val->dev >= num_mixers)
 
496
    return OSS_ENXIO;
 
497
 
 
498
  dev = val->dev;
 
499
  if (!mixer_devs[dev]->enabled || mixer_devs[dev]->unloaded)
 
500
    return OSS_ENXIO;
 
501
  touch_mixer (dev);
 
502
 
 
503
  if (val->ctrl < 0 || val->ctrl >= mixer_devs[dev]->nr_ext)
 
504
    return OSS_EIDRM;
 
505
  extnr = val->ctrl;
 
506
 
 
507
  ext_desc = &mixer_devs[dev]->extensions[extnr];
 
508
  ext = &ext_desc->ext;
 
509
 
 
510
  if (ext_desc->handler == NULL || !(ext->flags & MIXF_WRITEABLE))
 
511
    {
 
512
      cmn_err (CE_WARN, "NULL handler or control not writeable\n");
 
513
      return OSS_EFAULT;
 
514
    }
 
515
 
 
516
  if (val->timestamp != ext->timestamp)
 
517
    {
 
518
      return OSS_EIDRM;
 
519
    }
 
520
 
 
521
  func = (mixer_ext_fn) ext_desc->handler;
 
522
  mixer_devs[dev]->modify_counter++;
 
523
  err = val->value = func (dev, ext->ctrl, SNDCTL_MIX_WRITE, val->value);
 
524
 
 
525
  if (err >= 0)
 
526
    ext->update_counter++;
 
527
  return err;
 
528
}
 
529
 
 
530
int
 
531
mixer_ext_create_device (int dev, int maxentries)
 
532
{
 
533
  oss_mixext_root *mixroot;
 
534
  oss_mixext *mixext;
 
535
  oss_mixext_desc *mixext_desc;
 
536
  char *name = mixer_devs[dev]->name;
 
537
  char *id = mixer_devs[dev]->id;
 
538
  int i;
 
539
 
 
540
  maxentries++;                 /* Needs space for the device root node */
 
541
 
 
542
  if (mixer_devs[dev]->max_ext == 0)
 
543
     {
 
544
        mixext_desc =
 
545
          PMALLOC (mixer_devs[dev]->osdev, sizeof (*mixext_desc) * maxentries);
 
546
        mixer_devs[dev]->max_ext = maxentries;
 
547
        mixer_devs[dev]->extensions = mixext_desc;
 
548
     }
 
549
  else
 
550
     {
 
551
        mixext_desc = mixer_devs[dev]->extensions;
 
552
     }
 
553
 
 
554
  if (mixext_desc == NULL)
 
555
    {
 
556
      cmn_err (CE_CONT, "Not enough memory for mixer%d (ext)\n", dev);
 
557
      return OSS_EIO;
 
558
    }
 
559
 
 
560
  mixer_devs[dev]->nr_ext = 1;
 
561
  mixer_devs[dev]->timestamp = GET_JIFFIES ();
 
562
 
 
563
  mixext = &mixext_desc->ext;
 
564
  mixext->dev = dev;
 
565
  mixext->ctrl = -1;            /* Undefined */
 
566
  mixext->type = MIXT_DEVROOT;
 
567
  mixext->maxvalue = 0;
 
568
  mixext->minvalue = 0;
 
569
  mixext->flags = 0;
 
570
  strcpy (mixext->id, "DEVROOT");
 
571
  mixext->parent = 0;           /* Link to itself */
 
572
  mixext->timestamp = mixer_devs[dev]->timestamp;
 
573
  mixext_desc->handler = NULL;
 
574
  memset (mixext->data, 0, sizeof (mixext->data));
 
575
 
 
576
  mixroot = (oss_mixext_root *) & mixext->data;
 
577
 
 
578
  for (i = 0; i < 15 && id[i]; i++)
 
579
    mixroot->id[i] = id[i];
 
580
  mixroot->id[15] = 0;
 
581
 
 
582
  for (i = 0; i < 47 && name[i]; i++)
 
583
    mixroot->name[i] = name[i];
 
584
  mixroot->name[47] = 0;
 
585
 
 
586
  return 0;
 
587
}
 
588
 
 
589
int
 
590
mixer_ext_create_group_flags (int dev, int parent, const char *id,
 
591
                              unsigned int flags)
 
592
{
 
593
  oss_mixext *mixext;
 
594
  oss_mixext_desc *mixext_desc, *parent_desc;
 
595
  int enumber;
 
596
 
 
597
  flags &= ~MIXF_DESCR;
 
598
 
 
599
  if (mixer_devs[dev]->extensions == NULL)
 
600
    {
 
601
      cmn_err (CE_WARN, "Mixer extensions not initialized for device %d\n",
 
602
               dev);
 
603
      return OSS_EFAULT;
 
604
    }
 
605
 
 
606
  /*
 
607
   * Ensure that the parent node number is valid.
 
608
   */
 
609
  if (parent < 0 || parent >= mixer_devs[dev]->nr_ext)
 
610
     parent = 0;
 
611
 
 
612
  parent_desc =
 
613
    &mixer_devs[dev]->extensions[parent];
 
614
  mixext = &parent_desc->ext;
 
615
 
 
616
  if (mixext->type != MIXT_DEVROOT && mixext->type != MIXT_GROUP)
 
617
     parent = 0; /* Point to the root group */
 
618
 
 
619
  if (mixer_devs[dev]->nr_ext >= mixer_devs[dev]->max_ext)
 
620
    {
 
621
      cmn_err (CE_WARN, "Out of mixer controls for device %d/%s (%d)\n", dev,
 
622
               mixer_devs[dev]->name, mixer_devs[dev]->max_ext);
 
623
      return OSS_ENOSPC;
 
624
    }
 
625
 
 
626
  mixext_desc =
 
627
    &mixer_devs[dev]->extensions[(enumber = mixer_devs[dev]->nr_ext++)];
 
628
  mixext = &mixext_desc->ext;
 
629
  mixext->dev = dev;
 
630
  mixext->ctrl = -1;            /* Undefined */
 
631
  mixext->type = MIXT_GROUP;
 
632
  mixext->maxvalue = 0;
 
633
  mixext->minvalue = 0;
 
634
  mixext->flags = flags | MIXF_FLAT;    /* Will be unflattened later if required */
 
635
  strcpy (mixext->id, id);
 
636
  mixext->parent = parent;
 
637
  mixext_desc->handler = NULL;
 
638
  mixext_desc->enum_info = NULL;
 
639
  memset (mixext->enum_present, 0xff, sizeof (mixext->enum_present));
 
640
  mixext->timestamp = mixer_devs[dev]->timestamp;
 
641
  mixext->control_no = -1;
 
642
  mixext->desc = 0;
 
643
  memset (mixext->data, 0, sizeof (mixext->data));
 
644
 
 
645
  return enumber;
 
646
}
 
647
 
 
648
int
 
649
mixer_ext_create_group (int dev, int parent, const char *id)
 
650
{
 
651
  return mixer_ext_create_group_flags (dev, parent, id, 0);
 
652
}
 
653
 
 
654
int
 
655
mixer_ext_truncate (int dev, int index)
 
656
{
 
657
  if (index < mixer_devs[dev]->nr_ext)
 
658
    {
 
659
      mixer_devs[dev]->nr_ext = index;
 
660
      mixer_devs[dev]->modify_counter++;
 
661
      mixer_devs[dev]->timestamp++;
 
662
    }
 
663
  return 0;
 
664
}
 
665
 
 
666
static void expand_names (int dev);
 
667
static void unflatten_group (int dev, int group);
 
668
static void touch_parents (int dev, int group);
 
669
 
 
670
int
 
671
mixer_ext_create_control (int dev, int parent, int ctrl, mixer_ext_fn func,
 
672
                          int type, const char *id, int maxvalue, int flags)
 
673
{
 
674
  oss_mixext *mixext;
 
675
  oss_mixext_desc *mixext_desc, *parent_desc;
 
676
  int enumber;
 
677
 
 
678
  flags &= ~MIXF_DESCR;
 
679
 
 
680
  if (mixer_devs[dev]->extensions == NULL)
 
681
    {
 
682
      cmn_err (CE_WARN, "Mixer extensions not initialized for device %d\n",
 
683
               dev);
 
684
      return OSS_EFAULT;
 
685
    }
 
686
 
 
687
  if (mixer_devs[dev]->nr_ext >= mixer_devs[dev]->max_ext)
 
688
    {
 
689
      cmn_err (CE_WARN, "Out of mixer controls for device %d/%s (%d)\n", dev,
 
690
               mixer_devs[dev]->name, mixer_devs[dev]->max_ext);
 
691
      return OSS_ENOSPC;
 
692
    }
 
693
 
 
694
  if (func == NULL)             /* No access function */
 
695
    flags &= ~(MIXF_READABLE | MIXF_WRITEABLE);
 
696
 
 
697
  /*
 
698
   * Ensure that the parent node number is valid.
 
699
   */
 
700
  if (parent < 0 || parent >= mixer_devs[dev]->nr_ext)
 
701
     parent = 0;
 
702
 
 
703
  parent_desc =
 
704
    &mixer_devs[dev]->extensions[parent];
 
705
  mixext = &parent_desc->ext;
 
706
 
 
707
  if (mixext->type != MIXT_DEVROOT && mixext->type != MIXT_GROUP)
 
708
     parent = 0; /* Point to the root group */
 
709
 
 
710
 
 
711
  mixext_desc =
 
712
    &mixer_devs[dev]->extensions[(enumber = mixer_devs[dev]->nr_ext++)];
 
713
  mixext = &mixext_desc->ext;
 
714
  mixext->dev = dev;
 
715
  mixext->ctrl = ctrl;
 
716
  mixext->type = type;
 
717
  mixext->maxvalue = maxvalue;
 
718
  mixext->minvalue = 0;
 
719
  mixext->flags = flags;
 
720
  strncpy (mixext->id, id, sizeof (mixext->id));
 
721
  mixext->id[sizeof (mixext->id) - 1] = 0;
 
722
  mixext->parent = parent;
 
723
  mixext->timestamp = mixer_devs[dev]->timestamp;
 
724
  mixext_desc->handler = (mixer_ext_fn) func;
 
725
  mixext_desc->enum_info = NULL;
 
726
  memset (mixext->data, 0, sizeof (mixext->data));
 
727
  memset (mixext->enum_present, 0xff, sizeof (mixext->enum_present));
 
728
  mixext->control_no = -1;
 
729
  mixext->desc = 0;
 
730
 
 
731
/*
 
732
 * Perform name expansion too if it has already been done for the
 
733
 * earlier controls. Note that this only gets done with rare devices
 
734
 * that add/remove controls on fly.
 
735
 *
 
736
 * TODO: Optimize this to expand only the current control. Scanning through
 
737
 * all the controls may be bit time consuming with future devices having 100s 
 
738
 * of controls.
 
739
 */
 
740
  if (mixer_devs[dev]->names_checked)
 
741
    expand_names (dev);
 
742
  else
 
743
    strcpy(mixext->extname, mixext->id);
 
744
 
 
745
/*
 
746
 * Mark groups with tall controls such as peak meters and sliders as
 
747
 * non-flat
 
748
 */
 
749
 
 
750
  switch (type)
 
751
    {
 
752
    case MIXT_SLIDER:
 
753
    case MIXT_MONOSLIDER:
 
754
    case MIXT_STEREOSLIDER:
 
755
    case MIXT_MONOSLIDER16:
 
756
    case MIXT_STEREOSLIDER16:
 
757
    case MIXT_MONOVU:
 
758
    case MIXT_STEREOVU:
 
759
    case MIXT_MONOPEAK:
 
760
    case MIXT_STEREOPEAK:
 
761
    case MIXT_MONODB:
 
762
    case MIXT_STEREODB:
 
763
    case MIXT_3D:
 
764
      unflatten_group (dev, parent);
 
765
      break;
 
766
    }
 
767
 
 
768
  touch_parents(dev, parent);
 
769
 
 
770
  return enumber;
 
771
}
 
772
 
 
773
 
 
774
oss_mixext *
 
775
mixer_find_ext (int dev, int enumber)
 
776
{
 
777
  oss_mixext_desc *mixext;
 
778
 
 
779
  if (dev < 0 || dev >= num_mixers)
 
780
    {
 
781
      return NULL;
 
782
    }
 
783
  touch_mixer (dev);
 
784
 
 
785
  if (enumber < 0 || enumber >= mixer_devs[dev]->nr_ext)
 
786
    {
 
787
      return NULL;
 
788
    }
 
789
 
 
790
  mixext = &mixer_devs[dev]->extensions[enumber];
 
791
 
 
792
  return &mixext->ext;
 
793
}
 
794
 
 
795
/*
 
796
 * Default read/write access functions
 
797
 */
 
798
int
 
799
mixer_ext_rw (int dev, int ctrl, unsigned int cmd, int value)
 
800
{
 
801
  int err;
 
802
 
 
803
  if (cmd == SNDCTL_MIX_READ)
 
804
    {
 
805
      if ((err =
 
806
           oss_legacy_mixer_ioctl (dev, -1, MIXER_READ (ctrl),
 
807
                                   (ioctl_arg) & value)) < 0)
 
808
        return err;
 
809
      return value;
 
810
    }
 
811
 
 
812
  if (cmd == SNDCTL_MIX_WRITE)
 
813
    {
 
814
      if ((err =
 
815
           oss_legacy_mixer_ioctl (dev, -1, MIXER_WRITE (ctrl),
 
816
                                   (ioctl_arg) & value)) < 0)
 
817
        return err;
 
818
      return value;
 
819
    }
 
820
 
 
821
  return OSS_EINVAL;
 
822
}
 
823
 
 
824
int
 
825
mixer_ext_recrw (int dev, int ctrl, unsigned int cmd, int value)
 
826
{
 
827
  int caps, recmask, err;
 
828
 
 
829
  if ((err =
 
830
       oss_legacy_mixer_ioctl (dev, -1, SOUND_MIXER_READ_CAPS,
 
831
                               (ioctl_arg) & caps)) < 0)
 
832
    caps = SOUND_CAP_EXCL_INPUT;        /* Default */
 
833
 
 
834
  if ((err =
 
835
       oss_legacy_mixer_ioctl (dev, -1, SOUND_MIXER_READ_RECSRC,
 
836
                               (ioctl_arg) & recmask)) < 0)
 
837
    return err;
 
838
 
 
839
  if (cmd == SNDCTL_MIX_READ)
 
840
    return (recmask & (1 << ctrl)) ? 1 : 0;
 
841
 
 
842
  if (caps & SOUND_CAP_EXCL_INPUT)      /* Single recording source */
 
843
    recmask = 0;
 
844
 
 
845
  if (value)
 
846
    recmask |= (1 << ctrl);
 
847
  else
 
848
    recmask &= ~(1 << ctrl);
 
849
 
 
850
  if (recmask == 0)
 
851
    return 1;                   /* Can't remove the only recording source */
 
852
 
 
853
  if ((err =
 
854
       oss_legacy_mixer_ioctl (dev, -1, SOUND_MIXER_WRITE_RECSRC,
 
855
                               (ioctl_arg) & recmask)) < 0)
 
856
    return err;
 
857
 
 
858
 
 
859
  return (recmask & (1 << ctrl)) ? 1 : 0;
 
860
}
 
861
 
 
862
/*
 
863
 * Mixer extension initialization
 
864
 */
 
865
 
 
866
static void
 
867
store_name (oss_mixext * thisrec, char *name)
 
868
{
 
869
  int i;
 
870
 
 
871
  while (*name == '.')
 
872
    name++;
 
873
  strncpy (thisrec->extname, name, 32);
 
874
  thisrec->extname[31] = '\0';
 
875
 
 
876
  name = thisrec->extname;
 
877
  for (i = 0; i < strlen (name); i++)
 
878
    if (name[i] >= 'A' && name[i] <= 'Z')
 
879
      name[i] += 32;
 
880
}
 
881
 
 
882
static char *
 
883
cut_name (char *name)
 
884
{
 
885
  char *s = name;
 
886
  while (*s)
 
887
    if (*s++ == '_')
 
888
      return s;
 
889
 
 
890
  if (name[0] == '@')
 
891
    return &name[1];
 
892
 
 
893
  return name;
 
894
}
 
895
 
 
896
#include "mixerdefs.h"
 
897
 
 
898
static void
 
899
find_enum_defs (oss_mixext * thisrec, int dev, int ctl)
 
900
{
 
901
  int i;
 
902
 
 
903
  for (i = 0; mixer_defs[i].name != NULL; i++)
 
904
    if (strcmp (thisrec->extname, mixer_defs[i].name) == 0)
 
905
      {
 
906
        mixer_ext_set_strings (dev, ctl, mixer_defs[i].strings, 0);
 
907
        return;
 
908
      }
 
909
}
 
910
 
 
911
static void
 
912
expand_names (int dev)
 
913
{
 
914
  int i, n;
 
915
  oss_mixext_desc *mixext_desc;
 
916
 
 
917
  n = mixer_devs[dev]->nr_ext;
 
918
  mixer_devs[dev]->names_checked = 1;
 
919
 
 
920
  if (n < 1)
 
921
    return;
 
922
 
 
923
  for (i = 0; i < n; i++)
 
924
    {
 
925
      char tmp[100], *name;
 
926
      int parent = 0;
 
927
      oss_mixext *thisrec = NULL, *parentrec = NULL;
 
928
 
 
929
      mixext_desc = &mixer_devs[dev]->extensions[i];
 
930
      thisrec = &mixext_desc->ext;
 
931
 
 
932
      switch (thisrec->type)
 
933
        {
 
934
        case MIXT_DEVROOT:
 
935
          thisrec->extname[0] = 0;
 
936
          break;
 
937
 
 
938
        case MIXT_GROUP:
 
939
          parent = thisrec->parent;
 
940
          mixext_desc = &mixer_devs[dev]->extensions[parent];
 
941
          parentrec = &mixext_desc->ext;
 
942
          name = cut_name (thisrec->id);
 
943
          if (parentrec->extname[0] == 0)
 
944
            strcpy (tmp, name);
 
945
          else
 
946
            sprintf (tmp, "%s.%s", parentrec->extname, name);
 
947
          store_name (thisrec, tmp);
 
948
          break;
 
949
 
 
950
        case MIXT_STEREOSLIDER:
 
951
        case MIXT_STEREOSLIDER16:
 
952
        case MIXT_STEREODB:
 
953
        case MIXT_STEREOVU:
 
954
        case MIXT_MONODB:
 
955
        case MIXT_MONOSLIDER:
 
956
        case MIXT_MONOSLIDER16:
 
957
        case MIXT_SLIDER:
 
958
        case MIXT_MONOVU:
 
959
        case MIXT_MONOPEAK:
 
960
        case MIXT_STEREOPEAK:
 
961
        case MIXT_ONOFF:
 
962
        case MIXT_MUTE:
 
963
        case MIXT_ENUM:
 
964
        case MIXT_VALUE:
 
965
        case MIXT_HEXVALUE:
 
966
        case MIXT_3D:
 
967
          parent = thisrec->parent;
 
968
          mixext_desc = &mixer_devs[dev]->extensions[parent];
 
969
          parentrec = &mixext_desc->ext;
 
970
          name = cut_name (thisrec->id);
 
971
          if (*thisrec->id == 0 || *thisrec->id == '-') /* Special (hidden) names */
 
972
            strcpy (thisrec->extname, parentrec->extname);
 
973
          else
 
974
            {
 
975
              sprintf (tmp, "%s.%s", parentrec->extname, name);
 
976
              store_name (thisrec, tmp);
 
977
 
 
978
              if (thisrec->type == MIXT_ENUM)
 
979
                find_enum_defs (thisrec, dev, i);
 
980
            }
 
981
          break;
 
982
 
 
983
        case MIXT_MARKER:
 
984
          break;
 
985
 
 
986
        default:;
 
987
        }
 
988
    }
 
989
/*
 
990
 * Fix duplicate names.
 
991
 */
 
992
 
 
993
  for (i = 0; i < n; i++)
 
994
    {
 
995
      char tmp[100];
 
996
      int j, dupes = 0;
 
997
      oss_mixext *thisrec = NULL;
 
998
 
 
999
      mixext_desc = &mixer_devs[dev]->extensions[i];
 
1000
      thisrec = &mixext_desc->ext;
 
1001
 
 
1002
      if (thisrec->type == MIXT_GROUP)
 
1003
        continue;
 
1004
 
 
1005
      strcpy (tmp, thisrec->extname);
 
1006
 
 
1007
      for (j = i + 1; j < n; j++)
 
1008
        {
 
1009
          oss_mixext_desc *mixext_desc2;
 
1010
          oss_mixext *thisrec2 = NULL;
 
1011
          mixext_desc2 = &mixer_devs[dev]->extensions[j];
 
1012
          thisrec2 = &mixext_desc2->ext;
 
1013
 
 
1014
          if (thisrec2->type == MIXT_GROUP)
 
1015
            continue;
 
1016
 
 
1017
          if (strcmp (thisrec2->extname, tmp) == 0)
 
1018
            dupes++;
 
1019
        }
 
1020
 
 
1021
      if (dupes > 0)            /* Need to fix duplicates */
 
1022
        {
 
1023
          int count = 1, len;
 
1024
          char tmp2[32];
 
1025
 
 
1026
          for (j = i; j < n; j++)
 
1027
            {
 
1028
              oss_mixext_desc *mixext_desc2;
 
1029
              oss_mixext *thisrec2 = NULL;
 
1030
              mixext_desc2 = &mixer_devs[dev]->extensions[j];
 
1031
              thisrec2 = &mixext_desc2->ext;
 
1032
 
 
1033
              if (thisrec2->type != MIXT_GROUP)
 
1034
                if (strcmp (thisrec2->extname, tmp) == 0)
 
1035
                  {
 
1036
                    sprintf (tmp2, "%d", count++);
 
1037
                    tmp2[31] = '\0';
 
1038
                    len = strlen (thisrec2->extname);
 
1039
                    if (len >= sizeof (thisrec2->extname) - strlen (tmp2))
 
1040
                      len = sizeof (thisrec2->extname) - strlen (tmp2) - 1;
 
1041
                    strcpy (thisrec2->extname + len, tmp2);
 
1042
                  }
 
1043
            }
 
1044
        }
 
1045
    }
 
1046
}
 
1047
 
 
1048
static void
 
1049
unflatten_group (int dev, int group)
 
1050
{
 
1051
/*
 
1052
 * Clear the MIXF_FLAT flags from all parent groups (recursively):
 
1053
 */
 
1054
  int n;
 
1055
  oss_mixext_desc *mixext_desc;
 
1056
  oss_mixext *thisrec = NULL;
 
1057
 
 
1058
  n = mixer_devs[dev]->nr_ext;
 
1059
 
 
1060
  if (n < 1)
 
1061
    return;
 
1062
 
 
1063
  if (group <= 0 || group >= n)
 
1064
    return;
 
1065
 
 
1066
  mixext_desc = &mixer_devs[dev]->extensions[group];
 
1067
  thisrec = &mixext_desc->ext;
 
1068
 
 
1069
  if (thisrec->type != MIXT_GROUP)      /* Not a group */
 
1070
    return;
 
1071
 
 
1072
  if (!(thisrec->flags & MIXF_FLAT))    /* Already unflattened */
 
1073
    return;
 
1074
 
 
1075
  thisrec->flags &= ~MIXF_FLAT;
 
1076
 
 
1077
  if (thisrec->parent >= group) /* Broken link */
 
1078
    return;
 
1079
 
 
1080
  unflatten_group (dev, thisrec->parent);       /* Unflatten the parent */
 
1081
}
 
1082
 
 
1083
static void
 
1084
touch_parents (int dev, int group)
 
1085
{
 
1086
  int n;
 
1087
  oss_mixext_desc *mixext_desc;
 
1088
  oss_mixext *thisrec = NULL;
 
1089
 
 
1090
  n = mixer_devs[dev]->nr_ext;
 
1091
 
 
1092
  if (n < 1)
 
1093
    return;
 
1094
 
 
1095
  if (group <= 0 || group >= n)
 
1096
    return;
 
1097
 
 
1098
  mixext_desc = &mixer_devs[dev]->extensions[group];
 
1099
  thisrec = &mixext_desc->ext;
 
1100
 
 
1101
  while (thisrec->type != MIXT_DEVROOT)
 
1102
    {
 
1103
      if (thisrec->type != MIXT_GROUP)  /* Not a group */
 
1104
        return;
 
1105
 
 
1106
      thisrec->update_counter++;
 
1107
 
 
1108
      if (thisrec->parent >= group)     /* Broken link */
 
1109
        return;
 
1110
 
 
1111
      unflatten_group (dev, thisrec->parent);   /* Unflatten the parent */
 
1112
 
 
1113
      mixext_desc = &mixer_devs[dev]->extensions[thisrec->parent];
 
1114
      thisrec = &mixext_desc->ext;
 
1115
    }
 
1116
 
 
1117
  thisrec->update_counter++;
 
1118
}
 
1119
 
 
1120
#define INPUT_MASK (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN)
 
1121
#define OUTPUT_MASK (SOUND_MASK_PCM|SOUND_MASK_ALTPCM|SOUND_MASK_VOLUME| \
 
1122
                SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_SYNTH| \
 
1123
                SOUND_MASK_IMIX|SOUND_MASK_REARVOL|SOUND_MASK_CENTERVOL| \
 
1124
                SOUND_MASK_SIDEVOL)
 
1125
#define MONITOR_MASK (SOUND_MASK_SPEAKER|SOUND_MASK_LINE|SOUND_MASK_LINE| \
 
1126
                SOUND_MASK_MIC|SOUND_MASK_CD|SOUND_MASK_LINE1|SOUND_MASK_LINE2| \
 
1127
                SOUND_MASK_LINE3|SOUND_MASK_DIGITAL1|SOUND_MASK_DIGITAL2| \
 
1128
                SOUND_MASK_DIGITAL3|SOUND_MASK_MONO|SOUND_MASK_PHONE| \
 
1129
                SOUND_MASK_RADIO|SOUND_MASK_VIDEO)
 
1130
 
 
1131
void
 
1132
touch_mixer (int dev)
 
1133
{
 
1134
  int i, n, devmask, recmask, stereomask, grp, root = 0, caps = 0;
 
1135
  static char *id[] = SOUND_DEVICE_NAMES;
 
1136
  int created = 0;
 
1137
 
 
1138
  if (mixer_devs[dev] == NULL || mixer_devs[dev]->unloaded
 
1139
      || !mixer_devs[dev]->enabled)
 
1140
    {
 
1141
      return;
 
1142
    }
 
1143
 
 
1144
/*
 
1145
 * Create default mixer extension records if required.
 
1146
 */
 
1147
  if (mixer_devs[dev]->nr_ext > 0)      /* Already initialized */
 
1148
    return;
 
1149
 
 
1150
/*
 
1151
 * Compute number of required mixer extension entries
 
1152
 */
 
1153
 
 
1154
  n = mixer_devs[dev]->nr_extra_ext;    /* Reserve space for the actual driver */
 
1155
  if (n < 20)
 
1156
    n = 20;
 
1157
 
 
1158
  if (oss_legacy_mixer_ioctl
 
1159
      (dev, -1, SOUND_MIXER_READ_CAPS, (ioctl_arg) & caps) < 0)
 
1160
    caps = 0;                   /* Error */
 
1161
 
 
1162
  if (oss_legacy_mixer_ioctl
 
1163
      (dev, -1, SOUND_MIXER_READ_DEVMASK, (ioctl_arg) & devmask) < 0)
 
1164
    goto skip;                  /* Error */
 
1165
 
 
1166
  /* Remove devices that are handled otherwise */
 
1167
  devmask &= ~mixer_devs[dev]->ignore_mask;
 
1168
 
 
1169
  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 
1170
    if (devmask & (1 << i))     /* This control is supported */
 
1171
      n++;
 
1172
 
 
1173
  n = n * 2;
 
1174
 
 
1175
  if (oss_legacy_mixer_ioctl
 
1176
      (dev, -1, SOUND_MIXER_READ_RECMASK, (ioctl_arg) & recmask) < 0)
 
1177
    goto skip;                  /* Error */
 
1178
 
 
1179
  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 
1180
    if (recmask & (1 << i))     /* This control is also recording device */
 
1181
      n++;
 
1182
 
 
1183
  root = 0;
 
1184
 
 
1185
#ifdef CONFIG_OSSD
 
1186
  n += 20;                      /* Space for OSSD use */
 
1187
#endif
 
1188
 
 
1189
  n = n + 5;                    /* The marker entry and some spare space */
 
1190
  if ((root = mixer_ext_create_device (dev, n)) < 0)
 
1191
    return;                     /* Error */
 
1192
  created = 1;
 
1193
 
 
1194
  if (oss_legacy_mixer_ioctl (dev, -1, SOUND_MIXER_READ_STEREODEVS,
 
1195
                              (ioctl_arg) & stereomask) < 0)
 
1196
    stereomask = -1;            /* Assume all stereo */
 
1197
 
 
1198
  if (!(caps & SOUND_CAP_NOLEGACY))     /* Don't (re)export the legacy mixer */
 
1199
    for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 
1200
      if (devmask & (1 << i))
 
1201
        {
 
1202
          if ((grp =
 
1203
               mixer_ext_create_group_flags (dev, root, id[i],
 
1204
                                             MIXF_LEGACY)) > 0)
 
1205
            {
 
1206
              int cnum;
 
1207
              oss_mixext *ent;
 
1208
              int flags = 0;
 
1209
 
 
1210
              /*
 
1211
               * Set the type hints for main and PCM volume controls
 
1212
               */
 
1213
 
 
1214
              switch (i)
 
1215
                {
 
1216
                case SOUND_MIXER_VOLUME:
 
1217
                case SOUND_MIXER_MONO:
 
1218
                case SOUND_MIXER_REARVOL:
 
1219
                case SOUND_MIXER_CENTERVOL:
 
1220
                case SOUND_MIXER_SIDEVOL:
 
1221
                  flags |= MIXF_MAINVOL;
 
1222
                  break;
 
1223
 
 
1224
                case SOUND_MIXER_PCM:
 
1225
                case SOUND_MIXER_ALTPCM:
 
1226
                  flags |= MIXF_PCMVOL;
 
1227
                  break;
 
1228
 
 
1229
                case SOUND_MIXER_RECLEV:
 
1230
                case SOUND_MIXER_IGAIN:
 
1231
                  flags |= MIXF_RECVOL;
 
1232
                  break;
 
1233
 
 
1234
                case SOUND_MIXER_SYNTH:
 
1235
                case SOUND_MIXER_SPEAKER:
 
1236
                case SOUND_MIXER_LINE:
 
1237
                case SOUND_MIXER_LINE1:
 
1238
                case SOUND_MIXER_LINE2:
 
1239
                case SOUND_MIXER_LINE3:
 
1240
                case SOUND_MIXER_MIC:
 
1241
                case SOUND_MIXER_CD:
 
1242
                case SOUND_MIXER_DIGITAL1:
 
1243
                case SOUND_MIXER_DIGITAL2:
 
1244
                case SOUND_MIXER_DIGITAL3:
 
1245
                case SOUND_MIXER_PHONE:
 
1246
                case SOUND_MIXER_VIDEO:
 
1247
                case SOUND_MIXER_RADIO:
 
1248
                  flags |= MIXF_MONVOL;
 
1249
                  break;
 
1250
                }
 
1251
 
 
1252
              if (stereomask & (1 << i))
 
1253
                cnum = mixer_ext_create_control (dev, grp, i, mixer_ext_rw,
 
1254
                                                 MIXT_STEREOSLIDER,
 
1255
                                                 "", 100,
 
1256
                                                 flags | MIXF_READABLE |
 
1257
                                                 MIXF_WRITEABLE);
 
1258
              else
 
1259
                cnum = mixer_ext_create_control (dev, grp, i, mixer_ext_rw,
 
1260
                                                 MIXT_MONOSLIDER,
 
1261
                                                 "", 100,
 
1262
                                                 flags | MIXF_READABLE |
 
1263
                                                 MIXF_WRITEABLE);
 
1264
 
 
1265
              if ((ent = mixer_find_ext (dev, cnum)) != NULL)
 
1266
                {
 
1267
                  ent->control_no = i;
 
1268
 
 
1269
                  if ((1 << i) & INPUT_MASK)
 
1270
                    ent->desc &= MIXEXT_SCOPE_INPUT;
 
1271
                  if ((1 << i) & OUTPUT_MASK)
 
1272
                    ent->desc &= MIXEXT_SCOPE_OUTPUT;
 
1273
                  if ((1 << i) & MONITOR_MASK)
 
1274
                    ent->desc &= MIXEXT_SCOPE_MONITOR;
 
1275
 
 
1276
                      /*
 
1277
                       * Set the RGB color for some of the controls
 
1278
                       * to match the usual jack color.
 
1279
                       */
 
1280
 
 
1281
                      switch (i)
 
1282
                      {
 
1283
                      case SOUND_MIXER_MIC: ent->rgbcolor=OSS_RGB_PINK; break;
 
1284
                      case SOUND_MIXER_LINE: ent->rgbcolor=OSS_RGB_BLUE; break;
 
1285
                      case SOUND_MIXER_VOLUME: ent->rgbcolor=OSS_RGB_GREEN; break;
 
1286
                      case SOUND_MIXER_REARVOL: ent->rgbcolor=OSS_RGB_BLACK; break;
 
1287
                      case SOUND_MIXER_SIDEVOL: ent->rgbcolor=OSS_RGB_GRAY; break;
 
1288
                      case SOUND_MIXER_CENTERVOL: ent->rgbcolor=OSS_RGB_ORANGE; break;
 
1289
                      }
 
1290
                 }
 
1291
 
 
1292
              if (recmask & (1 << i))
 
1293
                {
 
1294
                  cnum =
 
1295
                    mixer_ext_create_control (dev, grp, i, mixer_ext_recrw,
 
1296
                                              MIXT_ONOFF, "REC", 1,
 
1297
                                              MIXF_READABLE | MIXF_WRITEABLE | MIXF_RECVOL);
 
1298
                  if ((ent = mixer_find_ext (dev, cnum)) != NULL)
 
1299
                    {
 
1300
                      ent->desc &= MIXEXT_SCOPE_RECSWITCH;
 
1301
                    }
 
1302
                }
 
1303
            }
 
1304
        }
 
1305
 
 
1306
skip:
 
1307
  if (!created)
 
1308
    if ((root = mixer_ext_create_device (dev, n)) < 0)
 
1309
      return;                   /* Error */
 
1310
  mixer_ext_create_control (dev, root, 0, NULL, MIXT_MARKER, "", 0, 0);
 
1311
 
 
1312
  if (mixer_devs[dev]->create_controls != NULL)
 
1313
    mixer_devs[dev]->create_controls (dev);
 
1314
  expand_names (dev);
 
1315
}
 
1316
 
 
1317
int
 
1318
mixer_ext_set_init_fn (int dev, mixer_create_controls_t func, int nextra)
 
1319
{
 
1320
/*
 
1321
 * Set device dependent mixer extension initialization function and
 
1322
 * reserve some extension entries for device dependent use.
 
1323
 *
 
1324
 * This initialization function will be called later when/if the
 
1325
 * extended mixer is actually used.
 
1326
 */
 
1327
  if (dev < 0 || dev >= num_mixers)
 
1328
    return OSS_ENXIO;
 
1329
 
 
1330
  mixer_devs[dev]->nr_extra_ext = nextra;
 
1331
  mixer_devs[dev]->create_controls = func;
 
1332
  return 0;
 
1333
}
 
1334
 
 
1335
int
 
1336
mixer_ext_rebuild_all (int dev, mixer_create_controls_t func, int nextra)
 
1337
{
 
1338
/*
 
1339
 * Throw away all existing mixer controls and recreate the mixer.
 
1340
 */
 
1341
  if (dev < 0 || dev >= num_mixers)
 
1342
    return OSS_ENXIO;
 
1343
  mixer_devs[dev]->nr_ext = 0;
 
1344
 
 
1345
  mixer_devs[dev]->nr_extra_ext = nextra;
 
1346
  mixer_devs[dev]->create_controls = func;
 
1347
 
 
1348
  touch_mixer (dev);
 
1349
  if (mixer_devs[dev]->create_vmix_controls != NULL)
 
1350
     {
 
1351
        mixer_devs[dev]->create_vmix_controls(dev);
 
1352
     }
 
1353
 
 
1354
  return 0;
 
1355
}
 
1356
 
 
1357
int
 
1358
mixer_ext_set_vmix_init_fn (int dev, mixer_create_controls_t func, int nextra,
 
1359
                            void *devc)
 
1360
{
 
1361
/*
 
1362
 * Set device dependent mixer extension initialization function and
 
1363
 * reserve some extension entries for device dependent use.
 
1364
 *
 
1365
 * This initialization function will be called later when/if the
 
1366
 * extended mixer is actually used.
 
1367
 */
 
1368
  if (dev < 0 || dev >= num_mixers)
 
1369
    return OSS_ENXIO;
 
1370
 
 
1371
  mixer_devs[dev]->nr_extra_ext += nextra;
 
1372
  mixer_devs[dev]->create_vmix_controls = func;
 
1373
  mixer_devs[dev]->vmix_devc = devc;
 
1374
  touch_mixer (dev);
 
1375
  func (dev);
 
1376
  expand_names (dev);
 
1377
  return 0;
 
1378
}
 
1379
 
 
1380
#ifdef VDEV_SUPPORT
 
1381
static void
 
1382
ainfo_combine_caps (oss_audioinfo * ainfo, adev_p adev)
 
1383
{
 
1384
  if (!(adev->flags & ADEV_NOOUTPUT))
 
1385
    ainfo->caps |= DSP_CAP_OUTPUT;
 
1386
  else
 
1387
    ainfo->caps &= ~DSP_CAP_OUTPUT;
 
1388
 
 
1389
  if (!(adev->flags & ADEV_NOINPUT))
 
1390
    ainfo->caps |= DSP_CAP_INPUT;
 
1391
  else
 
1392
    ainfo->caps &= ~DSP_CAP_INPUT;
 
1393
 
 
1394
  if (adev->flags & ADEV_DUPLEX)
 
1395
    ainfo->caps |= DSP_CAP_DUPLEX;
 
1396
  else
 
1397
    ainfo->caps &= ~DSP_CAP_DUPLEX;
 
1398
 
 
1399
#ifdef ALLOW_BUFFER_MAPPING
 
1400
  if (!(adev->flags & ADEV_NOMMAP))
 
1401
    ainfo->caps |= DSP_CAP_MMAP;
 
1402
#endif
 
1403
}
 
1404
#endif
 
1405
 
 
1406
#if 0
 
1407
/*
 
1408
 * Device list support is currently not used
 
1409
 */
 
1410
static int
 
1411
check_list (oss_devlist_t * oldlist, oss_devlist_t * newlist)
 
1412
{
 
1413
/*
 
1414
 * Check that the same devices are present in both lists. Any difference
 
1415
 * indicates that the device configuration has changed (invalidates the list).
 
1416
 */
 
1417
#if MAX_AUDIO_DEVFILES > 64
 
1418
#error Too many audio devices - fix this algorithm
 
1419
#endif
 
1420
  unsigned long long mask1, mask2;
 
1421
  int i;
 
1422
 
 
1423
  if (newlist->ndevs != oldlist->ndevs)
 
1424
    return 0;
 
1425
 
 
1426
  mask1 = 0LL;
 
1427
  mask2 = 0LL;
 
1428
 
 
1429
  for (i = 0; i < oldlist->ndevs; i++)
 
1430
    mask1 |= 1LL << oldlist->devices[i];
 
1431
  for (i = 0; i < newlist->ndevs; i++)
 
1432
    mask1 |= 1LL << newlist->devices[i];
 
1433
 
 
1434
  if (mask1 != mask2)
 
1435
    return 0;
 
1436
 
 
1437
  return 1;
 
1438
}
 
1439
#endif
 
1440
 
 
1441
static int
 
1442
get_engineinfo (int dev, oss_audioinfo * info, int combine_slaves)
 
1443
{
 
1444
  int dev_present = 0;
 
1445
  int i;
 
1446
  oss_native_word flags;
 
1447
 
 
1448
  adev_p adev, next;
 
1449
 
 
1450
  flags = 0;
 
1451
  memset ((char *) info, 0, sizeof (*info));
 
1452
 
 
1453
  if (dev < 0 || dev >= num_audio_engines)
 
1454
    return OSS_ENXIO;
 
1455
 
 
1456
  adev = audio_engines[dev];
 
1457
  if (adev == NULL)
 
1458
    {
 
1459
      cmn_err (CE_WARN, "Internal error - adev==NULL (%d)\n", dev);
 
1460
      return OSS_ENXIO;
 
1461
    }
 
1462
 
 
1463
  if (!adev->unloaded && adev->enabled)
 
1464
    dev_present = 1;
 
1465
 
 
1466
  if (dev_present)
 
1467
    {
 
1468
      MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
1469
    }
 
1470
  info->dev = dev;
 
1471
  strcpy (info->name, adev->name);
 
1472
  strcpy (info->handle, adev->handle);
 
1473
  info->busy = adev->open_mode;
 
1474
  info->caps = adev->caps;
 
1475
  if (!(adev->flags & ADEV_NOINPUT))
 
1476
    info->caps |= PCM_CAP_INPUT;
 
1477
  if (!(adev->flags & ADEV_NOOUTPUT))
 
1478
    info->caps |= PCM_CAP_OUTPUT;
 
1479
  if (adev->flags & ADEV_SPECIAL)
 
1480
    info->caps |= PCM_CAP_SPECIAL;
 
1481
  if (adev->flags & ADEV_VIRTUAL)
 
1482
    info->caps |= PCM_CAP_VIRTUAL;
 
1483
 
 
1484
  if (adev->flags & (ADEV_HIDDEN | ADEV_SHADOW))
 
1485
    {
 
1486
      info->caps |= PCM_CAP_HIDDEN;
 
1487
    }
 
1488
 
 
1489
  if (adev->flags & ADEV_DUPLEX)
 
1490
    {
 
1491
      info->caps |= PCM_CAP_DUPLEX;
 
1492
    }
 
1493
  if (adev->d->adrv_trigger)    /* Supports SETTRIGGER */
 
1494
    info->caps |= PCM_CAP_TRIGGER;
 
1495
#ifdef ALLOW_BUFFER_MAPPING
 
1496
  if (!(adev->flags & ADEV_NOMMAP))
 
1497
    info->caps |= PCM_CAP_MMAP;
 
1498
#endif
 
1499
 
 
1500
  info->oformats = adev->oformat_mask;
 
1501
  info->iformats = adev->iformat_mask;
 
1502
  info->pid = adev->pid;
 
1503
  info->latency = adev->latency;
 
1504
  *info->cmd = 0;
 
1505
  strncpy (info->cmd, adev->cmd, sizeof (info->cmd));
 
1506
  info->cmd[sizeof (info->cmd) - 1] = 0;
 
1507
 
 
1508
  strcpy (info->devnode, adev->devnode);
 
1509
 
 
1510
  if (!adev->unloaded && adev->enabled)
 
1511
    {
 
1512
      if (audio_engines[dev]->d->adrv_ioctl (dev, SNDCTL_GETSONG,
 
1513
                                             (ioctl_arg) info->song_name) ==
 
1514
          OSS_EINVAL)
 
1515
        strcpy (info->song_name, adev->song_name);
 
1516
      if (audio_engines[dev]->d->adrv_ioctl (dev, SNDCTL_GETLABEL,
 
1517
                                             (ioctl_arg) info->label) ==
 
1518
          OSS_EINVAL)
 
1519
        strcpy (info->label, adev->label);
 
1520
    }
 
1521
 
 
1522
  if (*info->label == 0)
 
1523
    {
 
1524
      strncpy (info->label, info->cmd, sizeof (info->label));
 
1525
      info->label[sizeof (info->label) - 1] = 0;
 
1526
    }
 
1527
 
 
1528
  info->magic = adev->magic;
 
1529
  info->card_number = adev->card_number;
 
1530
  info->port_number = adev->port_number;
 
1531
  info->mixer_dev = adev->mixer_dev;
 
1532
  info->legacy_device = adev->real_dev;
 
1533
  info->rate_source = adev->rate_source;
 
1534
  info->enabled = (adev->enabled && !adev->unloaded);
 
1535
  info->flags = adev->flags;
 
1536
  info->min_rate = adev->min_rate;
 
1537
  info->max_rate = adev->max_rate;
 
1538
  info->min_channels = adev->min_channels;
 
1539
  info->max_channels = adev->max_channels;
 
1540
  info->binding = adev->binding;
 
1541
  info->nrates = adev->nrates;
 
1542
  for (i = 0; i < info->nrates; i++)
 
1543
    info->rates[i] = adev->rates[i];
 
1544
 
 
1545
  if (adev->next_out == NULL || !dev_present)
 
1546
    info->next_play_engine = 0;
 
1547
  else
 
1548
    {
 
1549
      info->next_play_engine = adev->next_out->engine_num;
 
1550
      next = adev->next_out;
 
1551
 
 
1552
#ifdef VDEV_SUPPORT
 
1553
      i = 0;
 
1554
      while (combine_slaves && next != NULL && i++ < num_audio_engines)
 
1555
        {
 
1556
          ainfo_combine_caps (info, next);
 
1557
          next = next->next_out;
 
1558
        }
 
1559
#endif
 
1560
    }
 
1561
 
 
1562
  if (adev->next_in == NULL || !dev_present)
 
1563
    info->next_rec_engine = 0;
 
1564
  else
 
1565
    {
 
1566
      info->next_rec_engine = adev->next_in->engine_num;
 
1567
      next = adev->next_in;
 
1568
 
 
1569
#ifdef VDEV_SUPPORT
 
1570
      i=0;
 
1571
      while (combine_slaves && next != NULL && i++ < num_audio_engines)
 
1572
        {
 
1573
          ainfo_combine_caps (info, next);
 
1574
          next = next->next_in;
 
1575
        }
 
1576
#endif
 
1577
    }
 
1578
 
 
1579
  if (dev_present)
 
1580
    {
 
1581
      MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
1582
    }
 
1583
  return 0;
 
1584
}
 
1585
 
 
1586
#ifdef CONFIG_OSS_VMIX
 
1587
static int
 
1588
vmixctl_attach(vmixctl_attach_t *att)
 
1589
{
 
1590
        int err;
 
1591
        oss_device_t *osdev;
 
1592
 
 
1593
        if (att->masterdev<0 || att->masterdev >= num_audio_engines)
 
1594
           return OSS_ENXIO;
 
1595
 
 
1596
        if (att->inputdev != -1)
 
1597
        if (att->inputdev<0 || att->inputdev >= num_audio_engines)
 
1598
           return OSS_ENXIO;
 
1599
 
 
1600
        osdev=audio_engines[att->masterdev]->master_osdev;
 
1601
 
 
1602
        if ((err=vmix_attach_audiodev(osdev, att->masterdev, att->inputdev, att->attach_flags))<0)
 
1603
           return err;
 
1604
 
 
1605
        return 0;
 
1606
}
 
1607
 
 
1608
static int
 
1609
vmixctl_detach(vmixctl_attach_t *att)
 
1610
{
 
1611
        int err;
 
1612
        oss_device_t *osdev;
 
1613
 
 
1614
        if (att->masterdev<0 || att->masterdev >= num_audio_engines)
 
1615
           return OSS_ENXIO;
 
1616
 
 
1617
        osdev=audio_engines[att->masterdev]->master_osdev;
 
1618
 
 
1619
        if ((err=vmix_detach_audiodev(att->masterdev))<0)
 
1620
           return err;
 
1621
 
 
1622
        return 0;
 
1623
}
 
1624
 
 
1625
static int
 
1626
vmixctl_rate(vmixctl_rate_t *rate)
 
1627
{
 
1628
        int err;
 
1629
 
 
1630
        if (rate->masterdev<0 || rate->masterdev >= num_audio_engines)
 
1631
           return OSS_ENXIO;
 
1632
 
 
1633
        if ((err=vmix_set_master_rate(rate->masterdev, rate->rate))<0)
 
1634
           return err;
 
1635
 
 
1636
        return 0;
 
1637
}
 
1638
 
 
1639
static int
 
1640
vmixctl_map_channels(vmixctl_map_t *map)
 
1641
{
 
1642
        int err;
 
1643
 
 
1644
        if (map->masterdev < 0 || map->masterdev >= num_audio_engines)
 
1645
           return OSS_ENXIO;
 
1646
 
 
1647
        if ((err = vmix_set_channel_map (map->masterdev, &map->map)) < 0)
 
1648
          return err;
 
1649
 
 
1650
        return 0;
 
1651
}
 
1652
#endif
 
1653
 
 
1654
int
 
1655
oss_mixer_ext (int orig_dev, int class, unsigned int cmd, ioctl_arg arg)
 
1656
{
 
1657
  int val;
 
1658
  int combine_slaves = 0;
 
1659
#ifdef MANAGE_DEV_DSP
 
1660
#ifdef VDEV_SUPPORT
 
1661
  extern void oss_combine_write_lists (void);
 
1662
#endif
 
1663
#endif
 
1664
 
 
1665
  switch (cmd)
 
1666
    {
 
1667
    case SNDCTL_SYSINFO:        /* Formerly OSS_SYSINFO */
 
1668
      {
 
1669
        oss_sysinfo *info = (oss_sysinfo *) arg;
 
1670
        int i;
 
1671
 
 
1672
        memset (info, 0, sizeof (*info));
 
1673
        strcpy (info->product, "OSS");
 
1674
        strncpy (info->version, OSS_VERSION_STRING, sizeof (info->version));
 
1675
        info->version [sizeof (info->version) - 1] = '\0';
 
1676
        strcpy (info->license, oss_license_string);
 
1677
        info->versionnum = OSS_VERSION;
 
1678
 
 
1679
#ifdef OSS_HG_INFO
 
1680
        /* Detailed Mercurial version */
 
1681
        strncpy (info->revision_info, OSS_HG_INFO, sizeof(info->revision_info));
 
1682
        info->revision_info[sizeof(info->revision_info)-1]=0;
 
1683
#endif
 
1684
 
 
1685
        memset (info->options, 0, sizeof (info->options));
 
1686
 
 
1687
        info->numaudios = num_audio_devfiles;
 
1688
        info->numaudioengines = num_audio_engines;
 
1689
        for (i = 0; i < 8; i++)
 
1690
          info->openedaudio[i] = 0;
 
1691
        for (i = 0; i < num_audio_engines; i++)
 
1692
          if (audio_engines[i] != NULL)
 
1693
            {
 
1694
              if (audio_engines[i]->flags & ADEV_OPENED)
 
1695
                if (audio_engines[i]->next_out != NULL)
 
1696
                  {
 
1697
                    int x = audio_engines[i]->real_dev;
 
1698
                    info->openedaudio[x / 32] |= 1 << (x % 32);
 
1699
                  }
 
1700
            }
 
1701
        for (i = 0; i < 8; i++)
 
1702
          info->openedmidi[i] = 0;
 
1703
        for (i = 0; i < num_mididevs; i++)
 
1704
          if (midi_devs[i]->open_mode != 0)
 
1705
            info->openedmidi[i / 32] |= 1 << (i % 32);
 
1706
 
 
1707
        info->numsynths = 0;
 
1708
#ifdef CONFIG_OSS_MIDI
 
1709
        info->nummidis = num_mididevs;
 
1710
#endif
 
1711
        info->numtimers = oss_num_timers;
 
1712
        info->nummixers = num_mixers;
 
1713
        info->numcards = oss_num_cards;
 
1714
 
 
1715
        return 0;
 
1716
      }
 
1717
      break;
 
1718
 
 
1719
    case SNDCTL_MIX_NRMIX:
 
1720
      return *arg = num_mixers;
 
1721
      break;
 
1722
 
 
1723
    case SNDCTL_MIX_NREXT:      /* Return # of mixer extensions for device */
 
1724
      val = *arg;
 
1725
      *arg = 0;
 
1726
      if (val==-1)
 
1727
         val=orig_dev;
 
1728
      if (val < 0 || val >= num_mixers)
 
1729
        return OSS_ENXIO;
 
1730
      if (mixer_devs[val] == NULL || mixer_devs[val]->unloaded
 
1731
          || !mixer_devs[val]->enabled)
 
1732
        {
 
1733
          return OSS_ENXIO;
 
1734
        }
 
1735
 
 
1736
 
 
1737
      touch_mixer (val);
 
1738
      return *arg = mixer_devs[val]->nr_ext;
 
1739
      break;
 
1740
 
 
1741
    case SNDCTL_MIX_EXTINFO:
 
1742
      return oss_mixer_ext_info ((oss_mixext *) arg);
 
1743
      break;
 
1744
 
 
1745
    case SNDCTL_MIX_ENUMINFO:
 
1746
      return mixer_ext_get_enuminfo ((oss_mixer_enuminfo *) arg);
 
1747
      break;
 
1748
 
 
1749
    case SNDCTL_MIX_DESCRIPTION:
 
1750
      return mixer_ext_get_description ((oss_mixer_enuminfo *) arg);
 
1751
      break;
 
1752
 
 
1753
    case SNDCTL_MIX_READ:
 
1754
      return mixer_ext_read ((oss_mixer_value *) arg);
 
1755
      break;
 
1756
 
 
1757
    case SNDCTL_MIX_WRITE:
 
1758
      return mixer_ext_write ((oss_mixer_value *) arg);
 
1759
      break;
 
1760
 
 
1761
    case OSS_GETVERSION:
 
1762
      return *arg = OSS_VERSION;
 
1763
      break;
 
1764
 
 
1765
    case SNDCTL_AUDIOINFO:
 
1766
    case SNDCTL_AUDIOINFO_EX:
 
1767
      {
 
1768
        int dev;
 
1769
        oss_audioinfo *info = (oss_audioinfo *) arg;
 
1770
 
 
1771
        if (info == NULL)
 
1772
          return OSS_EFAULT;
 
1773
 
 
1774
        dev = info->dev;
 
1775
 
 
1776
        if (dev == -1)          /* Request for the current device */
 
1777
           {
 
1778
              oss_audio_set_error (orig_dev, E_PLAY,
 
1779
                                   OSSERR (1022,
 
1780
                                           "SNDCTL_AUDIOINFO called with dev=-1.."),
 
1781
                                   0);
 
1782
              /*
 
1783
               * Errordesc:
 
1784
               * Applications that try to obtain audio device information about
 
1785
               * the current device should call SNDCTL_ENGINEINFO instead of
 
1786
               * SNDCTL_AUDIOINFO.
 
1787
               *
 
1788
               * Audio file descriptors returned by open(2) are bound
 
1789
               * directly to specific audio engine instead of the
 
1790
               * device file.
 
1791
               */
 
1792
              return OSS_EINVAL;
 
1793
          }
 
1794
 
 
1795
        if (dev < 0 || dev >= num_audio_devfiles)
 
1796
          {
 
1797
            return OSS_EINVAL;
 
1798
          }
 
1799
 
 
1800
        if (audio_devfiles[dev] == NULL)
 
1801
          {
 
1802
            return OSS_EIO;
 
1803
          }
 
1804
 
 
1805
        if (dev >= 0)
 
1806
          {
 
1807
            dev = audio_devfiles[dev]->engine_num;      /* Get the engine number */
 
1808
            if (cmd == SNDCTL_AUDIOINFO && info->dev != -1)
 
1809
              combine_slaves = 1;
 
1810
          }
 
1811
        return get_engineinfo (dev, info, combine_slaves);
 
1812
      }
 
1813
      break;
 
1814
 
 
1815
    case SNDCTL_ENGINEINFO:
 
1816
      {
 
1817
        int dev;
 
1818
        oss_audioinfo *info = (oss_audioinfo *) arg;
 
1819
 
 
1820
        if (info == NULL)
 
1821
          return OSS_EFAULT;
 
1822
 
 
1823
        dev = info->dev;
 
1824
 
 
1825
        if (dev == -1)          /* Request for the current device */
 
1826
          switch (class)
 
1827
            {
 
1828
            case OSS_DEV_DSP:
 
1829
            case OSS_DEV_DSP_ENGINE:
 
1830
              dev = orig_dev;
 
1831
              break;
 
1832
 
 
1833
            default:
 
1834
              cmn_err(CE_WARN, "Unrecognized device class %d for dev %d\n", class, orig_dev);
 
1835
              return OSS_EINVAL;
 
1836
            }
 
1837
 
 
1838
        if (dev < 0 || dev >= num_audio_engines)
 
1839
          {
 
1840
            return OSS_EINVAL;
 
1841
          }
 
1842
 
 
1843
        return get_engineinfo (dev, info, 0);
 
1844
      }
 
1845
      break;
 
1846
 
 
1847
#ifdef CONFIG_OSS_MIDI
 
1848
    case SNDCTL_MIDIINFO:
 
1849
      {
 
1850
        int dev;
 
1851
        oss_native_word flags;
 
1852
        extern int oss_num_midi_clients;        /* midi.c */
 
1853
 
 
1854
        oss_midi_info *info = (oss_midi_info *) arg;
 
1855
        mididev_t *mdev;
 
1856
 
 
1857
        dev = info->dev;
 
1858
 
 
1859
        if (dev == -1)          /* Request for the current device */
 
1860
          switch (class)
 
1861
            {
 
1862
            case OSS_DEV_MIDI:
 
1863
              /*
 
1864
               * Figure out the HW device connected to this client (orig_dev).
 
1865
               */
 
1866
              dev = orig_dev;
 
1867
              if (dev < 0 || dev >= oss_num_midi_clients)
 
1868
                return OSS_ENXIO;
 
1869
              if (oss_midi_clients[dev]->mididev == NULL)
 
1870
                return OSS_EBUSY;       /* No binding established (yet) */
 
1871
              dev = oss_midi_clients[dev]->mididev->dev;
 
1872
              break;
 
1873
 
 
1874
            default:
 
1875
              return OSS_EINVAL;
 
1876
            }
 
1877
 
 
1878
        if (dev < 0 || dev >= num_mididevs)
 
1879
          {
 
1880
            return OSS_EINVAL;
 
1881
          }
 
1882
 
 
1883
        memset ((char *) info, 0, sizeof (*info));
 
1884
 
 
1885
        mdev = midi_devs[dev];
 
1886
        MUTEX_ENTER_IRQDISABLE (mdev->mutex, flags);
 
1887
        info->dev = dev;
 
1888
        strcpy (info->name, mdev->name);
 
1889
        strcpy (info->handle, mdev->handle);
 
1890
        info->pid = mdev->pid;
 
1891
        info->busy = mdev->open_mode;
 
1892
        *info->cmd = 0;
 
1893
        strncpy (info->cmd, mdev->cmd, sizeof (info->cmd));
 
1894
        info->cmd[sizeof (info->cmd) - 1] = 0;
 
1895
        info->magic = mdev->magic;
 
1896
        info->card_number = mdev->card_number;
 
1897
        strcpy (info->devnode, mdev->devnode);
 
1898
        info->legacy_device = mdev->real_dev;
 
1899
        info->port_number = mdev->port_number;
 
1900
        info->enabled = mdev->enabled;
 
1901
        info->flags = mdev->flags;
 
1902
        info->caps = mdev->caps;
 
1903
        info->latency = mdev->latency;
 
1904
        if (!(info->caps & MIDI_CAP_INOUT))
 
1905
          info->caps |= MIDI_CAP_INOUT;
 
1906
        if (mdev->flags & MFLAG_VIRTUAL)
 
1907
          info->caps |= MIDI_CAP_VIRTUAL;
 
1908
        if (mdev->flags & MFLAG_CLIENT)
 
1909
          info->caps |= MIDI_CAP_CLIENT;
 
1910
        if (mdev->flags & MFLAG_SERVER)
 
1911
          info->caps |= MIDI_CAP_SERVER;
 
1912
        if (mdev->flags & MFLAG_INTERNAL)
 
1913
          info->caps |= MIDI_CAP_INTERNAL;
 
1914
        if (mdev->flags & MFLAG_EXTERNAL)
 
1915
          info->caps |= MIDI_CAP_EXTERNAL;
 
1916
        if (mdev->flags & MFLAG_MTC)
 
1917
          info->caps |= MIDI_CAP_MTC;
 
1918
        if (midi_devs[dev]->enabled && !midi_devs[dev]->unloaded)
 
1919
          if (midi_devs[dev]->d->ioctl)
 
1920
            {
 
1921
              midi_devs[dev]->d->ioctl (dev, SNDCTL_GETSONG,
 
1922
                                        (ioctl_arg) info->song_name);
 
1923
              midi_devs[dev]->d->ioctl (dev, SNDCTL_GETLABEL,
 
1924
                                        (ioctl_arg) info->label);
 
1925
            }
 
1926
        if (*info->label == 0)
 
1927
          {
 
1928
            strncpy (info->label, info->cmd, sizeof (info->label));
 
1929
            info->label[sizeof (info->label) - 1] = 0;
 
1930
          }
 
1931
        MUTEX_EXIT_IRQRESTORE (mdev->mutex, flags);
 
1932
      }
 
1933
      return 0;
 
1934
      break;
 
1935
#endif
 
1936
 
 
1937
    case SNDCTL_CARDINFO:
 
1938
      {
 
1939
        int card, err;
 
1940
 
 
1941
        oss_card_info *info = (oss_card_info *) arg;
 
1942
        card = info->card;
 
1943
 
 
1944
        if (card < 0 || card >= oss_num_cards)
 
1945
          {
 
1946
            return OSS_ENXIO;
 
1947
          }
 
1948
 
 
1949
        memset ((char *) info, 0, sizeof (*info));
 
1950
        if ((err = oss_get_cardinfo (card, info)) < 0)
 
1951
          return err;
 
1952
        info->card = card;
 
1953
      }
 
1954
      return 0;
 
1955
      break;
 
1956
 
 
1957
    case SNDCTL_MIXERINFO:
 
1958
      {
 
1959
        int dev;
 
1960
 
 
1961
        oss_mixerinfo *info = (oss_mixerinfo *) arg;
 
1962
        mixer_operations_t *mdev;
 
1963
 
 
1964
        dev = info->dev;
 
1965
 
 
1966
        if (dev == -1)          /* Request for the current device */
 
1967
          switch (class)
 
1968
            {
 
1969
            case OSS_DEV_MIXER:
 
1970
              dev = orig_dev;
 
1971
              break;
 
1972
 
 
1973
            default:
 
1974
              return OSS_EINVAL;
 
1975
            }
 
1976
 
 
1977
        if (dev < 0 || dev >= num_mixers)
 
1978
          {
 
1979
            return OSS_ENXIO;
 
1980
          }
 
1981
 
 
1982
        if (mixer_devs[dev] == NULL)
 
1983
          return OSS_ENXIO;
 
1984
 
 
1985
        memset ((char *) info, 0, sizeof (*info));
 
1986
        touch_mixer (dev);
 
1987
 
 
1988
        mdev = mixer_devs[dev];
 
1989
        info->dev = dev;
 
1990
        strncpy (info->name, mdev->name, sizeof (info->name));
 
1991
        info->name[sizeof (info->name) - 1] = '\0';
 
1992
        strcpy (info->id, mdev->id);
 
1993
        strcpy (info->handle, mdev->handle);
 
1994
        info->card_number = mdev->card_number;
 
1995
        info->port_number = mdev->port_number;
 
1996
        info->enabled = (mdev->enabled && !mdev->unloaded);
 
1997
        info->magic = mdev->magic;
 
1998
        info->caps = mdev->caps;
 
1999
        info->flags = mdev->flags;
 
2000
        info->modify_counter = mdev->modify_counter;
 
2001
        info->nrext = mdev->nr_ext;
 
2002
        info->priority = mdev->priority;
 
2003
        strcpy (info->devnode, mdev->devnode);
 
2004
        info->legacy_device = mdev->real_dev;
 
2005
      }
 
2006
      return 0;
 
2007
      break;
 
2008
 
 
2009
    case OSSCTL_RENUM_AUDIODEVS:
 
2010
      {
 
2011
        oss_renumber_t *r = (oss_renumber_t *) arg;
 
2012
        int i;
 
2013
 
 
2014
#ifdef GET_PROCESS_UID
 
2015
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2016
          return OSS_EINVAL;
 
2017
#endif
 
2018
 
 
2019
        if (r->n != num_audio_devfiles) /* Wrong map size? */
 
2020
          {
 
2021
            cmn_err (CE_NOTE, "Legacy audio map size mismatch %d/%d\n",
 
2022
                     r->n, num_audio_devfiles);
 
2023
            return OSS_EINVAL;
 
2024
          }
 
2025
 
 
2026
        for (i = 0; i < r->n; i++)
 
2027
          {
 
2028
            adev_p adev = audio_devfiles[i];
 
2029
 
 
2030
            if (r->map[i] >= HARD_MAX_AUDIO_DEVFILES)   /* May be unnecessary check */
 
2031
              return OSS_EINVAL;
 
2032
 
 
2033
            if (r->map[i] < -1)
 
2034
              r->map[i] = -1;
 
2035
 
 
2036
            adev->real_dev = r->map[i];
 
2037
          }
 
2038
      }
 
2039
      return 0;
 
2040
      break;
 
2041
 
 
2042
    case OSSCTL_RENUM_MIXERDEVS:
 
2043
      {
 
2044
        oss_renumber_t *r = (oss_renumber_t *) arg;
 
2045
        int i;
 
2046
 
 
2047
#ifdef GET_PROCESS_UID
 
2048
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2049
          return OSS_EINVAL;
 
2050
#endif
 
2051
 
 
2052
        if (r->n != num_mixers) /* Wrong map size? */
 
2053
          return OSS_EINVAL;
 
2054
 
 
2055
        for (i = 0; i < r->n; i++)
 
2056
          {
 
2057
            mixdev_p mdev = mixer_devs[i];
 
2058
 
 
2059
            if (r->map[i] >= HARD_MAX_AUDIO_DEVFILES)   /* May be unnecessary check */
 
2060
              return OSS_EINVAL;
 
2061
 
 
2062
            mdev->real_dev = r->map[i];
 
2063
          }
 
2064
      }
 
2065
      return 0;
 
2066
      break;
 
2067
 
 
2068
    case OSSCTL_RENUM_MIDIDEVS:
 
2069
      {
 
2070
        oss_renumber_t *r = (oss_renumber_t *) arg;
 
2071
        int i;
 
2072
 
 
2073
#ifdef GET_PROCESS_UID
 
2074
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2075
          return OSS_EINVAL;
 
2076
#endif
 
2077
 
 
2078
        if (r->n != num_mididevs)       /* Wrong map size? */
 
2079
          return OSS_EINVAL;
 
2080
 
 
2081
        for (i = 0; i < r->n; i++)
 
2082
          {
 
2083
            mididev_p mdev = midi_devs[i];
 
2084
 
 
2085
            if (r->map[i] >= HARD_MAX_AUDIO_DEVFILES)   /* May be unnecessary check */
 
2086
              return OSS_EINVAL;
 
2087
 
 
2088
            mdev->real_dev = r->map[i];
 
2089
          }
 
2090
      }
 
2091
      return 0;
 
2092
      break;
 
2093
 
 
2094
#ifdef CONFIG_OSS_VMIX
 
2095
    case VMIXCTL_ATTACH:
 
2096
#ifdef GET_PROCESS_UID
 
2097
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2098
          return OSS_EINVAL;
 
2099
#endif
 
2100
      return vmixctl_attach((vmixctl_attach_t*)arg);
 
2101
      break;
 
2102
 
 
2103
    case VMIXCTL_DETACH:
 
2104
#ifdef GET_PROCESS_UID
 
2105
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2106
          return OSS_EINVAL;
 
2107
#endif
 
2108
      return vmixctl_detach((vmixctl_attach_t*)arg);
 
2109
      break;
 
2110
 
 
2111
    case VMIXCTL_RATE:
 
2112
#ifdef GET_PROCESS_UID
 
2113
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2114
          return OSS_EINVAL;
 
2115
#endif
 
2116
      return vmixctl_rate((vmixctl_rate_t*)arg);
 
2117
      break;
 
2118
 
 
2119
    case VMIXCTL_REMAP:
 
2120
#ifdef GET_PROCESS_UID
 
2121
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2122
          return OSS_EINVAL;
 
2123
#endif
 
2124
      return vmixctl_map_channels((vmixctl_map_t *)arg);
 
2125
      break;
 
2126
 
 
2127
#endif
 
2128
 
 
2129
#if 0
 
2130
/*
 
2131
 * These calls are obsolete and disabled in current OSS version.
 
2132
 */
 
2133
    case OSSCTL_GET_REROUTE:
 
2134
      {
 
2135
        oss_reroute_t *r = (oss_reroute_t *) arg;
 
2136
 
 
2137
#ifdef GET_PROCESS_UID
 
2138
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2139
          {
 
2140
            return OSS_EINVAL;
 
2141
          }
 
2142
#endif
 
2143
 
 
2144
        switch (r->mode)
 
2145
          {
 
2146
          case OPEN_READ:
 
2147
            memcpy (&r->devlist, &dspinlist, sizeof (oss_devlist_t));
 
2148
            break;
 
2149
 
 
2150
          case OPEN_WRITE:
 
2151
#ifdef MANAGE_DEV_DSP
 
2152
#ifdef VDEV_SUPPORT
 
2153
            oss_combine_write_lists ();
 
2154
#endif
 
2155
#endif
 
2156
            memcpy (&r->devlist, &dspoutlist, sizeof (oss_devlist_t));
 
2157
            break;
 
2158
 
 
2159
          case OPEN_WRITE | OPEN_READ:
 
2160
            memcpy (&r->devlist, &dspinoutlist, sizeof (oss_devlist_t));
 
2161
            break;
 
2162
 
 
2163
          default:
 
2164
            return OSS_EINVAL;
 
2165
          }
 
2166
      }
 
2167
      return 0;
 
2168
      break;
 
2169
 
 
2170
#if 0
 
2171
    case OSSCTL_SET_REROUTE:
 
2172
      {
 
2173
        oss_reroute_t *r = (oss_reroute_t *) arg;
 
2174
        int i, d;
 
2175
 
 
2176
#ifdef GET_PROCESS_UID
 
2177
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2178
          return OSS_EINVAL;
 
2179
#endif
 
2180
 
 
2181
        for (i = 0; i < r->devlist.ndevs; i++)
 
2182
          {
 
2183
            if ((d = r->devlist.devices[i]) < 0 || d >= num_audio_devfiles)
 
2184
              return OSS_EINVAL;
 
2185
          }
 
2186
 
 
2187
        switch (r->mode)
 
2188
          {
 
2189
          case OPEN_READ:
 
2190
            /* Refuse if number of devices has changed */
 
2191
            if (!check_list (&r->devlist, &dspinlist))
 
2192
              {
 
2193
                return OSS_EINVAL;
 
2194
              }
 
2195
            memcpy (&dspinlist, &r->devlist, sizeof (oss_devlist_t));
 
2196
            break;
 
2197
 
 
2198
          case OPEN_WRITE:
 
2199
#ifdef MANAGE_DEV_DSP
 
2200
#ifdef VDEV_SUPPORT
 
2201
            oss_combine_write_lists ();
 
2202
#endif
 
2203
#endif
 
2204
            /* Refuse if number of devices has changed */
 
2205
            if (!check_list (&r->devlist, &dspoutlist))
 
2206
              {
 
2207
                return OSS_EINVAL;
 
2208
              }
 
2209
            memcpy (&dspoutlist, &r->devlist, sizeof (oss_devlist_t));
 
2210
            dspoutlist2.ndevs = 0;
 
2211
            break;
 
2212
 
 
2213
          case OPEN_WRITE | OPEN_READ:
 
2214
            /* Refuse if number of devices has changed */
 
2215
            if (!check_list (&r->devlist, &dspinoutlist))
 
2216
              {
 
2217
                return OSS_EINVAL;
 
2218
              }
 
2219
            memcpy (&dspinoutlist, &r->devlist, sizeof (oss_devlist_t));
 
2220
            break;
 
2221
 
 
2222
          default:
 
2223
            return OSS_EINVAL;
 
2224
          }
 
2225
      }
 
2226
      return 0;
 
2227
      break;
 
2228
#endif
 
2229
 
 
2230
#ifdef APPLIST_SUPPORT
 
2231
    case OSSCTL_RESET_APPLIST:
 
2232
#ifdef GET_PROCESS_UID
 
2233
      if (GET_PROCESS_UID () != 0)      /* Not root */
 
2234
        return OSS_EINVAL;
 
2235
#endif
 
2236
 
 
2237
      oss_applist_size = 0;
 
2238
      return 0;
 
2239
      break;
 
2240
 
 
2241
    case OSSCTL_ADD_APPLIST:
 
2242
      {
 
2243
        app_routing_t *def, *parm = (app_routing_t *) arg;
 
2244
 
 
2245
#ifdef GET_PROCESS_UID
 
2246
        if (GET_PROCESS_UID () != 0)    /* Not root */
 
2247
          return OSS_EINVAL;
 
2248
#endif
 
2249
 
 
2250
        if (oss_applist_size >= APPLIST_SIZE)
 
2251
          return OSS_ENOSPC;
 
2252
 
 
2253
        if (parm->dev < -1 || parm->dev >= num_audio_devfiles)
 
2254
          return OSS_ENXIO;
 
2255
 
 
2256
        def = &oss_applist[oss_applist_size];
 
2257
 
 
2258
        memset (def, 0, sizeof (*def));
 
2259
        strcpy (def->name, parm->name);
 
2260
        def->mode = parm->mode & (OPEN_READ | OPEN_WRITE);
 
2261
        def->dev = parm->dev;
 
2262
        def->open_flags = parm->open_flags;
 
2263
        oss_applist_size++;
 
2264
        return 0;
 
2265
      }
 
2266
      break;
 
2267
 
 
2268
#endif
 
2269
#endif
 
2270
    default:
 
2271
#if 0
 
2272
      if (mixer_devs[orig_dev]->d->ioctl != NULL)
 
2273
         return mixer_devs[orig_dev]->d->ioctl (orig_dev, -1, cmd, arg);
 
2274
#endif
 
2275
 
 
2276
      return OSS_EINVAL;
 
2277
    }
 
2278
}
 
2279
 
 
2280
/*ARGSUSED*/
 
2281
static int
 
2282
oss_mixer_open (int dev, int dev_type, struct fileinfo *file, int recursive,
 
2283
                int open_flags, int *newdev)
 
2284
{
 
2285
/*
 
2286
 * Permit opening nonexistent mixer so that certain mixer ioctl calls
 
2287
 * can be called. Other code must check that the devices really exist
 
2288
 * before permitting the calls.
 
2289
 */
 
2290
  if (dev >= 0 && dev < num_mixers)
 
2291
    return 0;
 
2292
 
 
2293
  if (mixer_devs == NULL)
 
2294
    return 0;
 
2295
 
 
2296
  if (mixer_devs[dev]->unloaded)
 
2297
    return OSS_ENODEV;
 
2298
 
 
2299
  if (!mixer_devs[dev]->enabled)
 
2300
    return OSS_ENXIO;
 
2301
 
 
2302
  return 0;
 
2303
}
 
2304
 
 
2305
/*ARGSUSED*/
 
2306
static void
 
2307
oss_mixer_release (int dev, struct fileinfo *file)
 
2308
{
 
2309
}
 
2310
 
 
2311
/*ARGSUSED*/
 
2312
int
 
2313
oss_mixer_ioctl (int dev, struct fileinfo *bogus,
 
2314
                 unsigned int cmd, ioctl_arg arg)
 
2315
{
 
2316
  int ret;
 
2317
 
 
2318
  if (cmd == OSS_GETVERSION)
 
2319
    return *arg = OSS_VERSION;
 
2320
 
 
2321
/*
 
2322
 * Handle SNDCTL_SYSINFO/CARDINFO/etc even if there are no mixer devices in the
 
2323
 * system.
 
2324
 */
 
2325
  switch (cmd)
 
2326
  {
 
2327
      case OSS_GETVERSION:
 
2328
      case SNDCTL_SYSINFO:
 
2329
      case SNDCTL_CARDINFO:
 
2330
      case SNDCTL_MIXERINFO:
 
2331
      case SNDCTL_MIDIINFO:
 
2332
      case SNDCTL_AUDIOINFO:
 
2333
      case SNDCTL_AUDIOINFO_EX:
 
2334
      case SNDCTL_ENGINEINFO:
 
2335
      case OSSCTL_RENUM_AUDIODEVS:
 
2336
      case OSSCTL_RENUM_MIXERDEVS:
 
2337
      case OSSCTL_RENUM_MIDIDEVS:
 
2338
      case SNDCTL_MIX_EXTINFO:
 
2339
      case SNDCTL_MIX_ENUMINFO:
 
2340
      case SNDCTL_MIX_READ:
 
2341
      case SNDCTL_MIX_WRITE:
 
2342
      case SNDCTL_MIX_NRMIX:
 
2343
      case SNDCTL_MIX_MATRIX_WRITE:
 
2344
      case SNDCTL_MIX_MATRIX_READ:
 
2345
      case VMIXCTL_ATTACH:
 
2346
      case VMIXCTL_DETACH:
 
2347
      case VMIXCTL_RATE:
 
2348
         return oss_mixer_ext (dev, OSS_DEV_MIXER, cmd, arg);
 
2349
         break;
 
2350
  }
 
2351
 
 
2352
  if (dev < 0 || dev >= num_mixers)
 
2353
    {
 
2354
      return OSS_ENXIO;
 
2355
    }
 
2356
 
 
2357
  if (mixer_devs == NULL)
 
2358
    {
 
2359
      return OSS_ENXIO;
 
2360
    }
 
2361
 
 
2362
  if (!mixer_devs[dev]->enabled || mixer_devs[dev]->unloaded)
 
2363
    {
 
2364
      return OSS_ENODEV;
 
2365
    }
 
2366
 
 
2367
  if ((ret = oss_legacy_mixer_ioctl (dev, -1, cmd, arg)) != OSS_EINVAL)
 
2368
    {
 
2369
      return ret;
 
2370
    }
 
2371
 
 
2372
  return oss_mixer_ext (dev, OSS_DEV_MIXER, cmd, arg);
 
2373
}
 
2374
 
 
2375
#ifdef DO_TIMINGS
 
2376
 
 
2377
static char timing_buf[256 * 1024] = { 0 }, *timing_ptr = timing_buf;
 
2378
static int timing_prev_time = 0;
 
2379
int timing_flags = 0x7fffffff;
 
2380
 
 
2381
#define TM_SCALE 256
 
2382
static oss_timing_timer_func tmfunc = NULL;
 
2383
static void *tmfunc_arg = NULL;
 
2384
 
 
2385
void
 
2386
timing_install_timer (oss_timing_timer_func f, void *x)
 
2387
{
 
2388
  tmfunc = f;
 
2389
  tmfunc_arg = x;
 
2390
}
 
2391
 
 
2392
static void
 
2393
oss_do_timing_ (char *txt)
 
2394
{
 
2395
  int l = strlen (txt) + 20;
 
2396
  oss_native_word flags;
 
2397
  oss_native_word this_time;
 
2398
 
 
2399
  if (!timing_is_active) /* Nobody is listening */
 
2400
     return;
 
2401
 
 
2402
  MUTEX_ENTER_IRQDISABLE (oss_timing_mutex, flags);
 
2403
  if ((long) (&timing_buf[sizeof (timing_buf)] - timing_ptr - 8) <= l)
 
2404
    {
 
2405
      MUTEX_EXIT_IRQRESTORE (oss_timing_mutex, flags);
 
2406
      return;
 
2407
    }
 
2408
 
 
2409
  if (tmfunc != NULL)
 
2410
    {
 
2411
      this_time = tmfunc (tmfunc_arg);
 
2412
    }
 
2413
  else
 
2414
    {
 
2415
      this_time = 0;            /* TODO: Get the actual audio pointer */
 
2416
 
 
2417
      if (this_time == 0)
 
2418
        this_time = GET_JIFFIES ();
 
2419
    }
 
2420
 
 
2421
  sprintf (timing_ptr, "%ld/%d: %s\n", this_time,
 
2422
           this_time - timing_prev_time, txt);
 
2423
  l = strlen (timing_ptr);
 
2424
  timing_ptr += l;
 
2425
  timing_prev_time = this_time;
 
2426
  MUTEX_EXIT_IRQRESTORE (oss_timing_mutex, flags);
 
2427
}
 
2428
 
 
2429
typedef struct
 
2430
{
 
2431
  oss_native_word sum;
 
2432
  oss_native_word open_time;
 
2433
}
 
2434
timing_entry;
 
2435
 
 
2436
static timing_entry timing_bins[DF_NRBINS];
 
2437
static oss_native_word timing_start = 0;
 
2438
 
 
2439
static char *bin_names[DF_NRBINS] = {
 
2440
  "Iddle",
 
2441
  "Write",
 
2442
  "Read",
 
2443
  "Interrupt",
 
2444
  "Write sleep",
 
2445
  "Read sleep",
 
2446
  "Write SRC",
 
2447
  "Read SRC"
 
2448
};
 
2449
 
 
2450
void
 
2451
timing_open (void)
 
2452
{
 
2453
  int i;
 
2454
 
 
2455
  if (tmfunc == NULL)
 
2456
    return;
 
2457
  timing_start = tmfunc (tmfunc_arg) / TM_SCALE;
 
2458
 
 
2459
  for (i = 0; i < DF_NRBINS; i++)
 
2460
    {
 
2461
      timing_bins[i].sum = 0;
 
2462
      timing_bins[i].open_time = 0xffffffff;
 
2463
    }
 
2464
 
 
2465
}
 
2466
 
 
2467
void
 
2468
timing_close (void)
 
2469
{
 
2470
  char tmp[64];
 
2471
  int i;
 
2472
  oss_native_word t, sum, pc;
 
2473
  if (tmfunc == NULL)
 
2474
    return;
 
2475
 
 
2476
  t = tmfunc (tmfunc_arg) / TM_SCALE - timing_start;
 
2477
 
 
2478
  sprintf (tmp, "Timing close, elapsed=%d", t);
 
2479
  oss_do_timing2 (DFLAG_PROFILE, tmp);
 
2480
 
 
2481
  sum = 0;
 
2482
 
 
2483
  for (i = 0; i < DF_NRBINS; i++)
 
2484
    {
 
2485
      sum += timing_bins[i].sum;
 
2486
      pc = (timing_bins[i].sum * 1000) / t;
 
2487
      sprintf (tmp, "Bin %s: %d/%d (%d.%d%%)", bin_names[i],
 
2488
               timing_bins[i].sum, pc, pc / 10, pc % 10);
 
2489
      oss_do_timing2 (DFLAG_PROFILE, tmp);
 
2490
    }
 
2491
 
 
2492
  /* sum = sum-timing_bins[DF_SLEEPWRITE].sum-timing_bins[DF_SLEEPREAD].sum; */
 
2493
  pc = (sum * 10000) / t;
 
2494
 
 
2495
  sprintf (tmp, "OSS Total: %d (%d.%d%%)", sum, pc / 100, pc % 100);
 
2496
  oss_do_timing2 (DFLAG_PROFILE, tmp);
 
2497
}
 
2498
 
 
2499
void
 
2500
oss_timing_enter (int bin)
 
2501
{
 
2502
  if (tmfunc == NULL)
 
2503
    return;
 
2504
 
 
2505
  timing_bins[bin].open_time = tmfunc (tmfunc_arg) / TM_SCALE;
 
2506
}
 
2507
 
 
2508
void
 
2509
oss_timing_leave (int bin)
 
2510
{
 
2511
  oss_native_word t;
 
2512
 
 
2513
  if (tmfunc == NULL)
 
2514
    return;
 
2515
 
 
2516
  if (timing_bins[bin].open_time >= 0xfffffffe)
 
2517
    return;
 
2518
 
 
2519
  t = tmfunc (tmfunc_arg) / TM_SCALE - timing_bins[bin].open_time;
 
2520
  timing_bins[bin].sum += t;
 
2521
  timing_bins[bin].open_time = 0xfffffffe;
 
2522
}
 
2523
 
 
2524
void
 
2525
oss_do_timing (char *txt)
 
2526
{
 
2527
  if (!timing_is_active) /* Nobody is listening */
 
2528
     return;
 
2529
 
 
2530
  if (timing_flags & DFLAG_ALL)
 
2531
    oss_do_timing_ (txt);
 
2532
}
 
2533
 
 
2534
void
 
2535
oss_do_timing2 (int mask, char *txt)
 
2536
{
 
2537
  if (!timing_is_active) /* Nobody is listening */
 
2538
     return;
 
2539
 
 
2540
  if ((timing_flags & DFLAG_ALL) || (timing_flags & mask))
 
2541
    oss_do_timing_ (txt);
 
2542
}
 
2543
 
 
2544
void
 
2545
oss_timing_printf (char *s, ...)
 
2546
{
 
2547
  char tmp[1024], *a[6];
 
2548
  va_list ap;
 
2549
  int i, n = 0;
 
2550
 
 
2551
  if (!timing_is_active) /* Nobody is listening */
 
2552
     return;
 
2553
 
 
2554
  va_start (ap, s);
 
2555
 
 
2556
  for (i = 0; i < strlen (s); i++)
 
2557
    if (s[i] == '%')
 
2558
      n++;
 
2559
 
 
2560
  for (i = 0; i < n && i < 6; i++)
 
2561
    a[i] = va_arg (ap, char *);
 
2562
 
 
2563
  for (i = n; i < 6; i++)
 
2564
    a[i] = NULL;
 
2565
 
 
2566
      sprintf (tmp, s, a[0], a[1], a[2], a[3], a[4], a[5], NULL,
 
2567
               NULL, NULL, NULL);
 
2568
      oss_do_timing(tmp);
 
2569
 
 
2570
  va_end (ap);
 
2571
}
 
2572
 
 
2573
static int
 
2574
timing_read (int dev, struct fileinfo *file, uio_t * buf, int count)
 
2575
{
 
2576
  /*
 
2577
   * Return at most 'count' bytes from the status_buf.
 
2578
   */
 
2579
  int l;
 
2580
  oss_native_word flags;
 
2581
 
 
2582
  timing_is_active = 1;
 
2583
 
 
2584
  MUTEX_ENTER_IRQDISABLE (oss_timing_mutex, flags);
 
2585
 
 
2586
  l = timing_ptr - timing_buf;
 
2587
  if (l <= 0)
 
2588
    {
 
2589
      MUTEX_EXIT_IRQRESTORE (oss_timing_mutex, flags);
 
2590
      return 0;
 
2591
    }
 
2592
 
 
2593
  if (l > count)
 
2594
    l = count;
 
2595
 
 
2596
  timing_ptr = timing_buf;
 
2597
 
 
2598
  MUTEX_EXIT_IRQRESTORE (oss_timing_mutex, flags);
 
2599
 
 
2600
  if (uiomove (timing_buf, l, UIO_READ, buf) != 0)
 
2601
    cmn_err (CE_WARN, "audio: uiomove(UIO_READ) failed\n");
 
2602
 
 
2603
  return l;
 
2604
}
 
2605
#else
 
2606
/*
 
2607
 * Dummy wrappers
 
2608
 */
 
2609
 
 
2610
/*ARGSUSED*/
 
2611
void
 
2612
oss_timing_enter (int bin)
 
2613
{
 
2614
}
 
2615
 
 
2616
/*ARGSUSED*/
 
2617
void
 
2618
oss_timing_leave (int bin)
 
2619
{
 
2620
}
 
2621
 
 
2622
/*ARGSUSED*/
 
2623
void
 
2624
oss_do_timing (char *txt)
 
2625
{
 
2626
}
 
2627
 
 
2628
/*ARGSUSED*/
 
2629
void
 
2630
oss_do_timing2 (int mask, char *txt)
 
2631
{
 
2632
}
 
2633
 
 
2634
/*ARGSUSED*/
 
2635
void
 
2636
oss_timing_printf (char *s, ...)
 
2637
{
 
2638
}
 
2639
#endif
 
2640
 
 
2641
static oss_cdev_drv_t mixer_cdev_drv = {
 
2642
  oss_mixer_open,
 
2643
  oss_mixer_release,
 
2644
#ifdef DO_TIMINGS
 
2645
  timing_read,
 
2646
#else
 
2647
  NULL,                         /* read */
 
2648
#endif
 
2649
  NULL,                         /* write */
 
2650
  oss_mixer_ioctl
 
2651
};
 
2652
 
 
2653
int
 
2654
oss_install_mixer (int vers,
 
2655
                   oss_device_t * osdev,
 
2656
                   oss_device_t * master_osdev,
 
2657
                   const char *name,
 
2658
                   mixer_driver_t * driver, int driver_size, void *devc)
 
2659
{
 
2660
  mixer_operations_t *op = NULL;
 
2661
  mixer_driver_t *d;
 
2662
 
 
2663
  int i, num;
 
2664
  char handle[32];
 
2665
 
 
2666
  if (master_osdev == NULL)
 
2667
    master_osdev = osdev;
 
2668
 
 
2669
  if (mixer_devs == NULL)
 
2670
    {
 
2671
      mixer_devs = PMALLOC (osdev, sizeof (mixdev_p) * MAX_MIXER_DEV);
 
2672
      memset (mixer_devs, 0, sizeof (mixdev_p) * MAX_MIXER_DEV);
 
2673
      mixer_devs_p = mixer_devs;
 
2674
    }
 
2675
 
 
2676
  if (num_mixers >= MAX_MIXER_DEV - 1)
 
2677
    {
 
2678
      static int nnn = 0;
 
2679
      cmn_err (CE_WARN, "Too many mixer devices %d/%d (%s)\n",
 
2680
               num_mixers, MAX_MIXER_DEV, name);
 
2681
      /*
 
2682
       * In some special situations a driver may keep trying to install a mixer
 
2683
       * in infinite loop if the request fails. Stop this by panicking after
 
2684
       * this has continued for more than 50 times. In this case we can get an
 
2685
       * error message instead of having the system to lock up foreever.
 
2686
       */
 
2687
      if (nnn++ > 50)
 
2688
        cmn_err (CE_PANIC, "Killing runaway system.\n");
 
2689
      return OSS_EIO;
 
2690
    }
 
2691
 
 
2692
  if (vers != OSS_MIXER_DRIVER_VERSION)
 
2693
    {
 
2694
      cmn_err (CE_WARN, "Incompatible mixer driver for %s\n", name);
 
2695
      return OSS_EIO;
 
2696
    }
 
2697
 
 
2698
  if (driver_size > sizeof (mixer_driver_t))
 
2699
    driver_size = sizeof (mixer_driver_t);
 
2700
 
 
2701
/*
 
2702
 * Check if this device was earlier unloaded and now returning back.
 
2703
 */
 
2704
  num = -1;
 
2705
  for (i = 0; i < num_mixers; i++)
 
2706
    {
 
2707
      if (mixer_devs[i]->unloaded
 
2708
          && mixer_devs[i]->os_id == oss_get_osid (osdev))
 
2709
        {
 
2710
          op = mixer_devs[i];
 
2711
          num = i;
 
2712
          break;
 
2713
        }
 
2714
    }
 
2715
 
 
2716
  if ((d = PMALLOC (osdev, sizeof (*d))) == NULL)
 
2717
    {
 
2718
      cmn_err (CE_WARN, "Can't allocate mixer driver for (%s)\n", name);
 
2719
      return OSS_ENOSPC;
 
2720
    }
 
2721
 
 
2722
  if (num == -1)
 
2723
    {
 
2724
      op = PMALLOC (osdev, sizeof (mixer_operations_t));
 
2725
      if (op == NULL)
 
2726
        {
 
2727
          cmn_err (CE_WARN, "Can't allocate mixer driver for (%s)\n", name);
 
2728
          return OSS_ENOSPC;
 
2729
        }
 
2730
 
 
2731
      memset ((char *) op, 0, sizeof (mixer_operations_t));
 
2732
      num = num_mixers++;
 
2733
      sprintf (handle, "%s-mx%02d", osdev->handle, osdev->num_mixerdevs+1);
 
2734
      op->port_number = osdev->num_mixerdevs++;
 
2735
    }
 
2736
  else
 
2737
    {
 
2738
      strcpy (handle, op->handle);      /* Preserve the previous handle */
 
2739
    }
 
2740
 
 
2741
  memset ((char *) d, 0, sizeof (mixer_driver_t));
 
2742
  memcpy ((char *) d, (char *) driver, driver_size);
 
2743
  strcpy (op->handle, handle);
 
2744
  strcpy (op->id, osdev->nick);
 
2745
  op->d = d;
 
2746
 
 
2747
  strncpy (op->name, name, sizeof (op->name));
 
2748
  op->name[sizeof (op->name) - 1] = 0;
 
2749
  op->devc = devc;
 
2750
  op->osdev = osdev;
 
2751
  op->os_id = oss_get_osid (osdev);
 
2752
  op->master_osdev = master_osdev;
 
2753
  op->hw_devc = NULL;
 
2754
  op->max_ext = op->nr_ext = 0;
 
2755
  op->names_checked = 0;
 
2756
  op->extensions = NULL;
 
2757
  op->timestamp = GET_JIFFIES ();
 
2758
  op->ignore_mask = 0;
 
2759
  op->card_number = osdev->cardnum;
 
2760
  op->enabled = 1;
 
2761
  op->unloaded = 0;
 
2762
  op->flags = 0;
 
2763
  op->caps = 0;
 
2764
  op->priority = 0;             /* Normal (low) priority */
 
2765
  op->real_dev = num;
 
2766
 
 
2767
  if (osdev->first_mixer == -1) /* Not defined yet */
 
2768
     osdev->first_mixer = num;
 
2769
 
 
2770
  mixer_devs[num] = op;
 
2771
/*
 
2772
 * Create the device node
 
2773
 */
 
2774
 
 
2775
  {
 
2776
    oss_devnode_t name;
 
2777
 
 
2778
#ifdef NEW_DEVICE_NAMING
 
2779
# ifdef USE_DEVICE_SUBDIRS
 
2780
    sprintf (name, "oss/%s/mix%d", osdev->nick, osdev->num_mixerdevs - 1);
 
2781
# else
 
2782
    sprintf (name, "%s_mix%d", osdev->nick, osdev->num_mixerdevs - 1);
 
2783
# endif
 
2784
#else
 
2785
    sprintf (name, "mixer%d", num);
 
2786
#endif
 
2787
    oss_install_chrdev (osdev, name, OSS_DEV_MIXER, num, &mixer_cdev_drv, 0);
 
2788
    sprintf (op->devnode, "/dev/%s", name);
 
2789
 
 
2790
#if 0
 
2791
    /*
 
2792
     * Moved to install_dev_mixer()
 
2793
     */
 
2794
    if (num == 0)
 
2795
      {
 
2796
        oss_install_chrdev (osdev, "mixer", OSS_DEV_MIXER, num,
 
2797
                            &mixer_cdev_drv, 0);
 
2798
      }
 
2799
#endif
 
2800
  }
 
2801
 
 
2802
  return num;
 
2803
}
 
2804
 
 
2805
void
 
2806
install_dev_mixer (oss_device_t * osdev)
 
2807
{
 
2808
/*
 
2809
 * Install the default mixer node if necessary
 
2810
 */
 
2811
  oss_install_chrdev (osdev, "mixer", OSS_DEV_MIXER, 0, &mixer_cdev_drv, 0);
 
2812
}