2
* Purpose: OSS device autodetection utility for Linux
7
* This file is part of Open Sound System.
9
* Copyright (C) 4Front Technologies 1996-2008.
11
* This this source file is released under GPL v2 license (no other versions).
12
* See the COPYING file included in the main directory of this source
13
* distribution for the license terms and conditions.
23
#include <sys/types.h>
32
#define OSSLIBDIRLEN 512
33
static char *osslibdir = NULL;
35
static int usb_ok = 0;
37
static int verbose = 0;
41
char *key, *driver, *name;
47
typedef struct drv_slist
49
const char * drv_name;
50
struct drv_slist * next;
52
static drvlist_t * drvl = NULL;
54
#define MAX_DRIVERS 1000
55
static driver_def_t drivers[MAX_DRIVERS];
56
static int ndrivers = 0;
58
static int add_drv (const char *, int);
59
static int decode_descriptor (unsigned char *, int);
60
static void create_devlinks (mode_t);
61
static char * get_mapname (void);
62
static unsigned short get_uint16 (unsigned char *);
63
static int is_audio (unsigned char *, int);
64
static void load_license (const char *);
65
static void load_devlist (const char *, int);
66
static void pci_checkdevice (char *);
67
static void pci_detect (char *);
68
static drvlist_t * prepend_drvlist (const char *);
69
static int remove_devlinks (const char *);
70
static void usb_checkdevice (char *);
71
static void usb_scandir (char *);
72
static void usb_detect (void);
78
static char name[OSSLIBDIRLEN], tmp[OSSLIBDIRLEN+11];
81
if ((f = fopen ("/etc/oss.conf", "r")) == NULL)
83
perror ("/etc/oss.conf");
87
while (fgets (tmp, sizeof (tmp), f) != NULL)
90
if (l > 0 && tmp[l - 1] == '\n')
93
if (strncmp (tmp, "OSSLIBDIR=", 10) == 0)
95
l = snprintf (name, sizeof (name), "%s", &tmp[10]);
96
if ((l >= OSSLIBDIRLEN) || (l < 0))
98
fprintf (stderr, "String in /etc/oss.conf is too long!\n");
101
if ((stat (name, &st) == -1) || !S_ISDIR(st.st_mode))
103
fprintf (stderr, "Directory %s from /etc/oss.conf cannot "
112
fprintf (stderr, "OSSLIBDIR not set in /etc/oss.conf, using default "
117
snprintf (name, sizeof (name), "/usr/lib/oss");
122
load_license (const char *fname)
125
char cmd[2*OSSLIBDIRLEN];
128
if (stat (fname, &st) == -1)
129
return; /* Doesn't exist */
131
if (stat ("/usr/sbin/osslic", &st) == -1)
132
return; /* No osslic utility in the system. No need to install license. */
134
n = snprintf (cmd, sizeof (cmd), "/usr/sbin/osslic -q %s/%s", osslibdir,
136
if (n >= sizeof (cmd) || n < 0) return;
137
if (((n = system (cmd)) == -1))
138
fprintf (stderr, "Cannot run osslic!\n");
142
load_devlist (const char *fname, int is_3rdparty)
145
char line[256], *p, rfname[2*OSSLIBDIRLEN];
146
char *driver, *key, *name;
148
snprintf (rfname, sizeof (rfname), "%s/%s", osslibdir, fname);
150
if ((f = fopen (rfname, "r")) == NULL)
156
while (fgets (line, sizeof (line), f) != NULL)
161
if (*p == '#' || *p == '\n')
166
/* Drivers with upper case names are unsupported ones */
167
if ((*line >= 'A' && *line <= 'Z') || (*line == '\0'))
173
while (*p && *p != '\t' && *p != ' ')
179
while (*p && *p != '\t')
186
printf ("device=%s, name=%s, driver=%s\n", key, name, driver);
188
if (ndrivers >= MAX_DRIVERS)
190
printf ("Too many drivers defined in drivers.list\n");
194
drivers[ndrivers].key = strdup (key);
195
drivers[ndrivers].driver = strdup (driver);
196
drivers[ndrivers].name = strdup (name);
197
drivers[ndrivers].is_3rdparty = is_3rdparty;
198
drivers[ndrivers].detected = 0;
207
add_drv (const char * id, int pass)
211
for (i = 0; i < ndrivers; i++)
213
if (strcmp (id, drivers[i].key) == 0)
216
printf ("Detected %s\n", drivers[i].name);
217
drivers[i].detected = 1;
218
drivers[i].pass = pass;
226
static unsigned short
227
get_uint16 (unsigned char *p)
229
return *p + (p[1] << 8);
233
decode_descriptor (unsigned char *d, int desclen)
238
if (d[5] == 1) // Audio
247
is_audio (unsigned char *desc, int datalen)
251
if (desc[0] == 9 && desc[1] == 2) /* Config descriptor */
253
l = get_uint16 (desc + 2);
261
while (pos < datalen)
266
if (desclen < 2 || desclen > (datalen - pos))
272
if (decode_descriptor (d, desclen))
281
usb_checkdevice (char *fname)
284
unsigned char buf[4096];
288
if ((fd = open (fname, O_RDONLY, 0)) == -1)
294
if ((l = read (fd, buf, sizeof (buf))) == -1)
302
if (l < 12 || buf[1] != 1)
305
vendor = buf[8] | (buf[9] << 8);
306
device = buf[10] | (buf[11] << 8);
308
sprintf (tmp, "usb%x,%x", vendor, device);
309
if (add_drv (tmp, USB_PASS))
312
sprintf (tmp, "usbif%x,%x", vendor, device);
313
if (add_drv (tmp, USB_PASS))
316
if (is_audio (buf, l)) /* USB audio class */
318
if (add_drv ("usbif,class1", USB_PASS))
324
usb_scandir (char *dirname)
331
if ((dr = opendir (dirname)) == NULL)
336
while ((de = readdir (dr)) != NULL)
338
if (de->d_name[0] < '0' || de->d_name[0] > '9') /* Ignore non-numeric names */
341
snprintf (path, sizeof (path), "%s/%s", dirname, de->d_name);
343
if (stat (path, &st) == -1)
346
if (S_ISDIR (st.st_mode))
352
usb_checkdevice (path);
363
char path[OSSLIBDIRLEN + 25];
365
sprintf (path, "%s/modules/oss_usb.o", osslibdir);
367
if (stat (path, &st) == -1) /* USB module not available */
369
fprintf (stderr, "USB module not available, aborting USB detect\n");
374
if (stat ("/dev/bus/usb", &st) != -1)
377
usb_scandir ("/dev/bus/usb");
379
else if (stat ("/proc/bus/usb", &st) != -1)
382
usb_scandir ("/proc/bus/usb");
387
pci_checkdevice (char *path)
389
unsigned char buf[256];
393
int subvendor, subdevice;
395
if ((fd = open (path, O_RDONLY, 0)) == -1)
401
if (read (fd, buf, sizeof (buf)) != sizeof (buf))
408
vendor = buf[0] | (buf[1] << 8);
409
device = buf[2] | (buf[3] << 8);
410
subvendor = buf[0x2c] | (buf[0x2d] << 8);
411
subdevice = buf[0x2e] | (buf[0x2f] << 8);
412
sprintf (id, "pcs%x,%x", subvendor, subdevice);
413
if (add_drv (id, PCI_PASS))
415
sprintf (id, "pci%x,%x", vendor, device);
416
add_drv (id, PCI_PASS);
420
pci_detect (char *dirname)
429
dirname = "/proc/bus/pci";
432
if ((dr = opendir (dirname)) == NULL)
437
while ((de = readdir (dr)) != NULL)
439
if (de->d_name[0] < '0' || de->d_name[0] > '9') /* Ignore non-numeric names */
442
snprintf (path, sizeof (path), "%s/%s", dirname, de->d_name);
444
if (stat (path, &st) == -1)
447
if (S_ISDIR (st.st_mode))
453
pci_checkdevice (path);
460
remove_devlinks (const char * dirname)
467
if ((dr = opendir (dirname)) == NULL)
469
if (errno == ENONET) return 0;
474
while ((de = readdir (dr)) != NULL)
476
if ((!strcmp (de->d_name, ".")) || (!strcmp (de->d_name, ".."))) continue;
478
snprintf (path, sizeof (path), "%s/%s", dirname, de->d_name);
480
if ((stat (path, &st) != -1) && (S_ISDIR (st.st_mode))) remove_devlinks (path);
483
if (verbose > 2) fprintf (stderr, "Removing %s\n", path);
489
if (verbose > 2) fprintf (stderr, "Removing %s\n", path);
490
if (rmdir (dirname) == -1)
492
fprintf (stderr, "Couldn't remove %s\n", path);
499
create_devlinks (mode_t node_m)
502
char line[256], tmp[300], *p, *s;
506
if ((f = fopen ("/proc/opensound/devfiles", "r")) == NULL)
508
perror ("/proc/opensound/devfiles");
509
fprintf (stderr, "Cannot connect to the OSS kernel module.\n");
510
fprintf (stderr, "Perhaps you need to execute 'soundon' to load OSS\n");
514
remove_devlinks ("/dev/oss");
516
mkdir ("/dev/oss", 0755);
518
while (fgets (line, sizeof (line), f) != NULL)
520
char dev[64] = "/dev/";
522
s = strchr (line, '\n');
525
if (sscanf (line, "%s %d %d", dev + 5, &major, &minor) != 3)
527
fprintf (stderr, "Syntax error in /proc/opensound/devfiles\n");
528
fprintf (stderr, "%s\n", line);
533
* Check if the device is located in a subdirectory (say /dev/oss/sblive0/pcm0).
548
*p = 0; /* Extract the directory name part */
554
printf ("mknod %s c %d %d -m %o\n", dev, major, minor, node_m);
555
if (mknod (dev, node_m, makedev (major, minor)) == -1)
564
prepend_drvlist (const char * name)
568
dp = malloc (sizeof (drvlist_t));
571
fprintf (stderr, "Can't allocate memory!\n");
581
main (int argc, char *argv[])
583
char instfname[2*OSSLIBDIRLEN], *p;
584
int i, do_license = 0, make_devs = 0, pass;
585
mode_t node_m = S_IFCHR | 0666;
589
while ((i = getopt(argc, argv, "L:a:dilm:uv")) != EOF)
601
drvl = prepend_drvlist ("oss_imux");
605
drvl = prepend_drvlist ("oss_userdev");
609
drvl = prepend_drvlist (optarg);
623
while ((*p >= '0') && (*p <= '7')) node_m = node_m * 8 + *p++ - '0';
624
if ((*p) || (node_m & ~(S_IRWXU|S_IRWXG|S_IRWXO)))
626
fprintf (stderr, "Invalid permissions: %s\n", optarg);
633
fprintf (stderr, "%s: bad usage\n", argv[0]);
637
if (osslibdir == NULL) osslibdir = get_mapname ();
641
create_devlinks (node_m);
647
load_license ("etc/license.asc");
651
load_devlist ("etc/devices.list", 0);
653
if (stat ("/etc/oss_3rdparty", &st) != -1)
654
load_devlist ("/etc/oss_3rdparty", 1);
662
printf ("USB support available in the system, adding USB driver\n");
663
add_drv ("usbif,class1", USB_PASS);
666
printf ("No USB support detected in the system - skipping USB\n");
670
drvlist_t * d = drvl;
671
add_drv (drvl->drv_name, PSEUDO_PASS);
676
snprintf (instfname, sizeof (instfname), "%s/%s", osslibdir,
677
"etc/installed_drivers");
679
if ((f = fopen (instfname, "w")) == NULL)
685
for (pass = 0; pass < MAX_PASS; pass++)
686
for (i = 0; i < ndrivers; i++)
687
if (drivers[i].pass == pass && drivers[i].detected)
689
fprintf (f, "%s #%s\n", drivers[i].driver, drivers[i].name);