summaryrefslogtreecommitdiffstats
path: root/drivers/sound
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sound')
-rw-r--r--drivers/sound/ac97_codec.c155
-rw-r--r--drivers/sound/ac97_codec.h9
-rw-r--r--drivers/sound/dmasound.c109
-rw-r--r--drivers/sound/es1370.c14
-rw-r--r--drivers/sound/es1371.c14
-rw-r--r--drivers/sound/esssolo1.c35
-rw-r--r--drivers/sound/sb_card.c417
-rw-r--r--drivers/sound/sonicvibes.c14
-rw-r--r--drivers/sound/sound_core.c97
-rw-r--r--drivers/sound/soundcard.c68
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();