/* * sound/dev_table.c * * Device call tables. */ /* * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ #include #define _DEV_TABLE_C_ #include "sound_config.h" int sb_be_quiet = 0; int sound_started = 0; int sndtable_get_cardcount (void); int snd_find_driver (int type) { int i, n = num_sound_drivers; for (i = 0; i < n; i++) if (sound_drivers[i].card_type == type) return i; return -1; } static void start_services (void) { int soundcards_installed; if (!(soundcards_installed = sndtable_get_cardcount ())) return; /* No cards detected */ #ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { int dev; for (dev = 0; dev < num_audiodevs; dev++) { } audio_init_devices (); } #endif return; } static void start_cards (void) { int i, n = num_sound_cards; int drv; sound_started = 1; if (trace_init) printk ("Sound initialization started\n"); #ifdef CONFIG_LOWLEVEL_SOUND { extern void sound_preinit_lowlevel_drivers (void); sound_preinit_lowlevel_drivers (); } #endif /* * Check the number of cards actually defined in the table */ for (i = 0; i < n && snd_installed_cards[i].card_type; i++) num_sound_cards = i + 1; for (i = 0; i < n && snd_installed_cards[i].card_type; i++) if (snd_installed_cards[i].enabled) { snd_installed_cards[i].for_driver_use = NULL; if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) { snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ continue; } snd_installed_cards[i].config.card_subtype = sound_drivers[drv].card_subtype; if (sound_drivers[drv].probe (&snd_installed_cards[i].config)) { sound_drivers[drv].attach (&snd_installed_cards[i].config); } else snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ } #ifdef CONFIG_LOWLEVEL_SOUND { extern void sound_init_lowlevel_drivers (void); sound_init_lowlevel_drivers (); } #endif if (trace_init) printk ("Sound initialization complete\n"); } void sndtable_init (void) { start_cards (); } void sound_unload_drivers (void) { int i, n = num_sound_cards; int drv; if (!sound_started) return; if (trace_init) printk ("Sound unload started\n"); for (i = 0; i < n && snd_installed_cards[i].card_type; i++) if (snd_installed_cards[i].enabled) { if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1) { if (sound_drivers[drv].unload) { sound_drivers[drv].unload (&snd_installed_cards[i].config); snd_installed_cards[i].enabled = 0; } } } if (trace_init) printk ("Sound unload complete\n"); } void sound_unload_driver (int type) { int i, drv = -1, n = num_sound_cards; unsigned long flags; DEB (printk ("unload driver %d: ", type)); for (i = 0; i < n && snd_installed_cards[i].card_type; i++) if (snd_installed_cards[i].card_type == type) { if (snd_installed_cards[i].enabled) { if ((drv = snd_find_driver (type)) != -1) { DEB (printk (" card %d", i)); if (sound_drivers[drv].unload) { sound_drivers[drv].unload (&snd_installed_cards[i].config); snd_installed_cards[i].enabled = 0; } } } } DEB (printk ("\n")); save_flags (flags); cli (); restore_flags (flags); } int sndtable_probe (int unit, struct address_info *hw_config) { int sel = -1; DEB (printk ("sndtable_probe(%d)\n", unit)); if (!unit) return 1; if (sel == -1 && num_sound_cards < max_sound_cards) { int i; i = sel = (num_sound_cards++); snd_installed_cards[sel].card_type = unit; snd_installed_cards[sel].enabled = 1; } if (sel != -1) { int drv; snd_installed_cards[sel].for_driver_use = NULL; snd_installed_cards[sel].config.io_base = hw_config->io_base; snd_installed_cards[sel].config.irq = hw_config->irq; snd_installed_cards[sel].config.dma = hw_config->dma; snd_installed_cards[sel].config.dma2 = hw_config->dma2; snd_installed_cards[sel].config.name = hw_config->name; snd_installed_cards[sel].config.always_detect = hw_config->always_detect; snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1) { snd_installed_cards[sel].enabled = 0; DEB (printk ("Failed to find driver\n")); return 0; } DEB (printk ("Driver name '%s'\n", sound_drivers[drv].name)); hw_config->card_subtype = snd_installed_cards[sel].config.card_subtype = sound_drivers[drv].card_subtype; if (sound_drivers[drv].probe (hw_config)) { DEB (printk ("Hardware probed OK\n")); return 1; } DEB (printk ("Failed to find hardware\n")); snd_installed_cards[sel].enabled = 0; /* * Mark as not detected */ return 0; } return 0; } int sndtable_init_card (int unit, struct address_info *hw_config) { int i, n = num_sound_cards; DEB (printk ("sndtable_init_card(%d) entered\n", unit)); if (!unit) { sndtable_init (); return 1; } for (i = 0; i < n && snd_installed_cards[i].card_type; i++) if (snd_installed_cards[i].card_type == unit) { int drv; snd_installed_cards[i].config.io_base = hw_config->io_base; snd_installed_cards[i].config.irq = hw_config->irq; snd_installed_cards[i].config.dma = hw_config->dma; snd_installed_cards[i].config.dma2 = hw_config->dma2; snd_installed_cards[i].config.name = hw_config->name; snd_installed_cards[i].config.always_detect = hw_config->always_detect; snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1; snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2; snd_installed_cards[i].config.card_subtype = hw_config->card_subtype; if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ else { DEB (printk ("Located card - calling attach routine\n")); sound_drivers[drv].attach (hw_config); DEB (printk ("attach routine finished\n")); } start_services (); return 1; } DEB (printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n", unit, num_sound_cards)); return 0; } int sndtable_get_cardcount (void) { return num_audiodevs + num_mixers + num_synths + num_midis; } int sndtable_identify_card (char *name) { int i, n = num_sound_drivers; if (name == NULL) return 0; for (i = 0; i < n; i++) if (sound_drivers[i].driver_id != NULL) { char *id = sound_drivers[i].driver_id; int j; for (j = 0; j < 80 && name[j] == id[j]; j++) if (id[j] == 0 && name[j] == 0) /* Match */ return sound_drivers[i].card_type; } return 0; } void sound_setup (char *str, int *ints) { int i, n = num_sound_cards; /* * First disable all drivers */ for (i = 0; i < n && snd_installed_cards[i].card_type; i++) snd_installed_cards[i].enabled = 0; if (ints[0] == 0 || ints[1] == 0) return; /* * Then enable them one by time */ for (i = 1; i <= ints[0]; i++) { int card_type, ioaddr, irq, dma, dma2, ptr, j; unsigned int val; val = (unsigned int) ints[i]; card_type = (val & 0x0ff00000) >> 20; if (card_type > 127) { /* * Add any future extensions here */ return; } ioaddr = (val & 0x000fff00) >> 8; irq = (val & 0x000000f0) >> 4; dma = (val & 0x0000000f); dma2 = (val & 0xf0000000) >> 28; ptr = -1; for (j = 0; j < n && ptr == -1; j++) if (snd_installed_cards[j].card_type == card_type && !snd_installed_cards[j].enabled) /* * Not already found */ ptr = j; if (ptr == -1) printk ("Sound: Invalid setup parameter 0x%08x\n", val); else { snd_installed_cards[ptr].enabled = 1; snd_installed_cards[ptr].config.io_base = ioaddr; snd_installed_cards[ptr].config.irq = irq; snd_installed_cards[ptr].config.dma = dma; snd_installed_cards[ptr].config.dma2 = dma2; snd_installed_cards[ptr].config.name = NULL; snd_installed_cards[ptr].config.always_detect = 0; snd_installed_cards[ptr].config.driver_use_1 = 0; snd_installed_cards[ptr].config.driver_use_2 = 0; snd_installed_cards[ptr].config.card_subtype = 0; } } } struct address_info * sound_getconf (int card_type) { int j, ptr; int n = num_sound_cards; ptr = -1; for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++) if (snd_installed_cards[j].card_type == card_type) ptr = j; if (ptr == -1) return (struct address_info *) NULL; return &snd_installed_cards[ptr].config; } int sound_install_audiodrv (int vers, char *name, struct audio_driver *driver, int driver_size, int flags, unsigned int format_mask, void *devc, int dma1, int dma2) { #ifdef CONFIG_AUDIO struct audio_driver *d; struct audio_operations *op; int l, num; if (num_audiodevs >= MAX_AUDIO_DEV) { printk ("Sound: Too many audio drivers\n"); return -EIO; } if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof (struct audio_driver)) { printk ("Sound: Incompatible audio driver for %s\n", name); return -EIO; } d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_driver))); sound_mem_sizes[sound_nblocks] = sizeof (struct audio_driver); if (sound_nblocks < 1024) sound_nblocks++;; op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_operations))); sound_mem_sizes[sound_nblocks] = sizeof (struct audio_operations); if (sound_nblocks < 1024) sound_nblocks++;; if (d == NULL || op == NULL) { printk ("Sound: Can't allocate driver for (%s)\n", name); return -ENOSPC; } memset ((char *) op, 0, sizeof (struct audio_operations)); if (driver_size < sizeof (struct audio_driver)) memset ((char *) d, 0, sizeof (struct audio_driver)); memcpy ((char *) d, (char *) driver, driver_size); op->d = d; l = strlen (name) + 1; if (l > sizeof (op->name)) l = sizeof (op->name); strncpy (op->name, name, l); op->name[l - 1] = 0; op->flags = flags; op->format_mask = format_mask; op->devc = devc; /* * Hardcoded defaults */ audio_devs[num_audiodevs] = op; num = num_audiodevs++; DMAbuf_init (num, dma1, dma2); audio_init_devices (); return num; #else return -EINVAL; #endif } int sound_install_mixer (int vers, char *name, struct mixer_operations *driver, int driver_size, void *devc) { struct mixer_operations *op; int l; if (num_mixers >= MAX_MIXER_DEV) { printk ("Sound: Too many mixer drivers\n"); return -EIO; } if (vers != MIXER_DRIVER_VERSION || driver_size > sizeof (struct mixer_operations)) { printk ("Sound: Incompatible mixer driver for %s\n", name); return -EIO; } op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); sound_mem_sizes[sound_nblocks] = sizeof (struct mixer_operations); if (sound_nblocks < 1024) sound_nblocks++;; if (op == NULL) { printk ("Sound: Can't allocate mixer driver for (%s)\n", name); return -ENOSPC; } memset ((char *) op, 0, sizeof (struct mixer_operations)); memcpy ((char *) op, (char *) driver, driver_size); l = strlen (name) + 1; if (l > sizeof (op->name)) l = sizeof (op->name); strncpy (op->name, name, l); op->name[l - 1] = 0; op->devc = devc; mixer_devs[num_mixers] = op; return num_mixers++; }