2
* Purpose: Legacy sound device management utility
5
* Device file naming scheme was changed in OSS 4.0. This utility is used
6
* to create old style "legacy" device files such as /dev/dsp0 to the
7
* corresponding new type name (such as /dev/oss/oss_sblive0/pcm0).
9
* By default the currently existing device links will be preserved. Legacy
10
* devices for newly installed devices will be allocated after the
11
* previously available devices.
13
* Commad line options:
14
* -f Write legacydev file to <argument>.
15
* -v Produce verbose output.
16
* -r Remove all pre-existing legacy devices and reset the device
17
* numbering (not recommended).
18
* -N Don't modify links
22
* This file is part of Open Sound System.
24
* Copyright (C) 4Front Technologies 1996-2008.
26
* This this source file is released under GPL v2 license (no other versions).
27
* See the COPYING file included in the main directory of this source
28
* distribution for the license terms and conditions.
40
#include <sys/types.h>
42
#include <sys/ioctl.h>
43
#include "oss_config.h"
45
#define MAXDEV HARD_MAX_AUDIO_DEVFILES
47
static oss_sysinfo si;
49
static char * legacydev_file = "/etc/oss/legacy_devices";
51
static char * legacydev_file = NULL;
53
static int err = 0, mixerfd = -1, recreate_all = 0, verbose = 0,
56
static void create_dsplinks (void);
57
static void create_mixerlinks (void);
58
static int find_dsplink (oss_audioinfo *);
59
static int find_mixerlink (oss_mixerinfo *);
60
static void save_link (FILE *, char *);
61
static void save_links (void);
62
static int remove_nodes (const char *, const char *);
63
#ifdef CONFIG_OSS_MIDI
64
static void create_midilinks (void);
65
static int find_midilink (oss_midi_info *);
76
#define DEFAULT_OSSLIBDIR "/etc/oss"
78
#define DEFAULT_OSSLIBDIR "/usr/lib/oss"
85
#define OSSLIBDIRLEN PATH_MAX
86
char tmp[OSSLIBDIRLEN+11];
87
static char name[OSSLIBDIRLEN];
90
if ((f = fopen ("/etc/oss.conf", "r")) == NULL)
92
// perror ("/etc/oss.conf");
96
while (fgets (tmp, sizeof (tmp), f) != NULL)
99
if (l > 0 && tmp[l - 1] == '\n')
102
if (strncmp (tmp, "OSSLIBDIR=", 10) == 0)
104
l = snprintf (name, sizeof (name), "%s", &tmp[10]);
105
if ((l >= OSSLIBDIRLEN) || (l < 0))
107
fprintf (stderr, "String in /etc/oss.conf is too long!\n");
110
if ((stat (name, &st) == -1) || !S_ISDIR(st.st_mode))
112
fprintf (stderr, "Directory %s from /etc/oss.conf cannot "
123
snprintf (name, sizeof (name), DEFAULT_OSSLIBDIR);
128
remove_nodes (const char * dirname, const char * pattern)
135
if ((dr = opendir (dirname)) == NULL)
137
if (errno == ENOENT) return 0;
138
fprintf (stderr, "Cannot open %s\n", dirname);
143
while ((de = readdir (dr)) != NULL)
145
if (fnmatch (pattern, de->d_name, FNM_PATHNAME | FNM_PERIOD)) continue;
147
snprintf (path, sizeof (path), "%s/%s", dirname, de->d_name);
149
/* We want to remove dangling symlinks too, so no error check here */
150
if ((stat (path, &st) != -1) &&
151
/* No nodes that ossdevlinks may need to remove are directories */
152
(S_ISDIR (st.st_mode))) continue;
153
if (verbose > 2) fprintf (stderr, "Removing %s\n", path);
154
if ((unlink (path) == -1) && (errno != ENOENT))
155
fprintf (stderr, "unlink %s: %s\n", path, strerror(errno));
163
*****************************
168
find_dsplink (oss_audioinfo * ai)
172
* Look for a legacy (/dev/dsp#) devife file that is a symlink to
173
* ai->devnode. Return the device number if a
174
* matching link is found. Return -1 if nothing is found.
178
char devname[64], linkdev[256];
180
for (dev = 0; dev < MAXDEV; dev++)
182
sprintf (devname, "/dev/dsp%d", dev);
183
if (lstat (devname, &st) != -1)
184
if (S_ISLNK (st.st_mode))
188
if ((l = readlink (devname, linkdev, sizeof (linkdev) - 1)) == -1)
195
if (strcmp (linkdev, ai->devnode) == 0) /* Match */
197
ai->legacy_device = dev;
204
return -1; /* Nothing found */
208
create_dsplinks (void)
210
int dev, newdev, numfiles = 0, legacy_number = 0;
214
oss_audioinfo *ai, *audiodevs[MAXDEV];
216
oss_renumber_t renum = { 0 };
220
if ((unlink ("/dev/dsp") == -1) && (errno != ENOENT))
221
fprintf (stderr, "Couldn't remove /dev/dsp link!\n");
222
remove_nodes ("/dev", "dsp[0-9]*");
223
remove_nodes ("/dev", "dsp_*");
226
if (verbose) printf ("%d audio devices\n", si.numaudios);
228
if (si.numaudios < 1)
231
for (dev = 0; dev < si.numaudios; dev++)
233
ai = malloc (sizeof (*ai));
237
if (ioctl (mixerfd, SNDCTL_AUDIOINFO, ai) == -1)
239
perror ("SNDCTL_AUDIOINFO");
245
/* if (verbose) printf ("Adev %d = %s\n", dev, ai->devnode); */
248
for (dev = 0; dev < MAXDEV; dev++)
251
sprintf (devname, "/dev/dsp%d", dev);
254
if (lstat (devname, &st) != -1)
256
if (S_ISLNK (st.st_mode))
261
if (verbose) printf ("/dev/dsp%d is the next free legacy device\n", numfiles);
263
for (dev = 0; dev < si.numaudios; dev++)
267
if (audiodevs[dev]->caps & PCM_CAP_HIDDEN) /* Ignore hidden devices */
269
audiodevs[dev]->legacy_device = -1;
274
newdev = legacy_number++;
275
sprintf (devname, "/dev/dsp%d", newdev);
277
if (lstat (devname, &st) == -1)
279
if (verbose) printf ("%s: %s\n", devname, strerror (errno));
284
if (S_ISCHR (st.st_mode))
286
if (verbose) printf ("%s: character device\n", devname);
289
else if (S_ISLNK (st.st_mode))
295
readlink (devname, linkdev, sizeof (linkdev) - 1)) == -1)
298
strcpy (linkdev, "Invalid");
305
if (verbose) printf ("%s: symlink -> %s ", devname, linkdev);
307
if (strcmp (linkdev, audiodevs[dev]->devnode) != 0)
309
if (verbose) printf ("(should be %s)\n",
310
audiodevs[dev]->devnode);
311
if ((newdev = find_dsplink (audiodevs[dev])) == -1)
317
if (verbose) printf ("\tAlready linked to /dev/dsp%d\n",
321
if (verbose) printf ("OK\n");
325
if (verbose) printf ("%s: unknown file type\n", devname);
333
audiodevs[dev]->legacy_device = newdev;
334
sprintf (devname, "/dev/dsp%d", newdev);
336
if (strcmp (audiodevs[dev]->devnode, devname) != 0) /* Not the same */
339
if (symlink (audiodevs[dev]->devnode, devname) == -1)
342
fprintf (stderr, "Cannot create link %s->%s\n", devname,
343
audiodevs[dev]->devnode);
347
if (verbose) printf ("Created new legacy device %s -> %s\n",
348
devname, audiodevs[dev]->devnode);
349
audiodevs[dev]->legacy_device = newdev;
354
if (verbose) printf ("%d legacy dsp device files\n", numfiles);
356
renum.n = si.numaudios;
358
for (dev = 0; dev < si.numaudios; dev++)
360
if (audiodevs[dev]->legacy_device != dev)
361
if (audiodevs[dev]->legacy_device >= 0)
362
if (verbose) printf ("Adev %d (%s) is legacy device file "
363
"/dev/dsp%d\n", dev, audiodevs[dev]->devnode,
364
audiodevs[dev]->legacy_device);
366
renum.map[dev] = audiodevs[dev]->legacy_device;
369
if (ioctl (mixerfd, OSSCTL_RENUM_AUDIODEVS, &renum) == -1)
371
perror ("audio_renum");
376
* Find out a suitable /dev/dsp device (input and output capable).
377
* Remove old /dev/dsp if it appears to be a character device node.
379
if (lstat ("/dev/dsp", &st) != -1)
380
if (S_ISCHR (st.st_mode))
384
* Remove /dev/dsp link that points to some bogus device. This may
385
* happen if some hot-pluggable (USB) device has been
386
* removed from the system.
388
if (lstat ("/dev/dsp", &st) != -1) /* /dev/dsp exists (and is symlink) */
389
if (stat ("/dev/dsp", &st) == -1) /* But points to nowhere */
393
* Next find a duplex capable audio device.
396
for (dev = 0; dev < si.numaudios; dev++)
400
if (!(ai->caps & PCM_CAP_OUTPUT))
403
if (!(ai->caps & PCM_CAP_INPUT))
406
if (ai->min_channels > 2 || ai->max_channels < 2) /* No stereo */
409
if (verbose) printf ("%s is the default /dev/dsp device\n", ai->devnode);
410
err = symlink (ai->devnode, "/dev/dsp"); /* Ignore errors */
415
* Find out a suitable /dev/dsp_out device.
418
for (dev = 0; dev < si.numaudios; dev++)
422
if (!(ai->caps & PCM_CAP_OUTPUT))
425
if (verbose) printf ("%s is the default dsp_out device\n", ai->devnode);
426
err = symlink (ai->devnode, "/dev/dsp_out"); /* Ignore errors */
429
* Also link /dev/dsp just in case the link doesn't
432
err = symlink (ai->devnode, "/dev/dsp"); /* Ignore errors */
437
* Find out a suitable /dev/dsp_in device.
440
for (dev = 0; dev < si.numaudios; dev++)
444
if (!(ai->caps & PCM_CAP_INPUT))
447
if (verbose) printf ("%s is the default dsp_in device\n", ai->devnode);
448
err = symlink (ai->devnode, "/dev/dsp_in"); /* Ignore errors */
451
* Also link /dev/dsp just in case the link doesn't
454
err = symlink (ai->devnode, "/dev/dsp"); /* Ignore errors */
459
* Find out a suitable /dev/dsp_ac3 output device.
462
for (dev = 0; dev < si.numaudios; dev++)
466
if (!(ai->caps & PCM_CAP_OUTPUT))
469
if (!(ai->oformats & AFMT_AC3))
472
if (verbose) printf ("%s is the default AC3 output device\n",
474
err = symlink (ai->devnode, "/dev/dsp_ac3"); /* Ignore errors */
479
* Find out a suitable /dev/dsp_mmap output device.
482
for (dev = 0; dev < si.numaudios; dev++)
486
if (!(ai->caps & PCM_CAP_OUTPUT))
489
if (!(ai->caps & PCM_CAP_MMAP))
492
if (!(ai->caps & PCM_CAP_TRIGGER))
495
if (ai->max_channels < 2)
498
if (ai->min_channels > 2)
501
if (verbose) printf ("%s is the default mmap output device\n",
503
err = symlink (ai->devnode, "/dev/dsp_mmap"); /* Ignore errors */
508
* Find out a suitable /dev/dsp_multich output device.
511
for (dev = 0; dev < si.numaudios; dev++)
515
if (!(ai->caps & PCM_CAP_OUTPUT))
518
if (ai->max_channels < 4)
521
if (verbose) printf ("%s is the default multichan output device\n",
523
err = symlink (ai->devnode, "/dev/dsp_multich"); /* Ignore errors */
528
* Find out a suitable /dev/dsp_spdifout output device.
531
for (dev = 0; dev < si.numaudios; dev++)
535
if (!(ai->caps & PCM_CAP_OUTPUT))
538
if (!(ai->caps & PCM_CAP_DIGITALOUT))
541
if (verbose) printf ("%s is the default S/PDIF digital output device\n",
543
err = symlink (ai->devnode, "/dev/dsp_spdifout"); /* Ignore errors */
548
* Find out a suitable /dev/dsp_spdifin input device.
551
for (dev = 0; dev < si.numaudios; dev++)
555
if (!(ai->caps & PCM_CAP_INPUT))
558
if (!(ai->caps & PCM_CAP_DIGITALIN))
561
if (verbose) printf ("%s is the default S/PDIF digital input device\n",
563
err = symlink (ai->devnode, "/dev/dsp_spdifin"); /* Ignore errors */
569
*****************************
570
* /dev/mixer handling
574
find_mixerlink (oss_mixerinfo * xi)
578
* Look for a legacy (/dev/mixer#) devife file that is a symlink to
579
* xi->devnode. Return the device number if a
580
* matching link is found. Return -1 if nothing is found.
584
char devname[64], linkdev[256];
586
for (dev = 0; dev < MAXDEV; dev++)
588
sprintf (devname, "/dev/mixer%d", dev);
589
if (lstat (devname, &st) != -1)
590
if (S_ISLNK (st.st_mode))
594
if ((l = readlink (devname, linkdev, sizeof (linkdev) - 1)) == -1)
601
if (strcmp (linkdev, xi->devnode) == 0) /* Match */
603
xi->legacy_device = dev;
610
return -1; /* Nothing found */
614
create_mixerlinks (void)
616
int dev, newdev, numfiles = 0;
620
oss_mixerinfo *xi, *mixerdevs[MAXDEV];
622
oss_renumber_t renum = { 0 };
625
remove_nodes ("/dev", "mixer[0-9]*");
627
if (verbose) printf ("%d mixer devices\n", si.nummixers);
629
if (si.nummixers < 1)
632
for (dev = 0; dev < si.nummixers; dev++)
634
xi = malloc (sizeof (*xi));
638
if (ioctl (mixerfd, SNDCTL_MIXERINFO, xi) == -1)
640
perror ("SNDCTL_MIXERINFO");
646
/* if (verbose) printf ("Mixdev %d = %s\n", dev, xi->devnode); */
649
for (dev = 0; dev < MAXDEV; dev++)
652
sprintf (devname, "/dev/mixer%d", dev);
655
if (lstat (devname, &st) != -1)
657
if (S_ISLNK (st.st_mode))
662
if (numfiles < si.nummixers)
663
numfiles = si.nummixers;
665
if (verbose) printf ("/dev/mixer%d is the next free legacy device\n",
668
for (dev = 0; dev < si.nummixers; dev++)
672
sprintf (devname, "/dev/mixer%d", dev);
675
if (lstat (devname, &st) == -1)
677
if (verbose) printf ("%s: %s\n", devname, strerror (errno));
682
if (S_ISCHR (st.st_mode))
684
if (verbose) printf ("%s: character device\n", devname);
687
else if (S_ISLNK (st.st_mode))
693
readlink (devname, linkdev, sizeof (linkdev) - 1)) == -1)
696
strcpy (linkdev, "Invalid");
703
if (verbose) printf ("%s: symlink -> %s ", devname, linkdev);
705
if (strcmp (linkdev, mixerdevs[dev]->devnode) != 0)
707
if (verbose) printf ("(should be %s)\n",
708
mixerdevs[dev]->devnode);
709
if ((newdev = find_mixerlink (mixerdevs[dev])) == -1)
715
if (verbose) printf ("\tAlready linked to /dev/mixer%d\n",
719
if (verbose) printf ("OK\n");
723
if (verbose) printf ("%s: unknown file type\n", devname);
731
mixerdevs[dev]->legacy_device = newdev;
732
sprintf (devname, "/dev/mixer%d", newdev);
734
if (strcmp (mixerdevs[dev]->devnode, devname) != 0) /* Not the same */
737
if (symlink (mixerdevs[dev]->devnode, devname) == -1)
740
fprintf (stderr, "Cannot create link %s->%s\n", devname,
741
mixerdevs[dev]->devnode);
745
if (verbose) printf ("Created new legacy device %s -> %s\n",
746
devname, mixerdevs[dev]->devnode);
751
if (verbose) printf ("%d legacy mixer device files\n", numfiles);
753
renum.n = si.nummixers;
755
for (dev = 0; dev < si.nummixers; dev++)
757
if (mixerdevs[dev]->legacy_device != dev)
758
if (verbose) printf ("Mixdev %d is legacy device file /dev/mixer%d\n",
759
dev, mixerdevs[dev]->legacy_device);
760
renum.map[dev] = mixerdevs[dev]->legacy_device;
763
if (ioctl (mixerfd, OSSCTL_RENUM_MIXERDEVS, &renum) == -1)
765
perror ("mixer_renum");
769
#ifdef CONFIG_OSS_MIDI
771
* MIDI devices (/dev/midiNN)
775
find_midilink (oss_midi_info * xi)
779
* Look for a legacy (/dev/midi#) devife file that is a symlink to
780
* xi->devnode. Return the device number if a
781
* matching link is found. Return -1 if nothing is found.
785
char devname[64], linkdev[256];
787
for (dev = 0; dev < MAXDEV; dev++)
789
sprintf (devname, "/dev/midi%02d", dev);
790
if (lstat (devname, &st) != -1)
791
if (S_ISLNK (st.st_mode))
795
if ((l = readlink (devname, linkdev, sizeof (linkdev) - 1)) == -1)
802
if (strcmp (linkdev, xi->devnode) == 0) /* Match */
804
xi->legacy_device = dev;
811
return -1; /* Nothing found */
815
create_midilinks (void)
817
int dev, newdev, numfiles = 0;
821
oss_midi_info *xi, *mididevs[MAXDEV];
823
oss_renumber_t renum = { 0 };
826
remove_nodes ("/dev", "midi[0-9]*");
828
if (si.nummidis < 1) /* No MIDI devices in the system */
831
if (verbose) printf ("%d midi devices\n", si.nummidis);
832
for (dev = 0; dev < si.nummidis; dev++)
834
xi = malloc (sizeof (*xi));
838
if (ioctl (mixerfd, SNDCTL_MIDIINFO, xi) == -1)
840
perror ("SNDCTL_MIDIINFO");
846
/* if (verbose) printf ("Mididev %d = %s\n", dev, xi->devnode); */
849
for (dev = 0; dev < MAXDEV; dev++)
852
sprintf (devname, "/dev/midi%02d", dev);
855
if (lstat (devname, &st) != -1)
857
if (S_ISLNK (st.st_mode))
862
if (numfiles < si.nummidis)
863
numfiles = si.nummidis;
865
if (verbose) printf ("/dev/midi%02d is the next free legacy device\n",numfiles);
867
for (dev = 0; dev < si.nummidis; dev++)
871
sprintf (devname, "/dev/midi%02d", dev);
874
if (lstat (devname, &st) == -1)
876
if (verbose) printf ("%s: %s\n", devname, strerror (errno));
881
if (S_ISCHR (st.st_mode))
883
if (verbose) printf ("%s: character device\n", devname);
886
else if (S_ISLNK (st.st_mode))
892
readlink (devname, linkdev, sizeof (linkdev) - 1)) == -1)
895
strcpy (linkdev, "Invalid");
902
if (verbose) printf ("%s: symlink -> %s ", devname, linkdev);
904
if (strcmp (linkdev, mididevs[dev]->devnode) != 0)
906
if (verbose) printf ("(should be %s)\n",
907
mididevs[dev]->devnode);
908
if ((newdev = find_midilink (mididevs[dev])) == -1)
914
if (verbose) printf ("\tAlready linked to /dev/midi%02d\n",
918
if (verbose) printf ("OK\n");
922
if (verbose) printf ("%s: unknown file type\n", devname);
930
mididevs[dev]->legacy_device = newdev;
931
sprintf (devname, "/dev/midi%02d", newdev);
933
if (strcmp (mididevs[dev]->devnode, devname) != 0) /* Not the same */
936
if (symlink (mididevs[dev]->devnode, devname) == -1)
939
fprintf (stderr, "Cannot create link %s->%s\n", devname,
940
mididevs[dev]->devnode);
944
if (verbose) printf ("Created new legacy device %s -> %s\n",
945
devname, mididevs[dev]->devnode);
950
if (verbose) printf ("%d legacy MIDI device files\n", numfiles);
952
renum.n = si.nummidis;
954
for (dev = 0; dev < si.nummidis; dev++)
956
if (mididevs[dev]->legacy_device != dev)
957
if (verbose) printf ("Mididev %d is legacy device file /dev/midi%02d\n",
958
dev, mididevs[dev]->legacy_device);
959
renum.map[dev] = mididevs[dev]->legacy_device;
962
if (ioctl (mixerfd, OSSCTL_RENUM_MIDIDEVS, &renum) == -1)
964
perror ("midi_renum");
970
save_link (FILE * f, char *devname)
975
if ((l = readlink (devname, linkname, sizeof (linkname) - 1)) == -1)
979
fprintf (f, "rm -f %s;ln -sf %s %s\n", devname, linkname, devname);
989
if (legacydev_file == NULL)
991
char lfile[PATH_MAX+20], * osslibdir;
993
osslibdir = get_mapname ();
994
snprintf (lfile, sizeof (lfile), "%s/%s", osslibdir, "etc/legacy_devices");
995
if ((f = fopen (lfile, "w")) == NULL)
1001
else if ((f = fopen (legacydev_file, "w")) == NULL)
1003
perror (legacydev_file);
1011
for (i = 0; i < MAXDEV; i++)
1013
sprintf (devfile, "/dev/dsp%d", i);
1014
save_link (f, devfile);
1017
save_link (f, "/dev/dsp");
1018
save_link (f, "/dev/dsp_ac3");
1019
save_link (f, "/dev/dsp_in");
1020
save_link (f, "/dev/dsp_mmap");
1021
save_link (f, "/dev/dsp_multich");
1022
save_link (f, "/dev/dsp_out");
1023
save_link (f, "/dev/dsp_spdifout");
1024
save_link (f, "/dev/dsp_spdifin");
1030
for (i = 0; i < MAXDEV; i++)
1032
sprintf (devfile, "/dev/mixer%d", i);
1033
save_link (f, devfile);
1036
#ifdef CONFIG_OSS_MIDI
1041
for (i = 0; i < MAXDEV; i++)
1043
sprintf (devfile, "/dev/midi%02d", i);
1044
save_link (f, devfile);
1052
main (int argc, char *argv[])
1056
if ((mixerfd = open ("/dev/mixer", O_RDWR, 0)) == -1)
1058
perror ("/dev/mixer");
1062
if (ioctl (mixerfd, SNDCTL_SYSINFO, &si) == -1)
1067
"OSS has not detected any supported sound hardware ");
1068
fprintf (stderr, "in your system.\n");
1073
perror ("SNDCTL_SYSINFO");
1074
if (errno == EINVAL)
1075
fprintf (stderr, "Error: OSS version 4.0 or later is required\n");
1080
while ((c = getopt (argc, argv, "Nf:rv")) != EOF)
1084
legacydev_file = optarg;
1102
create_mixerlinks ();
1103
#ifdef CONFIG_OSS_MIDI
1104
create_midilinks ();