diff options
Diffstat (limited to 'drivers/sound')
-rw-r--r-- | drivers/sound/ac97_codec.c | 155 | ||||
-rw-r--r-- | drivers/sound/ac97_codec.h | 9 | ||||
-rw-r--r-- | drivers/sound/dmasound.c | 109 | ||||
-rw-r--r-- | drivers/sound/es1370.c | 14 | ||||
-rw-r--r-- | drivers/sound/es1371.c | 14 | ||||
-rw-r--r-- | drivers/sound/esssolo1.c | 35 | ||||
-rw-r--r-- | drivers/sound/sb_card.c | 417 | ||||
-rw-r--r-- | drivers/sound/sonicvibes.c | 14 | ||||
-rw-r--r-- | drivers/sound/sound_core.c | 97 | ||||
-rw-r--r-- | drivers/sound/soundcard.c | 68 |
10 files changed, 689 insertions, 243 deletions
diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c index a1177c6df..56ee3df89 100644 --- a/drivers/sound/ac97_codec.c +++ b/drivers/sound/ac97_codec.c @@ -19,9 +19,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * History - * Jan 14 2000 Ollie Lho <ollie@sis.com.tw> - * Isloated from trident.c to support multiple ac97 codec + * History + * v0.2 Feb 10 2000 Ollie Lho + * add ac97_read_proc for /proc/driver/vnedor/ac97 + * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> + * Isolated from trident.c to support multiple ac97 codec */ #include <linux/module.h> #include <linux/version.h> @@ -36,11 +38,13 @@ static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, uns static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask); static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg); +#define arraysize(x) (sizeof(x)/sizeof((x)[0])) + static struct { unsigned int id; char *name; int (*init) (struct ac97_codec *codec); -} snd_ac97_codec_ids[] = { +} ac97_codec_ids[] = { {0x414B4D00, "Asahi Kasei AK4540" , NULL}, {0x41445340, "Analog Devices AD1881" , NULL}, {0x43525900, "Cirrus Logic CS4297" , NULL}, @@ -52,9 +56,46 @@ static struct { {0x83847605, "SigmaTel STAC9704" , NULL}, {0x83847608, "SigmaTel STAC9708" , NULL}, {0x83847609, "SigmaTel STAC9721/23" , NULL}, + {0x54524108, "TriTech TR28028" , NULL}, + {0x574D4C00, "Wolfson WM9704" , NULL}, {0x00000000, NULL, NULL} }; +static const char *ac97_stereo_enhancements[] = +{ + /* 0 */ "No 3D Stereo Enhancement", + /* 1 */ "Analog Devices Phat Stereo", + /* 2 */ "Creative Stereo Enhancement", + /* 3 */ "National Semi 3D Stereo Enhancement", + /* 4 */ "YAMAHA Ymersion", + /* 5 */ "BBE 3D Stereo Enhancement", + /* 6 */ "Crystal Semi 3D Stereo Enhancement", + /* 7 */ "Qsound QXpander", + /* 8 */ "Spatializer 3D Stereo Enhancement", + /* 9 */ "SRS 3D Stereo Enhancement", + /* 10 */ "Platform Tech 3D Stereo Enhancement", + /* 11 */ "AKM 3D Audio", + /* 12 */ "Aureal Stereo Enhancement", + /* 13 */ "Aztech 3D Enhancement", + /* 14 */ "Binaura 3D Audio Enhancement", + /* 15 */ "ESS Technology Stereo Enhancement", + /* 16 */ "Harman International VMAx", + /* 17 */ "Nvidea 3D Stereo Enhancement", + /* 18 */ "Philips Incredible Sound", + /* 19 */ "Texas Instruments 3D Stereo Enhancement", + /* 20 */ "VLSI Technology 3D Stereo Enhancement", + /* 21 */ "TriTech 3D Stereo Enhancement", + /* 22 */ "Realtek 3D Stereo Enhancement", + /* 23 */ "Samsung 3D Stereo Enhancement", + /* 24 */ "Wolfson Microelectronics 3D Enhancement", + /* 25 */ "Delta Integration 3D Enhancement", + /* 26 */ "SigmaTel 3D Enhancement", + /* 27 */ "Reserved 27", + /* 28 */ "Rockwell 3D Stereo Enhancement", + /* 29 */ "Reserved 29", + /* 30 */ "Reserved 30", + /* 31 */ "Reserved 31" +}; /* this table has default mixer values for all OSS mixers. */ static struct mixer_defaults { @@ -86,9 +127,9 @@ static struct ac97_mixer_hw { } ac97_hw[SOUND_MIXER_NRDEVICES]= { [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63}, [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15}, - [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15}, + [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15}, [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31}, - [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15}, + [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15}, [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31}, [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31}, [SOUND_MIXER_CD] = {AC97_CD_VOL, 31}, @@ -155,10 +196,13 @@ static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) right = 100 - ((right * 100) / mh->scale); left = 100 - ((left * 100) / mh->scale); } - ret = left | (right << 8); } else if (oss_channel == SOUND_MIXER_SPEAKER) { ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_PHONEIN) { + ret = 100 - (((val & 0x1f) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_PHONEOUT) { + ret = 100 - (((val & 0x1f) * 100) / mh->scale); } else if (oss_channel == SOUND_MIXER_MIC) { ret = 100 - (((val & 0x1f) * 100) / mh->scale); /* the low bit is optional in the tone sliders and masking @@ -200,10 +244,14 @@ static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, } else { right = ((100 - right) * mh->scale) / 100; left = ((100 - left) * mh->scale) / 100; - } + } val = (left << 8) | right; } else if (oss_channel == SOUND_MIXER_SPEAKER) { val = (((100 - left) * mh->scale) / 100) << 1; + } else if (oss_channel == SOUND_MIXER_PHONEIN) { + val = (((100 - left) * mh->scale) / 100); + } else if (oss_channel == SOUND_MIXER_PHONEOUT) { + val = (((100 - left) * mh->scale) / 100); } else if (oss_channel == SOUND_MIXER_MIC) { val = codec->codec_read(codec , mh->offset) & ~0x801f; val |= (((100 - left) * mh->scale) / 100); @@ -212,11 +260,10 @@ static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, } else if (oss_channel == SOUND_MIXER_BASS) { val = codec->codec_read(codec , mh->offset) & ~0x0f00; val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; - } else if (oss_channel == SOUND_MIXER_TREBLE) { + } else if (oss_channel == SOUND_MIXER_TREBLE) { val = codec->codec_read(codec , mh->offset) & ~0x000f; val |= (((100 - left) * mh->scale) / 100) & 0x000e; } - #ifdef DEBUG printk(" 0x%04x", val); #endif @@ -335,11 +382,11 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned return -EINVAL; /* do we ever want to touch the hardware? */ - /* val = codec->read_mixer(card,i); */ - val = codec->mixer_state[i]; + val = codec->read_mixer(codec, i); + /* val = codec->mixer_state[i]; */ break; } - return put_user(val,(int *)arg); + return put_user(val, (int *)arg); } if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) { @@ -368,6 +415,76 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned return -EINVAL; } +/* entry point for /proc/driver/controller_vendor/ac97/%d */ +int ac97_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0, cap, extid, val, id1, id2; + struct ac97_codec *codec; + + if ((codec = data) == NULL) + return -ENODEV; + + id1 = codec->codec_read(codec, AC97_VENDOR_ID1); + id2 = codec->codec_read(codec, AC97_VENDOR_ID2); + len += sprintf (page+len, "Vendor name : %s\n", codec->name); + len += sprintf (page+len, "Vendor id : %04X %04X\n", id1, id2); + + extid = codec->codec_read(codec, AC97_EXTENDED_ID); + extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13)); + len += sprintf (page+len, "AC97 Version : %s\n", + extid ? "2.0 or later" : "1.0"); + + cap = codec->codec_read(codec, AC97_RESET); + len += sprintf (page+len, "Capabilities :%s%s%s%s%s%s\n", + cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "", + cap & 0x0002 ? " -reserved1-" : "", + cap & 0x0004 ? " -bass & treble-" : "", + cap & 0x0008 ? " -simulated stereo-" : "", + cap & 0x0010 ? " -headphone out-" : "", + cap & 0x0020 ? " -loudness-" : ""); + val = cap & 0x00c0; + len += sprintf (page+len, "DAC resolutions :%s%s%s\n", + " -16-bit-", + val & 0x0040 ? " -18-bit-" : "", + val & 0x0080 ? " -20-bit-" : ""); + val = cap & 0x0300; + len += sprintf (page+len, "ADC resolutions :%s%s%s\n", + " -16-bit-", + val & 0x0100 ? " -18-bit-" : "", + val & 0x0200 ? " -20-bit-" : ""); + len += sprintf (page+len, "3D enhancement : %s\n", + ac97_stereo_enhancements[(cap >> 10) & 0x1f]); + + val = codec->codec_read(codec, AC97_GENERAL_PURPOSE); + len += sprintf (page+len, "POP path : %s 3D\n" + "Sim. stereo : %s\n" + "3D enhancement : %s\n" + "Loudness : %s\n" + "Mono output : %s\n" + "MIC select : %s\n" + "ADC/DAC loopback : %s\n", + val & 0x8000 ? "post" : "pre", + val & 0x4000 ? "on" : "off", + val & 0x2000 ? "on" : "off", + val & 0x1000 ? "on" : "off", + val & 0x0200 ? "MIC" : "MIX", + val & 0x0100 ? "MIC2" : "MIC1", + val & 0x0080 ? "on" : "off"); + + cap = extid; + len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n", + cap & 0x0001 ? " -var rate PCM audio-" : "", + cap & 0x0002 ? " -2x PCM audio out-" : "", + cap & 0x0008 ? " -var rate MIC in-" : "", + cap & 0x0040 ? " -PCM center DAC-" : "", + cap & 0x0080 ? " -PCM surround DAC-" : "", + cap & 0x0100 ? " -PCM LFE DAC-" : "", + cap & 0x0200 ? " -slot/DAC mappings-" : ""); + + return len; +} + int ac97_probe_codec(struct ac97_codec *codec) { u16 id1, id2, cap; @@ -379,12 +496,14 @@ int ac97_probe_codec(struct ac97_codec *codec) if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000) return 0; + codec->name = NULL; + codec->codec_init = NULL; id1 = codec->codec_read(codec, AC97_VENDOR_ID1); id2 = codec->codec_read(codec, AC97_VENDOR_ID2); - for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) { - if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) { - codec->name = snd_ac97_codec_ids[i].name; - codec->codec_init = snd_ac97_codec_ids[i].init; + for (i = 0; i < arraysize(ac97_codec_ids); i++) { + if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { + codec->name = ac97_codec_ids[i].name; + codec->codec_init = ac97_codec_ids[i].init; break; } } @@ -392,7 +511,6 @@ int ac97_probe_codec(struct ac97_codec *codec) codec->name = "Unknown"; printk(KERN_INFO "ac97_codec: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n", id1, id2, codec->name); - printk(KERN_INFO "ac97_codec: capability: 0x%04x\n", cap); /* mixer masks */ codec->supported_mixers = AC97_SUPPORTED_MASK; @@ -437,4 +555,5 @@ static int sigmatel_init(struct ac97_codec * codec) return 1; } +EXPORT_SYMBOL(ac97_read_proc); EXPORT_SYMBOL(ac97_probe_codec); diff --git a/drivers/sound/ac97_codec.h b/drivers/sound/ac97_codec.h index 27d41f5bb..a614edbdb 100644 --- a/drivers/sound/ac97_codec.h +++ b/drivers/sound/ac97_codec.h @@ -107,16 +107,17 @@ /* OSS interface to the ac97s.. */ #define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\ SOUND_MASK_LINE|SOUND_MASK_CD|\ - SOUND_MIXER_ALTPCM|SOUND_MASK_IGAIN|\ + SOUND_MASK_ALTPCM|SOUND_MASK_IGAIN|\ SOUND_MASK_LINE1|SOUND_MASK_VIDEO) #define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ SOUND_MASK_BASS|SOUND_MASK_TREBLE|\ SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\ - SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT) + SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT) #define AC97_RECORD_MASK (SOUND_MASK_MIC|\ - SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\ + SOUND_MASK_CD|SOUND_MASK_VIDEO|\ + SOUND_MASK_LINE1| SOUND_MASK_LINE|\ SOUND_MASK_PHONEIN) #define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) ) @@ -153,6 +154,8 @@ struct ac97_codec { unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; }; +extern int ac97_read_proc (char *page_out, char **start, off_t off, + int count, int *eof, void *data); extern int ac97_probe_codec(struct ac97_codec *); #endif /* _AC97_CODEC_H_ */ diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index ae627ed3b..b6298ca83 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -116,6 +116,7 @@ History: #include <asm/machdep.h> #include <asm/io.h> #include <asm/dbdma.h> +#include <asm/feature.h> #include "awacs_defs.h" #include <linux/nvram.h> #include <linux/vt_kern.h> @@ -178,6 +179,7 @@ static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; static int awacs_rate_index; static int awacs_subframe; static int awacs_spkr_vol; +static struct device_node* awacs_node; static int awacs_revision; #define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ @@ -251,6 +253,7 @@ static short *beep_buf; static volatile struct dbdma_cmd *beep_dbdma_cmd; static void (*orig_mksound)(unsigned int, unsigned int); static int is_pbook_3400; +static unsigned char *latch_base; static int is_pbook_G3; static unsigned char *macio_base; @@ -898,7 +901,7 @@ static inline int ioctl_return(int *addr, int value) void dmasound_init(void); -void dmasound_setup(char *str, int *ints); +static int dmasound_setup(char *str); /*** Translations ************************************************************/ @@ -3208,9 +3211,15 @@ static void PMacIrqCleanup(void) out_le32(&awacs_txdma->control, RUN<<16); /* disable interrupts from awacs interface */ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); - free_irq(awacs_irq, pmac_awacs_intr); - free_irq(awacs_tx_irq, pmac_awacs_tx_intr); - free_irq(awacs_rx_irq, pmac_awacs_rx_intr); +#ifdef CONFIG_PMAC_PBOOK + if (is_pbook_G3) { + feature_clear(awacs_node, FEATURE_Sound_power); + feature_clear(awacs_node, FEATURE_Sound_CLK_enable); + } +#endif + free_irq(awacs_irq, 0); + free_irq(awacs_tx_irq, 0); + free_irq(awacs_rx_irq, 0); kfree(awacs_tx_cmd_space); if (awacs_rx_cmd_space) kfree(awacs_rx_cmd_space); @@ -3281,12 +3290,10 @@ static void PMacInit(void) /* We really want to execute a DMA stop command, after the AWACS * is initialized. * For reasons I don't understand, it stops the hissing noise - * common to many PowerBook G3 systems (like mine :-). Maybe it - * is just the AWACS control register change...... + * common to many PowerBook G3 systems (like mine :-). */ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); - out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00)); out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); @@ -3544,6 +3551,11 @@ static void awacs_nosound(unsigned long xx) save_flags(flags); cli(); if (beep_playing) { st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); + out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + out_le32(&awacs->control, + (in_le32(&awacs->control) & ~0x1f00) + | (awacs_rate_index << 8)); + out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE); beep_playing = 0; } restore_flags(flags); @@ -3645,8 +3657,23 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) PMacSilence(); disable_irq(awacs_irq); disable_irq(awacs_tx_irq); + if (is_pbook_G3) { + feature_clear(awacs_node, FEATURE_Sound_CLK_enable); + feature_clear(awacs_node, FEATURE_Sound_power); + } break; case PBOOK_WAKE: + /* There is still a problem on wake. Sound seems to work fine + if I launch mpg123 and resumes fine if mpg123 was playing, + but the console beep is dead until I do something with the + mixer. Probably yet another timing issue */ + if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable) + || !feature_test(awacs_node, FEATURE_Sound_power)) { + /* these aren't present on the 3400 AFAIK -- paulus */ + feature_set(awacs_node, FEATURE_Sound_CLK_enable); + feature_set(awacs_node, FEATURE_Sound_power); + mdelay(1000); + } out_le32(&awacs->control, MASK_IEPC | (awacs_rate_index << 8) | 0x11 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); @@ -3663,6 +3690,16 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) mdelay(2); awacs_write(awacs_reg[1] | MASK_ADDR1); } + /* enable CD sound input */ + if (macio_base && is_pbook_G3) { + out_8(macio_base + 0x37, 3); + } else if (is_pbook_3400) { + feature_set(awacs_node, FEATURE_IOBUS_enable); + udelay(10); + in_8(latch_base + 0x190); + } + /* Resume pending sounds. */ + PMacPlay(); } return PBOOK_SLEEP_OK; } @@ -5139,6 +5176,7 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long fmt; int data; int size, nbufs; + audio_buf_info info; switch (cmd) { case SNDCTL_DSP_RESET: @@ -5214,6 +5252,14 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, sq_setup(numBufs, size, sound_buffers); sq.max_active = nbufs; return 0; + case SNDCTL_DSP_GETOSPACE: + info.fragments = sq.max_active - sq.count; + info.fragstotal = sq.max_active; + info.fragsize = sq.block_size; + info.bytes = info.fragments * info.fragsize; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; default: return mixer_ioctl(inode, file, cmd, arg); @@ -5308,7 +5354,7 @@ static int state_open(struct inode *inode, struct file *file) { char *buffer = state.buf, *mach = ""; #ifdef CONFIG_PPC - char awacs_buf[50]; + char awacs_buf[64]; #endif int len = 0; @@ -5576,6 +5622,16 @@ void __init dmasound_init(void) printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); return; } + awacs_node = np; +#ifdef CONFIG_PMAC_PBOOK + if (machine_is_compatible("PowerBook1,1") + || machine_is_compatible("AAPL,PowerBook1998")) { + feature_set(np, FEATURE_Sound_CLK_enable); + feature_set(np, FEATURE_Sound_power); + /* Shorter delay will not work */ + mdelay(1000); + } +#endif awacs_tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(awacs_tx_cmd_space); @@ -5607,7 +5663,10 @@ void __init dmasound_init(void) awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf; if (awacs_revision == 3) { + mdelay(100); awacs_write(0x6000); + mdelay(2); + awacs_write(awacs_reg[1] + MASK_ADDR1); awacs_enable_amp(100 * 0x101); } } @@ -5629,26 +5688,36 @@ void __init dmasound_init(void) /* Powerbooks have odd ways of enabling inputs such as an expansion-bay CD or sound from an internal modem or a PC-card modem. */ - if (machine_is_compatible("AAPL,3400/2400")) { + if (machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500")) { is_pbook_3400 = 1; /* * Enable CD and PC-card sound inputs. * This is done by reading from address * f301a000, + 0x10 to enable the expansion-bay * CD sound input, + 0x80 to enable the PC-card - * sound input. The 0x100 seems to enable the - * MESH and/or its SCSI bus drivers. + * sound input. The 0x100 enables the SCSI bus + * terminator power. */ - in_8((unsigned char *)0xf301a190); - } else if (machine_is_compatible("PowerBook1,1")) { - np = find_devices("mac-io"); - if (np && np->n_addrs > 0) { - is_pbook_G3 = 1; - macio_base = (unsigned char *) - ioremap(np->addrs[0].address, 0x40); - /* enable CD sound input */ - out_8(macio_base + 0x37, 3); + latch_base = (unsigned char *) ioremap + (0xf301a000, 0x1000); + in_8(latch_base + 0x190); + } else if (machine_is_compatible("PowerBook1,1") + || machine_is_compatible("AAPL,PowerBook1998")) { + struct device_node* mio; + macio_base = 0; + is_pbook_G3 = 1; + for (mio = np->parent; mio; mio = mio->parent) { + if (strcmp(mio->name, "mac-io") == 0 + && mio->n_addrs > 0) { + macio_base = (unsigned char *) ioremap + (mio->addrs[0].address, 0x40); + break; + } } + /* enable CD sound input */ + if (macio_base) + out_8(macio_base + 0x37, 3); } } #endif /* CONFIG_PPC */ diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index a6d6603ac..f7e5622d1 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -2456,7 +2456,7 @@ static struct initvol { ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct es1370_state *s; mm_segment_t fs; @@ -2466,6 +2466,10 @@ static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii return -1; if (pcidev->irq == 0) return -1; + if (!pci_dma_supported(pcidev, 0xffffffff)) { + printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n"); + return -1; + } if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) { printk(KERN_WARNING "es1370: out of memory\n"); return -1; @@ -2569,7 +2573,7 @@ static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii return -1; } -static void es1370_remove(struct pci_dev *dev) +static void __devinit es1370_remove(struct pci_dev *dev) { struct es1370_state *s = (struct es1370_state *)dev->driver_data; @@ -2589,7 +2593,7 @@ static void es1370_remove(struct pci_dev *dev) dev->driver_data = NULL; } -static const struct pci_device_id id_table[] = { +static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; @@ -2608,8 +2612,10 @@ static int __init init_es1370(void) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; printk(KERN_INFO "es1370: version v0.33 time " __TIME__ " " __DATE__ "\n"); - if (!pci_register_driver(&es1370_driver)) + if (!pci_register_driver(&es1370_driver)) { + pci_unregister_driver(&es1370_driver); return -ENODEV; + } return 0; } diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 21e2c7c2b..feeb11956 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -2611,7 +2611,7 @@ static struct initvol { ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct es1371_state *s; mm_segment_t fs; @@ -2624,6 +2624,10 @@ static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii return -1; if (pcidev->irq == 0) return -1; + if (!pci_dma_supported(pcidev, 0xffffffff)) { + printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); + return -1; + } if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { printk(KERN_WARNING "es1371: out of memory\n"); return -1; @@ -2764,7 +2768,7 @@ static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii return -1; } -static void es1371_remove(struct pci_dev *dev) +static void __devinit es1371_remove(struct pci_dev *dev) { struct es1371_state *s = (struct es1371_state *)dev->driver_data; @@ -2788,7 +2792,7 @@ static void es1371_remove(struct pci_dev *dev) dev->driver_data = NULL; } -static const struct pci_device_id id_table[] = { +static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, @@ -2809,8 +2813,10 @@ static int __init init_es1371(void) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; printk(KERN_INFO "es1371: version v0.25 time " __TIME__ " " __DATE__ "\n"); - if (!pci_register_driver(&es1371_driver)) + if (!pci_register_driver(&es1371_driver)) { + pci_unregister_driver(&es1371_driver); return -ENODEV; + } return 0; } diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c index 72fbd14a5..f61503b2f 100644 --- a/drivers/sound/esssolo1.c +++ b/drivers/sound/esssolo1.c @@ -67,7 +67,7 @@ * Tim Janik's BSE (Bedevilled Sound Engine) found this * Integrated (aka redid 8-)) APM support patch by Zach Brown * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver - * + * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled */ /*****************************************************************************/ @@ -412,7 +412,7 @@ extern inline void dealloc_dmabuf(struct solo1_state *s, struct dmabuf *db) db->mapped = db->ready = 0; } -static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, unsigned long dmamask) +static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db) { int order; unsigned bytespersec; @@ -422,7 +422,6 @@ static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, unsigned long d db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; if (!db->rawbuf) { db->ready = db->mapped = 0; - s->dev->dma_mask = dmamask; for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) break; @@ -469,7 +468,10 @@ extern inline int prog_dmabuf_adc(struct solo1_state *s) int c; stop_adc(s); - if ((c = prog_dmabuf(s, &s->dma_adc, 0xffffff))) + /* check if PCI implementation supports 24bit busmaster DMA */ + if (s->dev->dma_mask > 0xffffff) + return -EIO; + if ((c = prog_dmabuf(s, &s->dma_adc))) return c; va = s->dma_adc.dmaaddr; if ((va & ~((1<<24)-1))) @@ -494,7 +496,7 @@ extern inline int prog_dmabuf_dac(struct solo1_state *s) int c; stop_dac(s); - if ((c = prog_dmabuf(s, &s->dma_dac, 0xffffffff))) + if ((c = prog_dmabuf(s, &s->dma_dac))) return c; memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */ va = s->dma_dac.dmaaddr; @@ -2190,10 +2192,11 @@ static int solo1_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct solo1_state *s; struct pm_dev *pmdev; + dma_addr_t dma_mask; if (!RSRCISIOREGION(pcidev, 0) || !RSRCISIOREGION(pcidev, 1) || @@ -2202,6 +2205,14 @@ static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid return -1; if (pcidev->irq == 0) return -1; + if (pci_dma_supported(pcidev, 0x00ffffff)) { + dma_mask = 0x00ffffff; /* this enables playback and recording */ + } else if (pci_dma_supported(pcidev, 0xffffffff)) { + dma_mask = 0xffffffff; /* this enables only playback, as the recording BMDMA can handle only 24bits */ + } else { + printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n"); + return -1; + } if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) { printk(KERN_WARNING "solo1: out of memory\n"); return -1; @@ -2259,7 +2270,7 @@ static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid goto err; /* store it in the driver field */ pcidev->driver_data = s; - pcidev->dma_mask = 0xffffff; /* pessimistic; play can handle 32bit addrs */ + pcidev->dma_mask = dma_mask; /* put it into driver list */ list_add_tail(&s->devs, &devs); @@ -2293,7 +2304,7 @@ static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid return -1; } -static void solo1_remove(struct pci_dev *dev) +static void __devinit solo1_remove(struct pci_dev *dev) { struct solo1_state *s = (struct solo1_state *)dev->driver_data; @@ -2319,7 +2330,7 @@ static void solo1_remove(struct pci_dev *dev) dev->driver_data = NULL; } -static const struct pci_device_id id_table[] = { +static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; @@ -2338,9 +2349,11 @@ static int __init init_solo1(void) { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.13 time " __TIME__ " " __DATE__ "\n"); - if (!pci_register_driver(&solo1_driver)) + printk(KERN_INFO "solo1: version v0.14 time " __TIME__ " " __DATE__ "\n"); + if (!pci_register_driver(&solo1_driver)) { + pci_unregister_driver(&solo1_driver); return -ENODEV; + } return 0; } diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index 40511d52b..3a4a94247 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -17,10 +17,15 @@ * 06-01-2000 Refined and bugfixed ISA PnP support, added * CMI 8330 support - Alessandro Zummo <azummo@ita.flashnet.it> * - * * 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump * Alessandro Zummo <azummo@ita.flashnet.it> * + * 11-02-2000 Added Soundblaster AWE 32 PnP support, refined PnP code + * Alessandro Zummo <azummo@ita.flashnet.it> + * + * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup. + * Alessandro Zummo <azummo@ita.flashnet.it> + * */ #include <linux/config.h> @@ -134,7 +139,8 @@ static struct address_info config_mpu; struct pci_dev *sb_dev = NULL, *wss_dev = NULL, - *jp_dev = NULL, + *jp_dev = NULL, +/* *ide_dev = NULL, */ *mpu_dev = NULL, *wt_dev = NULL; /* @@ -156,9 +162,10 @@ int support = 0; /* Set support to load this as a support module */ int sm_games = 0; /* Mixer - see sb_mixer.c */ int acer = 0; /* Do acer notebook init */ -#ifdef CONFIG_ISAPNP +#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE int isapnp = 1; int isapnpjump = 0; +int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */ #else int isapnp = 0; #endif @@ -179,11 +186,13 @@ MODULE_PARM(sm_games, "i"); MODULE_PARM(esstype, "i"); MODULE_PARM(acer, "i"); -#ifdef CONFIG_ISAPNP +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE MODULE_PARM(isapnp, "i"); MODULE_PARM(isapnpjump, "i"); +MODULE_PARM(nosbwave, "i"); MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); +MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver."); #endif MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); @@ -202,79 +211,86 @@ MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks"); void *smw_free = NULL; -#ifdef CONFIG_ISAPNP +#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE /* That's useful. */ -static int check_base(char *devname, char *resname, struct resource *res) +#define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, (resptr)->start) + +static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev) { - if (check_region(res->start, res->end - res->start)) + int err; + + if(dev->active) { - printk(KERN_ERR "sb: %s %s error, i/o at %#lx already in use\n", devname, resname, res->start); - return 0; + printk(KERN_INFO "sb: %s %s already in use\n", devname, resname); + return(NULL); } - printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, res->start); - return 1; -} + if((err = dev->activate(dev)) < 0) + { + printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err); + dev->deactivate(dev); + + return(NULL); + } + return(dev); +} /* Card's specific initialization functions */ -static struct pci_dev *sb_init_generic(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) { - if((sb_dev = isapnp_find_dev(card, - card->vendor, - card->device, - NULL))) + if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL))) { sb_dev->prepare(sb_dev); - sb_dev->activate(sb_dev); - if (!sb_dev->resource[0].start) - return(NULL); - - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[1].start; + if((sb_dev = activate_dev("Soundblaster", "sb", sb_dev))) + { + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + mpu_config->io_base = sb_dev->resource[1].start; + } } return(sb_dev); } -static struct pci_dev *sb_init_ess(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) { - if((sb_dev = isapnp_find_dev(card, - card->vendor, - card->device, - NULL))) + if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL))) { sb_dev->prepare(sb_dev); - sb_dev->activate(sb_dev); - - if (!sb_dev->resource[0].start) - return(NULL); - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[2].start; + if((sb_dev = activate_dev("ESS", "sb", sb_dev))) + { + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + mpu_config->io_base = sb_dev->resource[2].start; + } } return(sb_dev); } -static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) { - /* What a stupid chip... where did they get all those @@@ ?*/ - - printk(KERN_INFO "sb: CMI8330 detected\n"); - - /* Soundblaster compatible logical device. */ - - if((sb_dev = isapnp_find_dev(card, + /* + * The CMI8330/C3D is a very 'stupid' chip... where did they get al those @@@ ? + * It's ISAPnP section is badly designed and has many flaws, i'll do my best + * to workaround them. I strongly suggest you to buy a real soundcard. + * The CMI8330 on my motherboard has also the bad habit to activate + * the rear channel of my amplifier instead of the front one. + */ + + /* @X@0001:Soundblaster. + */ + + if((sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) { #ifdef CMI8330_DMA0BAD @@ -283,11 +299,11 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw sb_dev->prepare(sb_dev); /* This device doesn't work with DMA 0, so we must allocate - it to prevent PnP routines to assign it to the card. - - I know i could have inlined the following lines, but it's cleaner - this way. - */ + * it to prevent PnP routines to assign it to the card. + * + * I know i could have inlined the following lines, but it's cleaner + * this way. + */ #ifdef CMI8330_DMA0BAD if(sb_dev->dma_resource[0].start == 0) @@ -300,69 +316,72 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw } #endif - if(sb_dev->activate(sb_dev) >= 0) + if((sb_dev = activate_dev("CMI8330", "sb", sb_dev))) { hw_config->io_base = sb_dev->resource[0].start; hw_config->irq = sb_dev->irq_resource[0].start; hw_config->dma = sb_dev->dma_resource[0].start; hw_config->dma2 = sb_dev->dma_resource[1].start; - check_base("CMI8330", "sb", &sb_dev->resource[0]); + show_base("CMI8330", "sb", &sb_dev->resource[0]); } - else - printk(KERN_ERR "sb: CMI8330 sb config failed (out of resources?)\n"); #ifdef CMI8330_DMA0BAD if(dmahack) free_dma(0); #endif + + if(!sb_dev) return(NULL); + } else - printk(KERN_ERR "sb: CMI8330 panic! sb base not found\n"); + printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n"); + + /* @H@0001:mpu + */ - if((mpu_dev = isapnp_find_dev(card, +#ifdef CONFIG_MIDI + if((mpu_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) { mpu_dev->prepare(mpu_dev); - /* This disables the interrupt on this resource. Do we need it ? */ + /* This disables the interrupt on this resource. Do we need it ? + */ mpu_dev->irq_resource[0].flags = 0; - if(mpu_dev->activate(mpu_dev) >= 0) + if((mpu_dev = activate_dev("CMI8330", "mpu", mpu_dev))) { - if( check_base("CMI8330", "mpu", &mpu_dev->resource[0]) ) - mpu_config->io_base = mpu_dev->resource[0].start; + show_base("CMI8330", "mpu", &mpu_dev->resource[0]); + mpu_config->io_base = mpu_dev->resource[0].start; } - else - printk(KERN_ERR "sb: CMI8330 mpu config failed (out of resources?)\n"); } else - printk(KERN_ERR "sb: CMI8330 panic! mpu not found\n"); + printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n"); +#endif - /* Gameport. */ + /* @P@:Gameport + */ - if((jp_dev = isapnp_find_dev(card, + if((jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) { jp_dev->prepare(jp_dev); - if(jp_dev->activate(jp_dev) >= 0) - { - check_base("CMI8330", "gameport", &jp_dev->resource[0]); - } - else - printk(KERN_ERR "sb: CMI8330 gameport config failed (out of resources?)\n"); + + if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev))) + show_base("CMI8330", "gameport", &jp_dev->resource[0]); } else - printk(KERN_ERR "sb: CMI8330 panic! gameport not found\n"); - + printk(KERN_ERR "sb: CMI8330 panic: gameport not found\n"); - /* OPL3 support */ + /* @@@0001:OPL3 + */ #if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE) - if((wss_dev = isapnp_find_dev(card, + if((wss_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) { wss_dev->prepare(wss_dev); @@ -372,15 +391,11 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw wss_dev->irq_resource[0].flags = 0; wss_dev->dma_resource[0].flags = 0; - if(wss_dev->activate(wss_dev) >= 0) - { - check_base("CMI8330", "opl3", &wss_dev->resource[1]); - } - else - printk(KERN_ERR "sb: CMI8330 opl3 config failed (out of resources?)\n"); + if((wss_dev = activate_dev("CMI8330", "opl3", wss_dev))) + show_base("CMI8330", "opl3", &wss_dev->resource[1]); } else - printk(KERN_ERR "sb: CMI8330 panic! opl3 not found\n"); + printk(KERN_ERR "sb: CMI8330 panic: opl3 not found\n"); #endif printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n"); @@ -388,18 +403,25 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw return(sb_dev); } -static struct pci_dev *sb_init_awe64(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) -{ - printk(KERN_INFO "sb: SoundBlaster AWE 64 detected\n"); - - /* CTL0042:Audio. */ +/* Specific support for awe will be dropped when: + * a) The new awe_wawe driver with PnP support will be introduced in the kernel + * b) The joystick driver will support PnP + */ - if((sb_dev = isapnp_find_dev(card, - ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL))) +static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) +{ + /* CTL0042:Audio SB64 + * CTL0031:Audio SB32 + * CTL0045:Audio SB64 + */ + + if( (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)) || + (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), NULL)) || + (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), NULL)) ) { sb_dev->prepare(sb_dev); - if(sb_dev->activate(sb_dev) >= 0) + if((sb_dev = activate_dev("AWE", "sb", sb_dev))) { hw_config->io_base = sb_dev->resource[0].start; hw_config->irq = sb_dev->irq_resource[0].start; @@ -408,87 +430,144 @@ static struct pci_dev *sb_init_awe64(struct pci_bus *card, struct address_info * mpu_config->io_base = sb_dev->resource[1].start; - check_base("AWE64", "sb", &sb_dev->resource[0]); - check_base("AWE64", "mpu", &sb_dev->resource[1]); - check_base("AWE64", "opl3", &sb_dev->resource[2]); + show_base("AWE", "sb", &sb_dev->resource[0]); + show_base("AWE", "mpu", &sb_dev->resource[1]); + show_base("AWE", "opl3", &sb_dev->resource[2]); } else - printk(KERN_ERR "sb: AWE64 sb config failed (out of resources?)\n"); + return(NULL); } else - printk(KERN_ERR "sb: AWE64 panic! sb base not found\n"); + printk(KERN_ERR "sb: AWE panic: sb base not found\n"); - /* CTL7002:Game */ + /* CTL7002:Game SB64 + * CTL7001:Game SB32 + */ - if((jp_dev = isapnp_find_dev(card, - ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL))) + if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) || + (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) ) { jp_dev->prepare(jp_dev); - if(jp_dev->activate(jp_dev) >= 0) + if((jp_dev = activate_dev("AWE", "gameport", jp_dev))) + show_base("AWE", "gameport", &jp_dev->resource[0]); + } + else + printk(KERN_ERR "sb: AWE panic: gameport not found\n"); + + + /* CTL0022:WaveTable SB64 + * CTL0021:WaveTable SB32 + */ + + if( nosbwave == 0 && + ( (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) || + (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) || + (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) )) + { + wt_dev->prepare(wt_dev); + + if((wt_dev = activate_dev("AWE", "wavetable", wt_dev))) { - check_base("AWE64", "gameport", &jp_dev->resource[0]); + show_base("AWE", "wavetable", &wt_dev->resource[0]); + show_base("AWE", "wavetable", &wt_dev->resource[1]); + show_base("AWE", "wavetable", &wt_dev->resource[2]); } - else - printk(KERN_ERR "sb: AWE64 gameport config failed (out of resources?)\n"); } else - printk(KERN_ERR "sb: AWE64 panic! gameport not found\n"); + printk(KERN_ERR "sb: AWE panic: wavetable not found\n"); - /* CTL0022:WaveTable */ + /* CTL2011:IDE SB32/64 + */ - if((wt_dev = isapnp_find_dev(card, - ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL))) +/* No reasons to enable this... or not? */ +/* + if( (ide_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x2011), NULL)) ) { - wt_dev->prepare(wt_dev); + ide_dev->prepare(ide_dev); - if(wt_dev->activate(wt_dev) >= 0) + if((ide_dev = activate_dev("AWE", "IDE", ide_dev))) { - check_base("AWE64", "wavetable", &wt_dev->resource[0]); - check_base("AWE64", "wavetable", &wt_dev->resource[1]); - check_base("AWE64", "wavetable", &wt_dev->resource[2]); + show_base("AWE", "IDE 1", &ide_dev->resource[0]); + show_base("AWE", "IDE 2", &ide_dev->resource[1]); } - else - printk(KERN_ERR "sb: AWE64 wavetable config failed (out of resources?)\n"); } else - printk(KERN_ERR "sb: AWE64 panic! wavetable not found\n"); + printk(KERN_ERR "sb: AWE panic: IDE not found\n"); +*/ - printk(KERN_INFO "sb: AWE64 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n"); + printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n"); return(sb_dev); } +#define SBF_DEV 0x01 -static struct { unsigned short vendor, function; struct pci_dev * (*initfunc)(struct pci_bus *, struct address_info *, struct address_info *); char *name; } + +static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; } isapnp_sb_list[] __initdata = { - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), &sb_init_awe64, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), &sb_init_ess, "ESS 1869" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), &sb_init_ess, "ESS 1878" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), &sb_init_ess, "ESS 1879" }, - {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), &sb_init_cmi, "CMI 8330 SoundPRO" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, + {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, {0} }; +static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot) +{ + struct pci_dev *idev = NULL; + + /* You missed the init func? That's bad. */ + if(isapnp_sb_list[slot].initfunc) + { + char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name; + + printk(KERN_INFO "sb: %s detected\n", busname); + + /* Initialize this baby. */ + + if((idev = isapnp_sb_list[slot].initfunc(bus, card, hw_config, mpu_config))) + { + /* We got it. */ + + printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n", + busname, + hw_config->io_base, hw_config->irq, hw_config->dma, + hw_config->dma2); + return 1; + } + else + printk(KERN_INFO "sb: Failed to initialize %s\n", busname); + } + else + printk(KERN_ERR "sb: Bad entry in sb_card.c PnP table\n"); + + return 0; +} + /* Actually this routine will detect and configure only the first card with successful - initalization. isapnpjump could be used to jump to a specific entry. + initialization. isapnpjump could be used to jump to a specific entry. Please always add entries at the end of the array. Should this be fixed? - azummo */ -static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) { - +static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) +{ int i; /* Count entries in isapnp_sb_list */ @@ -502,34 +581,43 @@ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address } for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) { - struct pci_bus *card = NULL; - - while ((card = isapnp_find_card( - isapnp_sb_list[i].vendor, - isapnp_sb_list[i].function, - card))) { - /* You missed the init func? That's bad. */ + if(!(isapnp_sb_list[i].flags & SBF_DEV)) + { + struct pci_bus *bus = NULL; + + while ((bus = isapnp_find_card( + isapnp_sb_list[i].vendor, + isapnp_sb_list[i].function, + bus))) { + + if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i)) + return 0; + } + } + } - if(isapnp_sb_list[i].initfunc) - { - struct pci_dev *idev = NULL; + /* No cards found. I'll try now to search inside every card for a logical device + * that matches any entry marked with SBF_DEV in the table. + */ + + for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) { - /* Initialize this baby. */ + if(isapnp_sb_list[i].flags & SBF_DEV) + { + struct pci_dev *card = NULL; - if((idev = isapnp_sb_list[i].initfunc(card, hw_config, mpu_config))) - { - /* We got it. */ + while ((card = isapnp_find_dev(NULL, + isapnp_sb_list[i].vendor, + isapnp_sb_list[i].function, + card))) { - printk(KERN_INFO "sb: ISAPnP reports %s at i/o %#x, irq %d, dma %d, %d\n", - isapnp_sb_list[i].name, - hw_config->io_base, hw_config->irq, hw_config->dma, - hw_config->dma2); + if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i)) return 0; - } } } } + return -ENODEV; } #endif @@ -544,18 +632,15 @@ int init_module(void) able to disable PNP support for this single driver! */ -#ifdef CONFIG_ISAPNP - if (isapnp) +#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE + if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) ) { - if(sb_probe_isapnp(&config, &config_mpu) < 0 ) - { - printk(KERN_ERR "sb_card: No ISAPnP cards found\n"); - return -EINVAL; - } + printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n"); + isapnp = 0; } - else +#endif + if(isapnp == 0) { -#endif if (io == -1 || dma == -1 || irq == -1) { printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n"); @@ -566,11 +651,8 @@ int init_module(void) config.irq = irq; config.dma = dma; config.dma2 = dma16; -#ifdef CONFIG_ISAPNP } -#endif - /* If this is not before the #ifdef line, there's a reason... */ config.card_subtype = type; if (!probe_sb(&config)) @@ -604,6 +686,7 @@ void cleanup_module(void) if(sb_dev) sb_dev->deactivate(sb_dev); if(jp_dev) jp_dev->deactivate(jp_dev); if(wt_dev) wt_dev->deactivate(wt_dev); +/* if(ide_dev) wt_dev->deactivate(ide_dev); */ if(mpu_dev) mpu_dev->deactivate(mpu_dev); if(wss_dev) wss_dev->deactivate(wss_dev); } diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index 6e17c8f93..ae86b61f7 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -2430,7 +2430,7 @@ static struct initvol { ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { static const char __initlocaldata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller"; struct sv_state *s; @@ -2447,6 +2447,10 @@ static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) return -1; if (pcidev->irq == 0) return -1; + if (!pci_dma_supported(pcidev, 0x00ffffff)) { + printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n"); + return -1; + } /* try to allocate a DDMA resource if not already available */ if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) { pcidev->resource[RESOURCE_DDMA].start = 0; @@ -2598,7 +2602,7 @@ static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) return -1; } -static void sv_remove(struct pci_dev *dev) +static void __devinit sv_remove(struct pci_dev *dev) { struct sv_state *s = (struct sv_state *)dev->driver_data; @@ -2625,7 +2629,7 @@ static void sv_remove(struct pci_dev *dev) dev->driver_data = NULL; } -static const struct pci_device_id id_table[] = { +static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; @@ -2648,8 +2652,10 @@ static int __init init_sonicvibes(void) if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); #endif - if (!pci_register_driver(&sv_driver)) + if (!pci_register_driver(&sv_driver)) { + pci_unregister_driver(&sv_driver); return -ENODEV; + } return 0; } diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c index a8bc739cc..923b46e90 100644 --- a/drivers/sound/sound_core.c +++ b/drivers/sound/sound_core.c @@ -43,13 +43,17 @@ #include <linux/sound.h> #include <linux/major.h> #include <linux/kmod.h> - - +#include <linux/devfs_fs_kernel.h> + +#define SOUND_STEP 16 + + struct sound_unit { int unit_minor; struct file_operations *unit_fops; struct sound_unit *next; + devfs_handle_t de; }; #ifdef CONFIG_SOUND_MSNDCLAS @@ -82,7 +86,7 @@ static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, if(*list==NULL || (*list)->unit_minor>n) break; list=&((*list)->next); - n+=16; + n+=SOUND_STEP; } if(n>=top) @@ -129,6 +133,7 @@ static void __sound_remove_unit(struct sound_unit **list, int unit) if(p->unit_minor==unit) { *list=p->next; + devfs_unregister (p->de); kfree(p); MOD_DEC_USE_COUNT; return; @@ -148,11 +153,15 @@ spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED; * Allocate the controlling structure and add it to the sound driver * list. Acquires locks as needed */ + +static devfs_handle_t devfs_handle = NULL; -static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top) +static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode) { int r; struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL); + char name_buf[16]; + if(s==NULL) return -ENOMEM; @@ -162,6 +171,13 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f if(r<0) kfree(s); + if (r == low) + sprintf (name_buf, "%s", name); + else + sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP); + s->de = devfs_register (devfs_handle, name_buf, 0, + DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor, + S_IFCHR | mode, 0, 0, fops, NULL); return r; } @@ -203,21 +219,76 @@ static struct sound_unit *chains[16]; int register_sound_special(struct file_operations *fops, int unit) { - return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1); + char *name; + + switch (unit) { + case 0: + name = "mixer"; + break; + case 1: + name = "sequencer"; + break; + case 2: + name = "midi00"; + break; + case 3: + name = "dsp"; + break; + case 4: + name = "audio"; + break; + case 5: + name = "unknown5"; + break; + case 6: + name = "sndstat"; + break; + case 7: + name = "unknown7"; + break; + case 8: + name = "sequencer2"; + break; + case 9: + name = "dmmidi"; + break; + case 10: + name = "dmfm"; + break; + case 11: + name = "unknown11"; + break; + case 12: + name = "adsp"; + break; + case 13: + name = "amidi"; + break; + case 14: + name = "admmidi"; + break; + default: + name = "unknown"; + break; + } + return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1, + name, S_IRUGO | S_IWUGO); } EXPORT_SYMBOL(register_sound_special); int register_sound_mixer(struct file_operations *fops, int dev) { - return sound_insert_unit(&chains[0], fops, dev, 0, 128); + return sound_insert_unit(&chains[0], fops, dev, 0, 128, + "mixer", S_IRUGO | S_IWUGO); } EXPORT_SYMBOL(register_sound_mixer); int register_sound_midi(struct file_operations *fops, int dev) { - return sound_insert_unit(&chains[2], fops, dev, 2, 130); + return sound_insert_unit(&chains[2], fops, dev, 2, 130, + "midi", S_IRUGO | S_IWUGO); } EXPORT_SYMBOL(register_sound_midi); @@ -229,14 +300,16 @@ EXPORT_SYMBOL(register_sound_midi); int register_sound_dsp(struct file_operations *fops, int dev) { - return sound_insert_unit(&chains[3], fops, dev, 3, 131); + return sound_insert_unit(&chains[3], fops, dev, 3, 131, + "dsp", S_IWUGO | S_IRUSR | S_IRGRP); } EXPORT_SYMBOL(register_sound_dsp); int register_sound_synth(struct file_operations *fops, int dev) { - return sound_insert_unit(&chains[9], fops, dev, 9, 137); + return sound_insert_unit(&chains[9], fops, dev, 9, 137, + "synth", S_IRUGO | S_IWUGO); } EXPORT_SYMBOL(register_sound_synth); @@ -359,7 +432,8 @@ void cleanup_module(void) { /* We have nothing to really do here - we know the lists must be empty */ - unregister_chrdev(SOUND_MAJOR, "sound"); + devfs_unregister_chrdev(SOUND_MAJOR, "sound"); + devfs_unregister (devfs_handle); } int init_module(void) @@ -367,11 +441,12 @@ int init_module(void) int soundcore_init(void) #endif { - if(register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) + if(devfs_register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) { printk(KERN_ERR "soundcore: sound device already in use.\n"); return -EBUSY; } + devfs_handle = devfs_mk_dir (NULL, "sound", 0, NULL); /* * Now init non OSS drivers */ diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 5593cf5dd..a1d682969 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -15,6 +15,9 @@ * integrated sound_switch.c * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, * which should disappear in the near future) + * Eric Dumas : devfs support (22-Jan-98) <dumas@linux.eu.org> with fixups + * by C. Scott Ananian <cananian@alumni.princeton.edu> + * Richard Gooch : moved common (non OSS-specific) devices to sound_core.c * * Rob Riggs Added persistent DMA buffers support (1998/10/17) */ @@ -36,6 +39,8 @@ #include <linux/wait.h> #include <linux/malloc.h> #include <linux/ioport.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/major.h> #endif /* __KERNEL__ */ #include <linux/delay.h> #include <linux/proc_fs.h> @@ -93,7 +98,6 @@ unsigned long seq_time = 0; /* Time for /dev/sequencer */ static mixer_vol_table mixer_vols[MAX_MIXER_DEV]; static int num_mixer_volumes = 0; - int *load_mixer_volumes(char *name, int *levels, int present) { int i, n; @@ -811,6 +815,66 @@ bad1: return -1; } + +/* These device names follow the official Linux device list, + * Documentation/devices.txt. Let us know if there are other + * common names we should support for compatibility. + * Only those devices not created by the generic code in sound_core.c are + * registered here. + */ +static const struct { + unsigned short minor; + char *name; + umode_t mode; + int *num; +} dev_list[] = { /* list of minor devices */ +#ifdef CONFIG_AUDIO +/* seems to be some confusion here -- this device is not in the device list */ + {SND_DEV_DSP16, "dspW", S_IWUGO | S_IRUSR | S_IRGRP, + &num_audiodevs}, + {SND_DEV_AUDIO, "audio", S_IWUGO | S_IRUSR | S_IRGRP, + &num_audiodevs}, +#endif /* CONFIG_AUDIO */ +}; + +static char * +soundcard_make_name(char *buf, char *name, int idx) { + if (idx==0) + sprintf(buf, "sound/%s", name); + else + sprintf(buf, "sound/%s%d", name, idx); + return buf; +} + +/* Register/unregister audio entries */ +static void soundcard_register_devfs (int do_register) +{ + char name_buf[32]; + int i, j, num; + + for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) + { + num = (dev_list[i].num == NULL) ? 0 : *dev_list[i].num; + for (j = 0; j < num || j == 0; j++) + { + soundcard_make_name (name_buf, dev_list[i].name, j); + if (do_register) + devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE, + SOUND_MAJOR, dev_list[i].minor+ (j* 0x10), + S_IFCHR | dev_list[i].mode, 0, 0, + &oss_sound_fops, NULL); + else + { + devfs_handle_t de; + + de = devfs_find_handle (NULL, name_buf, 0, 0, 0, + DEVFS_SPECIAL_CHR, 0); + devfs_unregister (de); + } + } + } +} + #ifdef MODULE static void #else @@ -849,6 +913,7 @@ soundcard_init(void) if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info)) printk(KERN_ERR "sound: registering /proc/sound failed\n"); #endif + soundcard_register_devfs(1); /* register after we know # of devices */ } #ifdef MODULE @@ -931,6 +996,7 @@ void cleanup_module(void) return; } remove_proc_entry("sound", NULL); + soundcard_register_devfs (0); if (chrdev_registered) destroy_special_devices(); |