diff options
Diffstat (limited to 'drivers/sound')
29 files changed, 1327 insertions, 482 deletions
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index 6b176afb8..ebc695d0c 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -13,7 +13,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND if [ "$CONFIG_SOUND_ES1370" = "y" ]; then bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT - fi + fi dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND fi dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND @@ -71,6 +71,10 @@ fi dep_tristate 'OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then + if [ "$CONFIG_SOUND_OSS" = "y" ]; then + bool 'Persistent DMA buffers' CONFIG_SOUND_DMAP + fi + dep_tristate 'ProAudioSpectrum 16 support' CONFIG_SOUND_PAS $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_PAS" = "y" ]; then int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10 @@ -134,6 +138,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then dep_tristate 'Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_MSS" = "y" ]; then + bool 'Enable support for the SoundPro mixer' CONFIG_SOUND_SPRO hex 'MSS/WSS I/O base 530, 604, E80 or F40' CONFIG_MSS_BASE 530 int 'MSS/WSS IRQ 7, 9, 10 or 11' CONFIG_MSS_IRQ 11 int 'MSS/WSS DMA 0, 1 or 3' CONFIG_MSS_DMA 3 diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c index 6d7c2e13e..c94481524 100644 --- a/drivers/sound/ad1816.c +++ b/drivers/sound/ad1816.c @@ -32,10 +32,10 @@ Please report any bugs to: tek@rbg.informatik.tu-darmstadt.de ------------------------------------------------------------------------------- -version: 1.2 -cvs: $Header: /home/tek/tmp/CVSROOT/sound21/ad1816.c,v 1.28 1999/01/16 19:01:36 tek Exp $ +version: 1.3 +cvs: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $ status: experimental -date: 1999/01/16 +date: 1999/4/18 Changes: Oleg Drokin: Some cleanup of load/unload functions. 1998/11/24 @@ -44,6 +44,13 @@ Changes: some argument checks added 1998/11/30 Thorsten Knabe: Buggy isa bridge workaround added 1999/01/16 + + David Moews/Thorsten Knabe: Introduced options + parameter. Added slightly modified patch from + David Moews to disable dsp audio sources by setting + bit 0 of options parameter. This seems to be + required by some Aztech/Newcom SC-16 cards. 1999/04/18 + */ #include <linux/config.h> @@ -100,6 +107,8 @@ static int nr_ad1816_devs = 0; static int ad1816_clockfreq=33000; +static int options=0; + /* for backward mapping of irq to sound device */ static volatile char irq2dev[17] = {-1, -1, -1, -1, -1, -1, -1, -1, @@ -1091,12 +1100,14 @@ int probe_ad1816 ( struct address_info *hw_config ) int tmp; printk("ad1816: AD1816 sounddriver Copyright (C) 1998 by Thorsten Knabe\n"); - printk("ad1816: $Header: /home/tek/tmp/CVSROOT/sound21/ad1816.c,v 1.28 1999/01/16 19:01:36 tek Exp $\n"); - printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, isadmabug=%d\n", + printk("ad1816: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $\n"); + printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, clockfreq=%d, options=%d isadmabug=%d\n", hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma2, + ad1816_clockfreq, + options, isa_dma_bridge_buggy); if (check_region (io_base, 16)) { @@ -1264,7 +1275,11 @@ void attach_ad1816 (struct address_info *hw_config) nr_ad1816_devs++; ad_write(devc,32,0x80f0); /* sound system mode */ - ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */ + if (options&1) { + ad_write(devc,33,0); /* disable all audiosources for dsp */ + } else { + ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */ + } ad_write(devc,4,0x8080); /* default values for volumes (muted)*/ ad_write(devc,5,0x8080); ad_write(devc,6,0x8080); @@ -1274,7 +1289,7 @@ void attach_ad1816 (struct address_info *hw_config) ad_write(devc,17,0x8888); ad_write(devc,18,0x8888); ad_write(devc,19,0xc888); /* +20db mic active */ - ad_write(devc,14,0x0000); /* Master volume unmuted full power */ + ad_write(devc,14,0x0000); /* Master volume unmuted */ ad_write(devc,39,0x009f); /* 3D effect on 0% phone out muted */ ad_write(devc,44,0x0080); /* everything on power, 3d enabled for d/a */ outb(0x10,devc->base+8); /* set dma mode */ @@ -1382,6 +1397,7 @@ MODULE_PARM(irq,"i"); MODULE_PARM(dma,"i"); MODULE_PARM(dma2,"i"); MODULE_PARM(ad1816_clockfreq,"i"); +MODULE_PARM(options,"i"); struct address_info cfg; diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 709d7f2ed..baa090771 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -100,6 +100,11 @@ ad1848_port_info; static int nr_ad1848_devs = 0; int deskpro_xl = 0; +#ifdef CONFIG_SOUND_SPRO +int soundpro = 1; +#else +int soundpro = 0; +#endif static volatile char irq2dev[17] = { -1, -1, -1, -1, -1, -1, -1, -1, @@ -132,6 +137,21 @@ static ad1848_info adev_info[MAX_AUDIO_DEV]; #define io_Status(d) ((d)->base+2) #define io_Polled_IO(d) ((d)->base+3) +static struct { + unsigned char flags; +#define CAP_F_TIMER 0x01 +} capabilities [9 /*devc->model */ ] = { + {0} + ,{0} /* MD_1848 */ + ,{CAP_F_TIMER} /* MD_4231 */ + ,{CAP_F_TIMER} /* MD_4231A */ + ,{CAP_F_TIMER} /* MD_1845 */ + ,{CAP_F_TIMER} /* MD_4232 */ + ,{0} /* MD_C930 */ + ,{CAP_F_TIMER} /* MD_IWAVE */ + ,{0} /* MD_4235 */ +}; + static int ad1848_open(int dev, int mode); static void ad1848_close(int dev); static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag); @@ -312,22 +332,21 @@ static int ad1848_set_recmask(ad1848_info * devc, int mask) if (mask & (1 << i)) n++; - if (n == 0) - mask = SOUND_MASK_MIC; - else if (n != 1) /* Too many devices selected */ - { - mask &= ~devc->recmask; /* Filter out active settings */ + if (!soundpro) { + if (n == 0) + mask = SOUND_MASK_MIC; + else if (n != 1) { /* Too many devices selected */ + mask &= ~devc->recmask; /* Filter out active settings */ - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; - if (n != 1) - mask = SOUND_MASK_MIC; - } - switch (mask) - { + if (n != 1) + mask = SOUND_MASK_MIC; + } + switch (mask) { case SOUND_MASK_MIC: recdev = 2; break; @@ -349,11 +368,38 @@ static int ad1848_set_recmask(ad1848_info * devc, int mask) default: mask = SOUND_MASK_MIC; recdev = 2; - } + } + + recdev <<= 6; + ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); + ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); + } else { /* soundpro */ + unsigned char val; + int set_rec_bit; + int j; + + for (i = 0; i < 32; i++) { /* For each bit */ + if ((devc->supported_rec_devices & (1 << i)) == 0) + continue; /* Device not supported */ + + for (j = LEFT_CHN; j <= RIGHT_CHN; j++) { + if (devc->mix_devices[i][j].nbits == 0) /* Inexistent channel */ + continue; + + /* + * This is tricky: + * set_rec_bit becomes 1 if the corresponding bit in mask is set + * then it gets flipped if the polarity is inverse + */ + set_rec_bit = ((mask & (1 << i)) != 0) ^ devc->mix_devices[i][j].recpol; - recdev <<= 6; - ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); - ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev); + val = ad_read(devc, devc->mix_devices[i][j].recreg); + val &= ~(1 << devc->mix_devices[i][j].recpos); + val |= (set_rec_bit << devc->mix_devices[i][j].recpos); + ad_write(devc, devc->mix_devices[i][j].recreg, val); + } + } + } /* Rename the mixer bits back if necessary */ for (i = 0; i < 32; i++) @@ -371,7 +417,8 @@ static int ad1848_set_recmask(ad1848_info * devc, int mask) return mask; } -static void change_bits(ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) +static void change_bits(ad1848_info * devc, unsigned char *regval, + unsigned char *muteval, int dev, int chn, int newval) { unsigned char mask; int shift; @@ -379,7 +426,7 @@ static void change_bits(ad1848_info * devc, unsigned char *regval, int dev, int int mutemask; int set_mute_bit; - set_mute_bit = (newval == 0); + set_mute_bit = (newval == 0) ^ devc->mix_devices[dev][chn].mutepol; if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ newval = 100 - newval; @@ -399,8 +446,11 @@ static void change_bits(ad1848_info * devc, unsigned char *regval, int dev, int } newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ - *regval |= ((newval & mask) << shift) | mute; /* Set new value */ + *regval &= ~(mask << shift); /* Clear bits */ + *regval |= (newval & mask) << shift; /* Set new value */ + + *muteval &= mutemask; + *muteval |= mute; } static int ad1848_mixer_get(ad1848_info * devc, int dev) @@ -413,15 +463,36 @@ static int ad1848_mixer_get(ad1848_info * devc, int dev) return devc->levels[dev]; } +static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int channel) +{ + int regoffs, muteregoffs; + unsigned char val, muteval; + + regoffs = devc->mix_devices[dev][channel].regno; + muteregoffs = devc->mix_devices[dev][channel].mutereg; + val = ad_read(devc, regoffs); + + if (muteregoffs != regoffs) { + muteval = ad_read(devc, muteregoffs); + change_bits(devc, &val, &muteval, dev, channel, value); + } + else + change_bits(devc, &val, &val, dev, channel, value); + + ad_write(devc, regoffs, val); + devc->saved_regs[regoffs] = val; + if (muteregoffs != regoffs) { + ad_write(devc, muteregoffs, muteval); + devc->saved_regs[muteregoffs] = muteval; + } +} + static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) { int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; int retvol; - int regoffs; - unsigned char val; - if (dev > 31) return -EINVAL; @@ -430,6 +501,9 @@ static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) dev = devc->mixer_reroute[dev]; + if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) + return -EINVAL; + if (left > 100) left = 100; if (right > 100) @@ -444,34 +518,21 @@ static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) left = mix_cvt[left]; right = mix_cvt[right]; - if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; - devc->levels[dev] = retvol; /* * Set the left channel */ - - regoffs = devc->mix_devices[dev][LEFT_CHN].regno; - val = ad_read(devc, regoffs); - change_bits(devc, &val, dev, LEFT_CHN, left); - ad_write(devc, regoffs, val); - devc->saved_regs[regoffs] = val; + ad1848_mixer_set_channel(devc, dev, left, LEFT_CHN); /* * Set the right channel */ - if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) - return retvol; /* Was just a mono channel */ - - regoffs = devc->mix_devices[dev][RIGHT_CHN].regno; - val = ad_read(devc, regoffs); - change_bits(devc, &val, dev, RIGHT_CHN, right); - ad_write(devc, regoffs, val); - devc->saved_regs[regoffs] = val; + goto out; + ad1848_mixer_set_channel(devc, dev, right, RIGHT_CHN); + out: return retvol; } @@ -487,6 +548,8 @@ static void ad1848_mixer_reset(ad1848_info * devc) for (i = 0; i < 32; i++) devc->mixer_reroute[i] = i; + devc->supported_rec_devices = MODE1_REC_DEVICES; + switch (devc->model) { case MD_4231: @@ -509,11 +572,18 @@ static void ad1848_mixer_reset(ad1848_info * devc) devc->supported_devices = MODE3_MIXER_DEVICES; break; + case MD_1848: + if (soundpro) { + devc->supported_devices = SPRO_MIXER_DEVICES; + devc->supported_rec_devices = SPRO_REC_DEVICES; + devc->mix_devices = &(spro_mix_devices[0]); + break; + } + default: devc->supported_devices = MODE1_MIXER_DEVICES; } - devc->supported_rec_devices = MODE1_REC_DEVICES; devc->orig_devices = devc->supported_devices; devc->orig_rec_devices = devc->supported_rec_devices; @@ -528,10 +598,20 @@ static void ad1848_mixer_reset(ad1848_info * devc) ad1848_set_recmask(devc, SOUND_MASK_MIC); devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; - if (devc->mixer_output_port & AUDIO_SPEAKER) - ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ - else - ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ + + if (!soundpro) { + if (devc->mixer_output_port & AUDIO_SPEAKER) + ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ + else + ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ + } else { + /* + * From the "wouldn't it be nice if the mixer API had (better) + * support for custom stuff" category + */ + /* Enable surround mode and SB16 mixer */ + ad_write(devc, 16, 0x60); + } } static int ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) @@ -1357,6 +1437,8 @@ static void ad1848_init_hw(ad1848_info * devc) { devc->audio_flags &= ~DMA_DUPLEX; ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ + if (soundpro) + ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ } outb((0), io_Status(devc)); /* Clear pending interrupts */ @@ -1706,7 +1788,27 @@ int ad1848_detect(int io_base, int *ad_flags, int *osp) DDB(printk("ad1848_detect() - step K\n")); } + } else if (tmp1 == 0x0a) { + /* + * Is it perhaps a SoundPro CMI8330? + * If so, then we should be able to change indirect registers + * greater than I15 after activating MODE2, even though reading + * back I12 does not show it. + */ + + /* + * Let's try comparing register values + */ + for (i = 0; i < 16; i++) { + if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) { + DDB(printk("ad1848 detect step H(%d/%x/%x) - SoundPro chip?\n", i, tmp1, tmp2)); + soundpro = 1; + devc->chip_name = "SoundPro CMI 8330"; + break; + } + } } + DDB(printk("ad1848_detect() - step L\n")); if (ad_flags) { @@ -1807,7 +1909,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt /* Don't free it either then.. */ devc->irq = 0; } - if (devc->model != MD_1848 && devc->model != MD_C930) + if (capabilities[devc->model].flags & CAP_F_TIMER) { #ifndef __SMP__ int x; @@ -1840,8 +1942,8 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt irq2dev[-irq] = devc->dev_no = my_dev; #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) - if (devc->model != MD_1848 && - devc->model != MD_C930 && devc->irq_ok) + if ((capabilities[devc->model].flags & CAP_F_TIMER) && + devc->irq_ok) ad1848_tmr_install(my_dev); #endif @@ -2302,7 +2404,8 @@ int probe_ms_sound(struct address_info *hw_config) (hw_config->irq != 7) && (hw_config->irq != 9) && (hw_config->irq != 10) && - (hw_config->irq != 11)) + (hw_config->irq != 11) && + (hw_config->irq != 12)) { printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); return 0; @@ -2555,6 +2658,7 @@ MODULE_PARM(dma, "i"); /* First DMA channel */ MODULE_PARM(dma2, "i"); /* Second DMA channel */ MODULE_PARM(type, "i"); /* Card type */ MODULE_PARM(deskpro_xl, "i"); /* Special magic for Deskpro XL boxen */ +MODULE_PARM(soundpro, "i"); /* More special magic for SoundPro chips */ int io = -1; int irq = -1; diff --git a/drivers/sound/ad1848_mixer.h b/drivers/sound/ad1848_mixer.h index 5768420a9..fdd06e499 100644 --- a/drivers/sound/ad1848_mixer.h +++ b/drivers/sound/ad1848_mixer.h @@ -24,7 +24,10 @@ * solution). */ #define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ - SOUND_MASK_LINE1|SOUND_MASK_IMIX) + SOUND_MASK_LINE1 | SOUND_MASK_IMIX) + +#define SPRO_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_LINE1) #define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \ SOUND_MASK_LINE2 | \ @@ -47,16 +50,27 @@ SOUND_MASK_LINE3 | \ SOUND_MASK_IGAIN | SOUND_MASK_PCM) +#define SPRO_MIXER_DEVICES (SOUND_MASK_VOLUME | SOUND_MASK_PCM | \ + SOUND_MASK_LINE | SOUND_MASK_SYNTH | \ + SOUND_MASK_CD | SOUND_MASK_MIC | \ + SOUND_MASK_SPEAKER | SOUND_MASK_LINE1 | \ + SOUND_MASK_OGAIN) + struct mixer_def { - unsigned int regno: 5; - unsigned int polarity:1; /* 0=normal, 1=reversed */ - unsigned int bitpos:3; - unsigned int nbits:3; - unsigned int mutepos:4; + unsigned int regno:5; /* register number for volume */ + unsigned int polarity:1; /* volume polarity: 0=normal, 1=reversed */ + unsigned int bitpos:3; /* position of bits in register for volume */ + unsigned int nbits:3; /* number of bits in register for volume */ + unsigned int mutereg:5; /* register number for mute bit */ + unsigned int mutepol:1; /* mute polarity: 0=normal, 1=reversed */ + unsigned int mutepos:4; /* position of mute bit in register */ + unsigned int recreg:5; /* register number for recording bit */ + unsigned int recpol:1; /* recording polarity: 0=normal, 1=reversed */ + unsigned int recpos:4; /* position of recording bit in register */ }; static char mix_cvt[101] = { - 0, 0,3,7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, + 0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65, 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79, 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90, @@ -77,7 +91,17 @@ typedef mixer_ent mixer_ents[2]; */ #define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r, mute_bit) \ - {{reg_l, pola_l, pos_l, len_l, mute_bit}, {reg_r, pola_r, pos_r, len_r, mute_bit}} + [name] = {{reg_l, pola_l, pos_l, len_l, reg_l, 0, mute_bit, 0, 0, 8}, \ + {reg_r, pola_r, pos_r, len_r, reg_r, 0, mute_bit, 0, 0, 8}} + +#define MIX_ENT2(name, reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ + rec_reg_l, rec_pola_l, rec_pos_l, \ + reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ + rec_reg_r, rec_pola_r, rec_pos_r) \ + [name] = {{reg_l, pola_l, pos_l, len_l, mute_reg_l, mute_pola_l, mute_pos_l, \ + rec_reg_l, rec_pola_l, rec_pos_l}, \ + {reg_r, pola_r, pos_r, len_r, mute_reg_r, mute_pola_r, mute_pos_r, \ + rec_reg_r, rec_pola_r, rec_pos_r}} static mixer_ents ad1848_mix_devices[32] = { MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4, 8), @@ -144,6 +168,30 @@ MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4, 7), MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4, 7) }; +static mixer_ents spro_mix_devices[32] = { +MIX_ENT (SOUND_MIXER_VOLUME, 19, 0, 4, 4, 19, 0, 0, 4, 8), +MIX_ENT (SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT2(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 23, 0, 3, 0, 0, 8, + 5, 1, 1, 4, 23, 0, 3, 0, 0, 8), +MIX_ENT (SOUND_MIXER_PCM, 6, 1, 1, 4, 7, 1, 1, 4, 8), +MIX_ENT (SOUND_MIXER_SPEAKER, 18, 0, 3, 2, 0, 0, 0, 0, 8), +MIX_ENT2(SOUND_MIXER_LINE, 20, 0, 4, 4, 17, 1, 4, 16, 0, 2, + 20, 0, 0, 4, 17, 1, 3, 16, 0, 1), +MIX_ENT2(SOUND_MIXER_MIC, 18, 0, 0, 3, 17, 1, 0, 16, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT2(SOUND_MIXER_CD, 21, 0, 4, 4, 17, 1, 2, 16, 0, 4, + 21, 0, 0, 4, 17, 1, 1, 16, 0, 3), +MIX_ENT (SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_IGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT (SOUND_MIXER_OGAIN, 17, 1, 6, 1, 0, 0, 0, 0, 8), +/* This is external wavetable */ +MIX_ENT2(SOUND_MIXER_LINE1, 22, 0, 4, 4, 23, 1, 1, 23, 0, 4, + 22, 0, 0, 4, 23, 1, 0, 23, 0, 5), +}; + static int default_mixer_levels[32] = { 0x3232, /* Master Volume */ diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index 605a03ba5..ac2b6d40a 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -60,7 +60,10 @@ static int set_format(int dev, int fmt) else return audio_devs[dev]->local_format; - return audio_devs[dev]->local_format; + if (audio_devs[dev]->local_conversion) + return audio_devs[dev]->local_conversion; + else + return audio_devs[dev]->local_format; } int audio_open(int dev, struct file *file) @@ -387,7 +390,7 @@ int audio_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) return 0; case SNDCTL_DSP_GETFMTS: - val = audio_devs[dev]->format_mask; + val = audio_devs[dev]->format_mask | AFMT_MU_LAW; break; case SNDCTL_DSP_SETFMT: diff --git a/drivers/sound/awacs_defs.h b/drivers/sound/awacs_defs.h index c84e24ff0..e30bb608c 100644 --- a/drivers/sound/awacs_defs.h +++ b/drivers/sound/awacs_defs.h @@ -157,4 +157,68 @@ struct awacs_regs { #define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */ + +/* Burgundy values */ + +#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12) +#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12) + +#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12) +#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12) +#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12) +#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12) + +#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12) +#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12) +#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12) +#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12) + +#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12) +#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12) + +#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12) + +#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12) + +#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12) +#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12) +#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12) + +#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1) +#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2) +#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3) +#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4) + +#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1) +#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2) +#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3) +#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4) + + +/* These are all default values for the burgundy */ +#define DEF_BURGUNDY_INPSEL21 (0xAA) +#define DEF_BURGUNDY_INPSEL3 (0x0A) + +#define DEF_BURGUNDY_GAINCD (0x33) +#define DEF_BURGUNDY_GAINLINE (0x44) +#define DEF_BURGUNDY_GAINMIC (0x44) +#define DEF_BURGUNDY_GAINMODEM (0x06) + +/* Remember: lowest volume here is 0x9b */ +#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC) +#define DEF_BURGUNDY_VOLLINE (0x00000000) +#define DEF_BURGUNDY_VOLMIC (0x00000000) +#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC) + +#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f) +#define DEF_BURGUNDY_OUTPUTENABLES (0x0A) + +#define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) + +#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E) + +#define DEF_BURGUNDY_ATTENSPEAKER (0x44) +#define DEF_BURGUNDY_ATTENLINEOUT (0xCC) +#define DEF_BURGUNDY_ATTENHP (0xCC) + #endif /* _AWACS_DEFS_H_ */ diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 9a6b4c72f..dd12a0c68 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -437,6 +437,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, memset((char *) op, 0, sizeof(struct audio_operations)); init_waitqueue(&op->in_sleeper); init_waitqueue(&op->out_sleeper); + init_waitqueue(&op->poll_sleeper); if (driver_size < sizeof(struct audio_driver)) memset((char *) d, 0, sizeof(struct audio_driver)); diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index 019b915c5..cf6475662 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -236,6 +236,7 @@ struct audio_operations /* fields formerly in dmabuf.c */ struct wait_queue *in_sleeper; struct wait_queue *out_sleeper; + struct wait_queue *poll_sleeper; /* fields formerly in audio.c */ int audio_mode; diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index ccde8519a..85bde7d48 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -935,6 +935,7 @@ static void finish_output_interrupt(int dev, struct dma_buffparms *dmap) if (dmap->audio_callback != NULL) dmap->audio_callback(dev, dmap->callback_parm); wake_up(&adev->out_sleeper); + wake_up(&adev->poll_sleeper); } static void do_outputintr(int dev, int dummy) @@ -1103,7 +1104,10 @@ static void do_inputintr(int dev) } dmap->flags |= DMA_ACTIVE; if (dmap->qlen > 0) + { wake_up(&adev->in_sleeper); + wake_up(&adev->poll_sleeper); + } } void DMAbuf_inputintr(int dev) @@ -1217,7 +1221,6 @@ static unsigned int poll_input(struct file * file, int dev, poll_table *wait) if (!(adev->open_mode & OPEN_READ)) return 0; if (dmap->mapping_flags & DMA_MAP_MAPPED) { - poll_wait(file, &adev->in_sleeper, wait); if (dmap->qlen) return POLLIN | POLLRDNORM; return 0; @@ -1228,7 +1231,6 @@ static unsigned int poll_input(struct file * file, int dev, poll_table *wait) !dmap->qlen && adev->go) { unsigned long flags; - poll_wait(file, &adev->in_sleeper, wait); save_flags(flags); cli(); DMAbuf_activate_recording(dev, dmap); @@ -1236,7 +1238,6 @@ static unsigned int poll_input(struct file * file, int dev, poll_table *wait) } return 0; } - poll_wait(file, &adev->in_sleeper, wait); if (!dmap->qlen) return 0; return POLLIN | POLLRDNORM; @@ -1250,14 +1251,12 @@ static unsigned int poll_output(struct file * file, int dev, poll_table *wait) if (!(adev->open_mode & OPEN_WRITE)) return 0; if (dmap->mapping_flags & DMA_MAP_MAPPED) { - poll_wait(file, &adev->out_sleeper, wait); if (dmap->qlen) return POLLOUT | POLLWRNORM; return 0; } if (dmap->dma_mode == DMODE_INPUT) return 0; - poll_wait(file, &adev->out_sleeper, wait); if (dmap->dma_mode == DMODE_NONE) return POLLOUT | POLLWRNORM; if (!DMAbuf_space_in_queue(dev)) @@ -1267,6 +1266,8 @@ static unsigned int poll_output(struct file * file, int dev, poll_table *wait) unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait) { + struct audio_operations *adev = audio_devs[dev]; + poll_wait(file, &adev->poll_sleeper, wait); return poll_input(file, dev, wait) | poll_output(file, dev, wait); } diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index 43b419817..5f96b3a42 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -173,9 +173,11 @@ static volatile struct awacs_regs *awacs; static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; static int awacs_rate_index; static int awacs_subframe; -static int awacs_revision; static int awacs_spkr_vol; +static int awacs_revision; +#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ + /* * Space for the DBDMA command blocks. */ @@ -184,6 +186,7 @@ static volatile struct dbdma_cmd *awacs_tx_cmds; /* * Cached values of AWACS registers (we can't read them). + * Except on the burgundy. XXX */ int awacs_reg[5]; @@ -240,6 +243,14 @@ static short *beep_buf; static volatile struct dbdma_cmd *beep_dbdma_cmd; static void (*orig_mksound)(unsigned int, unsigned int); +/* Burgundy functions */ +static void awacs_burgundy_wcw(unsigned addr,unsigned newval); +static unsigned awacs_burgundy_rcw(unsigned addr); +static void awacs_burgundy_write_volume(unsigned address, int volume); +static int awacs_burgundy_read_volume(unsigned address); +static void awacs_burgundy_write_mvolume(unsigned address, int volume); +static int awacs_burgundy_read_mvolume(unsigned address); + #ifdef CONFIG_PMAC_PBOOK /* * Stuff for restoring after a sleep. @@ -3007,6 +3018,9 @@ static void PMacIrqCleanup(void) if (beep_buf) kfree(beep_buf); kd_mksound = orig_mksound; +#ifdef CONFIG_PMAC_PBOOK + notifier_chain_unregister(&sleep_notifier_list, &awacs_sleep_notifier); +#endif } #endif /* MODULE */ @@ -3040,8 +3054,9 @@ static void PMacInit(void) * If we have a sample rate which is within catchRadius percent * of the requested value, we don't have to expand the samples. * Otherwise choose the next higher rate. + * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz. */ - i = 8; + i = (awacs_revision >= AWACS_BURGUNDY)? 1: 8; do { tolerance = catchRadius * awacs_freqs[--i] / 100; } while (sound.soft.speed > awacs_freqs[i] + tolerance && i > 0); @@ -3053,7 +3068,9 @@ static void PMacInit(void) awacs_rate_index = i; PMacSilence(); - out_le32(&awacs->control, MASK_IEPC | MASK_IEE | (i << 8) | 0x11); + /* XXX disable error interrupt on burgundy for now */ + out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 + | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3); awacs_write(awacs_reg[1] | MASK_ADDR1); out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE); @@ -3213,8 +3230,9 @@ pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs) /* do something when headphone is plugged/unplugged? */ } if (ctrl & MASK_CNTLERR) { - printk(KERN_ERR "AWACS: error, status = %x\n", - in_le32(&awacs->codec_stat)); + int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16; + if (err != 0 && awacs_revision < AWACS_BURGUNDY) + printk(KERN_ERR "AWACS: error %x\n", err); } /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */ out_le32(&awacs->control, ctrl); @@ -3223,6 +3241,8 @@ pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs) static void awacs_write(int val) { + if (awacs_revision >= AWACS_BURGUNDY) + return; while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) ; /* XXX should have timeout */ out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22)); @@ -3247,7 +3267,8 @@ static struct timer_list beep_timer = { static void awacs_mksound(unsigned int hz, unsigned int ticks) { unsigned long flags; - int srate = awacs_freqs[BEEP_SPEED]; + int beep_speed = (awacs_revision < AWACS_BURGUNDY)? BEEP_SPEED: 0; + int srate = awacs_freqs[beep_speed]; int period, ncycles, nsamples; int i, j, f; short *p; @@ -3308,7 +3329,7 @@ static void awacs_mksound(unsigned int hz, unsigned int ticks) out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) - | (BEEP_SPEED << 8)); + | (beep_speed << 8)); out_le32(&awacs->byteswap, 0); out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); @@ -3330,8 +3351,9 @@ static int awacs_sleep_notify(struct notifier_block *this, PMacSilence(); break; case PBOOK_WAKE: - out_le32(&awacs->control, MASK_IEPC | MASK_IEE | - (awacs_rate_index << 8) | 0x11); + out_le32(&awacs->control, MASK_IEPC + | (awacs_rate_index << 8) | 0x11 + | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); awacs_write(awacs_reg[0] | MASK_ADDR0); awacs_write(awacs_reg[1] | MASK_ADDR1); awacs_write(awacs_reg[2] | MASK_ADDR2); @@ -3342,6 +3364,220 @@ static int awacs_sleep_notify(struct notifier_block *this, } #endif /* CONFIG_PMAC_PBOOK */ + +/* All the burgundy functions: */ + +/* Waits for busy flag to clear */ +inline static void +awacs_burgundy_busy_wait(void) +{ + while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) + ; +} + +inline static void +awacs_burgundy_extend_wait(void) +{ + while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) + ; + while (in_le32(&awacs->codec_stat) & MASK_EXTEND) + ; +} + +static void +awacs_burgundy_wcw(unsigned addr, unsigned val) +{ + out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff)); + awacs_burgundy_busy_wait(); + out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff)); + awacs_burgundy_busy_wait(); + out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff)); + awacs_burgundy_busy_wait(); + out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff)); + awacs_burgundy_busy_wait(); +} + +static unsigned +awacs_burgundy_rcw(unsigned addr) +{ + unsigned val = 0; + int flags; + + /* should have timeouts here */ + save_flags(flags); cli(); + + out_le32(&awacs->codec_ctrl, addr + 0x100000); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; + + out_le32(&awacs->codec_ctrl, addr + 0x100100); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8; + + out_le32(&awacs->codec_ctrl, addr + 0x100200); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16; + + out_le32(&awacs->codec_ctrl, addr + 0x100300); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24; + + restore_flags(flags); + + return val; +} + + +static void +awacs_burgundy_wcb(unsigned addr, unsigned val) +{ + out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff)); + awacs_burgundy_busy_wait(); +} + +static unsigned +awacs_burgundy_rcb(unsigned addr) +{ + unsigned val = 0; + int flags; + + /* should have timeouts here */ + save_flags(flags); cli(); + + out_le32(&awacs->codec_ctrl, addr + 0x100000); + awacs_burgundy_busy_wait(); + awacs_burgundy_extend_wait(); + val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; + + restore_flags(flags); + + return val; +} + +static int +awacs_burgundy_check(void) +{ + /* Checks to see the chip is alive and kicking */ + int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE; + + return error == 0xf0000; +} + +static int +awacs_burgundy_init(void) +{ + if (awacs_burgundy_check()) { + printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n"); + return 1; + } + + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES, + DEF_BURGUNDY_OUTPUTENABLES); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + DEF_BURGUNDY_MORE_OUTPUTENABLES); + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS, + DEF_BURGUNDY_OUTPUTSELECTS); + + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21, + DEF_BURGUNDY_INPSEL21); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3, + DEF_BURGUNDY_INPSEL3); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD, + DEF_BURGUNDY_GAINCD); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE, + DEF_BURGUNDY_GAINLINE); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC, + DEF_BURGUNDY_GAINMIC); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM, + DEF_BURGUNDY_GAINMODEM); + + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, + DEF_BURGUNDY_ATTENSPEAKER); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT, + DEF_BURGUNDY_ATTENLINEOUT); + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP, + DEF_BURGUNDY_ATTENHP); + + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME, + DEF_BURGUNDY_MASTER_VOLUME); + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD, + DEF_BURGUNDY_VOLCD); + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE, + DEF_BURGUNDY_VOLLINE); + awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC, + DEF_BURGUNDY_VOLMIC); + return 0; +} + +static void +awacs_burgundy_write_volume(unsigned address, int volume) +{ + int hardvolume,lvolume,rvolume; + + lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0; + rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0; + + hardvolume = lvolume + (rvolume << 16); + + awacs_burgundy_wcw(address, hardvolume); +} + +static int +awacs_burgundy_read_volume(unsigned address) +{ + int softvolume,wvolume; + + wvolume = awacs_burgundy_rcw(address); + + softvolume = (wvolume & 0xff) - 155; + softvolume += (((wvolume >> 16) & 0xff) - 155)<<8; + + return softvolume > 0 ? softvolume : 0; +} + + + + +static int +awacs_burgundy_read_mvolume(unsigned address) +{ + int lvolume,rvolume,wvolume; + + wvolume = awacs_burgundy_rcw(address); + + wvolume &= 0xffff; + + rvolume = (wvolume & 0xff) - 155; + lvolume = ((wvolume & 0xff00)>>8) - 155; + + return lvolume + (rvolume << 8); +} + + +static void +awacs_burgundy_write_mvolume(unsigned address, int volume) +{ + int lvolume,rvolume,hardvolume; + + lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0; + rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0; + + hardvolume = lvolume + (rvolume << 8); + hardvolume += (hardvolume << 16); + + awacs_burgundy_wcw(address, hardvolume); +} + +/* End burgundy functions */ + + + + + /* Turn on sound output, needed on G3 desktop powermacs */ static void awacs_enable_amp(int spkr_vol) @@ -3715,117 +3951,244 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, #ifdef CONFIG_PPC case DMASND_AWACS: - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_LINE | SOUND_MASK_MIC - | SOUND_MASK_CD | SOUND_MASK_RECLEV - | SOUND_MASK_ALTPCM; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_RECMASK: - data = SOUND_MASK_LINE | SOUND_MASK_MIC - | SOUND_MASK_CD; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_RECSRC: - data = 0; - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - if (awacs_reg[0] & MASK_MUX_CD) - data |= SOUND_MASK_CD; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data &= (SOUND_MASK_LINE - | SOUND_MASK_MIC | SOUND_MASK_CD); - awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC - | MASK_MUX_AUDIN); - if (data & SOUND_MASK_LINE) - awacs_reg[0] |= MASK_MUX_AUDIN; - if (data & SOUND_MASK_MIC) - awacs_reg[0] |= MASK_MUX_MIC; - if (data & SOUND_MASK_CD) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(awacs_reg[0] | MASK_ADDR0); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_RECLEV; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_CAPS: - return IOCTL_OUT(arg, 0); - case SOUND_MIXER_READ_VOLUME: - data = (awacs_reg[1] & MASK_AMUTE)? 0: - awacs_get_volume(awacs_reg[2], 6); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return IOCTL_OUT(arg, sound_set_volume(data)); - case SOUND_MIXER_READ_SPEAKER: - if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA) - data = awacs_spkr_vol; - else - data = (awacs_reg[1] & MASK_CMUTE)? 0: - awacs_get_volume(awacs_reg[4], 6); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_SPEAKER: - IOCTL_IN(arg, data); - if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA) - awacs_enable_amp(data); - else - data = awacs_volume_setter(data, 4, MASK_CMUTE, 6); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ - IOCTL_IN(arg, data); - beep_volume = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_ALTPCM: - return IOCTL_OUT(arg, beep_volume); - case SOUND_MIXER_WRITE_LINE: - IOCTL_IN(arg, data); - awacs_reg[0] &= ~MASK_MUX_AUDIN; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_AUDIN; - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ - case SOUND_MIXER_READ_LINE: - data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - data &= 0xff; - awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE); - if (data >= 25) { - awacs_reg[0] |= MASK_MUX_MIC; - if (data >= 75) - awacs_reg[0] |= MASK_GAINLINE; + if (awacs_revision<AWACS_BURGUNDY) { /* Different IOCTLS for burgundy*/ + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER + | SOUND_MASK_LINE | SOUND_MASK_MIC + | SOUND_MASK_CD | SOUND_MASK_RECLEV + | SOUND_MASK_ALTPCM; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECMASK: + data = SOUND_MASK_LINE | SOUND_MASK_MIC + | SOUND_MASK_CD; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECSRC: + data = 0; + if (awacs_reg[0] & MASK_MUX_AUDIN) + data |= SOUND_MASK_LINE; + if (awacs_reg[0] & MASK_MUX_MIC) + data |= SOUND_MASK_MIC; + if (awacs_reg[0] & MASK_MUX_CD) + data |= SOUND_MASK_CD; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_IN(arg, data); + data &= (SOUND_MASK_LINE + | SOUND_MASK_MIC | SOUND_MASK_CD); + awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC + | MASK_MUX_AUDIN); + if (data & SOUND_MASK_LINE) + awacs_reg[0] |= MASK_MUX_AUDIN; + if (data & SOUND_MASK_MIC) + awacs_reg[0] |= MASK_MUX_MIC; + if (data & SOUND_MASK_CD) + awacs_reg[0] |= MASK_MUX_CD; + awacs_write(awacs_reg[0] | MASK_ADDR0); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_STEREODEVS: + data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER + | SOUND_MASK_RECLEV; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_CAPS: + return IOCTL_OUT(arg, 0); + case SOUND_MIXER_READ_VOLUME: + data = (awacs_reg[1] & MASK_AMUTE)? 0: + awacs_get_volume(awacs_reg[2], 6); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return IOCTL_OUT(arg, sound_set_volume(data)); + case SOUND_MIXER_READ_SPEAKER: + if (awacs_revision == 3 && adb_hardware == ADB_VIACUDA) + data = awacs_spkr_vol; + else + data = (awacs_reg[1] & MASK_CMUTE)? 0: + awacs_get_volume(awacs_reg[4], 6); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_SPEAKER: + IOCTL_IN(arg, data); + if (awacs_revision == 3 && adb_hardware == ADB_VIACUDA) + awacs_enable_amp(data); + else + data = awacs_volume_setter(data, 4, MASK_CMUTE, 6); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ + IOCTL_IN(arg, data); + beep_volume = data & 0xff; + /* fall through */ + case SOUND_MIXER_READ_ALTPCM: + return IOCTL_OUT(arg, beep_volume); + case SOUND_MIXER_WRITE_LINE: + IOCTL_IN(arg, data); + awacs_reg[0] &= ~MASK_MUX_AUDIN; + if ((data & 0xff) >= 50) + awacs_reg[0] |= MASK_MUX_AUDIN; + awacs_write(MASK_ADDR0 | awacs_reg[0]); + /* fall through */ + case SOUND_MIXER_READ_LINE: + data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_MIC: + IOCTL_IN(arg, data); + data &= 0xff; + awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE); + if (data >= 25) { + awacs_reg[0] |= MASK_MUX_MIC; + if (data >= 75) + awacs_reg[0] |= MASK_GAINLINE; + } + awacs_write(MASK_ADDR0 | awacs_reg[0]); + /* fall through */ + case SOUND_MIXER_READ_MIC: + data = (awacs_reg[0] & MASK_MUX_MIC)? + (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_CD: + IOCTL_IN(arg, data); + awacs_reg[0] &= ~MASK_MUX_CD; + if ((data & 0xff) >= 50) + awacs_reg[0] |= MASK_MUX_CD; + awacs_write(MASK_ADDR0 | awacs_reg[0]); + /* fall through */ + case SOUND_MIXER_READ_CD: + data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_RECLEV: + IOCTL_IN(arg, data); + data = awacs_volume_setter(data, 0, 0, 4); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECLEV: + data = awacs_get_volume(awacs_reg[0], 4); + return IOCTL_OUT(arg, data); } - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ - case SOUND_MIXER_READ_MIC: - data = (awacs_reg[0] & MASK_MUX_MIC)? - (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_CD: - IOCTL_IN(arg, data); - awacs_reg[0] &= ~MASK_MUX_CD; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ - case SOUND_MIXER_READ_CD: - data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_RECLEV: - IOCTL_IN(arg, data); - data = awacs_volume_setter(data, 0, 0, 4); - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_RECLEV: - data = awacs_get_volume(awacs_reg[0], 4); - return IOCTL_OUT(arg, data); + break; + } else { + /* We are, we are, we are... Burgundy or better */ + switch(cmd) { + case SOUND_MIXER_READ_DEVMASK: + data = SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_LINE | SOUND_MASK_MIC | + SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECMASK: + data = SOUND_MASK_LINE | SOUND_MASK_MIC + | SOUND_MASK_CD; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECSRC: + data = 0; + if (awacs_reg[0] & MASK_MUX_AUDIN) + data |= SOUND_MASK_LINE; + if (awacs_reg[0] & MASK_MUX_MIC) + data |= SOUND_MASK_MIC; + if (awacs_reg[0] & MASK_MUX_CD) + data |= SOUND_MASK_CD; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_IN(arg, data); + data &= (SOUND_MASK_LINE + | SOUND_MASK_MIC | SOUND_MASK_CD); + awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC + | MASK_MUX_AUDIN); + if (data & SOUND_MASK_LINE) + awacs_reg[0] |= MASK_MUX_AUDIN; + if (data & SOUND_MASK_MIC) + awacs_reg[0] |= MASK_MUX_MIC; + if (data & SOUND_MASK_CD) + awacs_reg[0] |= MASK_MUX_CD; + awacs_write(awacs_reg[0] | MASK_ADDR0); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_STEREODEVS: + data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER + | SOUND_MASK_RECLEV | SOUND_MASK_CD + | SOUND_MASK_LINE; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_CAPS: + return IOCTL_OUT(arg, 0); + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data); + /* Fall through */ + case SOUND_MIXER_READ_VOLUME: + return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME)); + case SOUND_MIXER_WRITE_SPEAKER: + IOCTL_IN(arg, data); + + if (!(data & 0xff)) { + /* Mute the left speaker */ + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2); + } else { + /* Unmute the left speaker */ + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2); + } + if (!(data & 0xff00)) { + /* Mute the right speaker */ + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4); + } else { + /* Unmute the right speaker */ + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4); + } + + data = (((data&0xff)*16)/100 > 0xf ? 0xf : + (((data&0xff)*16)/100)) + + ((((data>>8)*16)/100 > 0xf ? 0xf : + ((((data>>8)*16)/100)))<<4); + + awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data); + /* Fall through */ + case SOUND_MIXER_READ_SPEAKER: + data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER); + data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8); + return IOCTL_OUT(arg, ~data); + case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ + IOCTL_IN(arg, data); + beep_volume = data & 0xff; + /* fall through */ + case SOUND_MIXER_READ_ALTPCM: + return IOCTL_OUT(arg, beep_volume); + case SOUND_MIXER_WRITE_LINE: + IOCTL_IN(arg, data); + awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data); + + /* fall through */ + case SOUND_MIXER_READ_LINE: + data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_MIC: + IOCTL_IN(arg, data); + /* Mic is mono device */ + data = (data << 8) + (data << 24); + awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data); + /* fall through */ + case SOUND_MIXER_READ_MIC: + data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC); + data <<= 24; + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_CD: + IOCTL_IN(arg, data); + awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data); + /* fall through */ + case SOUND_MIXER_READ_CD: + data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_WRITE_RECLEV: + IOCTL_IN(arg, data); + data = awacs_volume_setter(data, 0, 0, 4); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_READ_RECLEV: + data = awacs_get_volume(awacs_reg[0], 4); + return IOCTL_OUT(arg, data); + case SOUND_MIXER_OUTMASK: + break; + case SOUND_MIXER_OUTSRC: + break; + } + break; } - break; #endif } @@ -3946,9 +4309,7 @@ static void sq_setup(int numBufs, int bufSize, char **buffers) sq.front = sq.count = 0; sq.rear = -1; - sq.write_queue = sq.open_queue = sq.sync_queue = 0; sq.syncing = 0; - sq.playing = 0; #ifdef CONFIG_ATARI @@ -4129,21 +4490,21 @@ static int sq_fsync(struct file *filp, struct dentry *dentry) static int sq_release(struct inode *inode, struct file *file) { int rc = 0; - if (sq.busy) { + + if (sq.busy) rc = sq_fsync(file, file->f_dentry); - sq.busy = 0; - WAKE_UP(sq.open_queue); - /* Wake up a process waiting for the queue being released. - * Note: There may be several processes waiting for a call - * to open() returning. */ - } sound.soft = sound.dsp; sound.hard = sound.dsp; sound_silence(); - if (rc == 0) { - sq_release_buffers(); - MOD_DEC_USE_COUNT; - } + sq_release_buffers(); + MOD_DEC_USE_COUNT; + + sq.busy = 0; + WAKE_UP(sq.open_queue); + /* Wake up a process waiting for the queue being released. + * Note: There may be several processes waiting for a call + * to open() returning. */ + return rc; } @@ -4262,6 +4623,9 @@ static void __init sq_init(void) if (sq_unit < 0) return; + sq.write_queue = sq.open_queue = sq.sync_queue = 0; + sq.busy = 0; + /* whatever you like as startup mode for /dev/dsp, * (/dev/audio hasn't got a startup mode). note that * once changed a new open() will *not* restore these! @@ -4332,7 +4696,7 @@ static int state_open(struct inode *inode, struct file *file) #endif /* CONFIG_AMIGA */ #ifdef CONFIG_PPC case DMASND_AWACS: - mach = "PowerMac "; + sprintf(mach, "PowerMac (AWACS rev %d) ", awacs_revision); break; #endif /* CONFIG_PPC */ } @@ -4510,6 +4874,7 @@ void __init dmasound_init(void) #ifdef CONFIG_PPC awacs_subframe = 0; + awacs_revision = 0; np = find_devices("awacs"); if (np == 0) { /* @@ -4524,6 +4889,8 @@ void __init dmasound_init(void) sfprop = (int *) get_property(sound, "sub-frame", 0); if (sfprop != 0 && *sfprop >= 0 && *sfprop < 16) awacs_subframe = *sfprop; + if (device_is_compatible(sound, "burgundy")) + awacs_revision = AWACS_BURGUNDY; } } if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) { @@ -4542,7 +4909,7 @@ void __init dmasound_init(void) awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd), GFP_KERNEL); if (awacs_tx_cmd_space == NULL) { - printk("DMA sound driver: Not enough buffer memory, driver disabled!\n"); + printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); return; } awacs_tx_cmds = (volatile struct dbdma_cmd *) @@ -4560,17 +4927,22 @@ void __init dmasound_init(void) awacs_write(awacs_reg[4] + MASK_ADDR4); /* Initialize recent versions of the awacs */ - awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf; - if (awacs_revision >= 3) { - awacs_write(0x6000); - awacs_enable_amp(100 * 0x101); + if (awacs_revision == 0) { + awacs_revision = + (in_le32(&awacs->codec_stat) >> 12) & 0xf; + if (awacs_revision == 3) { + awacs_write(0x6000); + awacs_enable_amp(100 * 0x101); + } } + if (awacs_revision >= AWACS_BURGUNDY) + awacs_burgundy_init(); /* Initialize beep stuff */ beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1); orig_mksound = kd_mksound; kd_mksound = awacs_mksound; - beep_buf = (short *) kmalloc(BEEP_BUFLEN * 2, GFP_KERNEL); + beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); if (beep_buf == NULL) printk(KERN_WARNING "dmasound: no memory for " "beep buffer\n"); @@ -4596,15 +4968,15 @@ void __init dmasound_init(void) mixer_init(); if (!sound.mach.irqinit()) { - printk("DMA sound driver: Interrupt initialization failed\n"); + printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n"); return; } #ifdef MODULE irq_installed = 1; #endif - printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs, - bufSize); + printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", + numBufs, bufSize); return; } diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 37d1fc38f..1ce70dc7b 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -3,7 +3,7 @@ /* * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver. * - * Copyright (C) 1998 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -83,6 +83,15 @@ * 16.12.98 0.16 Don't wake up app until there are fragsize bytes to read/write * 06.01.99 0.17 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.18 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes <joma@telindus.be> + * 22.03.99 0.19 return EAGAIN instead of EBUSY when O_NONBLOCK + * read/write cannot be executed + * 07.04.99 0.20 implemented the following ioctl's: SOUND_PCM_READ_RATE, + * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; + * Alpha fixes reported by Peter Jones <pjones@redhat.com> + * Note: joystick address handling might still be wrong on archs + * other than i386 * * some important things missing in Ensoniq documentation: * @@ -127,6 +136,8 @@ /* --------------------------------------------------------------------- */ #undef OSS_DOCUMENTED_MIXER_SEMANTICS +#define DBG(x) {} +/*#define DBG(x) {x}*/ /* --------------------------------------------------------------------- */ @@ -281,7 +292,8 @@ struct es1370_state { int dev_midi; /* hardware resources */ - unsigned int io, irq; + unsigned long io; /* long for SPARC */ + unsigned int irq; /* mixer registers; there is no HW readback */ struct { @@ -1019,7 +1031,7 @@ static int drain_dac1(struct es1370_state *s, int nonblock) tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "es1370: dma timed out??\n"); + DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");) } remove_wait_queue(&s->dma_dac1.wait, &wait); current->state = TASK_RUNNING; @@ -1054,7 +1066,7 @@ static int drain_dac2(struct es1370_state *s, int nonblock) tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV); tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "es1370: dma timed out??\n"); + DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");) } remove_wait_queue(&s->dma_dac2.wait, &wait); current->state = TASK_RUNNING; @@ -1095,7 +1107,7 @@ static ssize_t es1370_read(struct file *file, char *buffer, size_t count, loff_t if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_adc.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1150,7 +1162,7 @@ static ssize_t es1370_write(struct file *file, const char *buffer, size_t count, if (cnt <= 0) { start_dac2(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_dac2.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1228,8 +1240,6 @@ static int es1370_mmap(struct file *file, struct vm_area_struct *vma) if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) return -EAGAIN; db->mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1455,7 +1465,7 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1468,7 +1478,7 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.total_bytes >> s->dma_dac2.fragshift; + cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -1522,11 +1532,19 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd s->dma_dac2.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? + 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? + 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -1597,6 +1615,7 @@ static int es1370_release(struct inode *inode, struct file *file) down(&s->open_sem); if (file->f_mode & FMODE_WRITE) { stop_dac2(s); + synchronize_irq(); dealloc_dmabuf(&s->dma_dac2); } if (file->f_mode & FMODE_READ) { @@ -1663,7 +1682,7 @@ static ssize_t es1370_write_dac(struct file *file, const char *buffer, size_t co if (cnt <= 0) { start_dac1(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_dac1.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1725,8 +1744,6 @@ static int es1370_mmap_dac(struct file *file, struct vm_area_struct *vma) if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot)) return -EAGAIN; s->dma_dac1.mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1867,7 +1884,7 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.total_bytes >> s->dma_dac1.fragshift; + cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -1900,11 +1917,17 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int s->dma_dac1.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -2022,7 +2045,7 @@ static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, l cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.iwait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2069,7 +2092,7 @@ static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t c cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.owait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2192,7 +2215,7 @@ static int es1370_midi_release(struct inode *inode, struct file *file) } tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "es1370: midi timed out??\n"); + DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");) } remove_wait_queue(&s->midi.owait, &wait); current->state = TASK_RUNNING; @@ -2272,7 +2295,7 @@ __initfunc(int init_es1370(void)) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.17 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.20 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2296,7 +2319,7 @@ __initfunc(int init_es1370(void)) s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; s->irq = pcidev->irq; if (check_region(s->io, ES1370_EXTENT)) { - printk(KERN_ERR "es1370: io ports %#x-%#x in use\n", s->io, s->io+ES1370_EXTENT-1); + printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); goto err_region; } request_region(s->io, ES1370_EXTENT, "es1370"); @@ -2317,7 +2340,7 @@ __initfunc(int init_es1370(void)) if (micz[index]) s->ctrl |= CTRL_XCTL1; s->sctrl = 0; - printk(KERN_INFO "es1370: found adapter at io %#06x irq %u\n" + printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n" KERN_INFO "es1370: features: joystick %s, line %s, mic impedance %s\n", s->io, s->irq, (s->ctrl & CTRL_JYSTK_EN) ? "on" : "off", (s->ctrl & CTRL_XCTL0) ? "out" : "in", diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index e52f47d14..fa2efd25f 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -54,6 +54,17 @@ * Don't wake up app until there are fragsize bytes to read/write * 06.01.99 0.8 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.9 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes <joma@telindus.be> + * 22.03.99 0.10 return EAGAIN instead of EBUSY when O_NONBLOCK + * read/write cannot be executed + * 07.04.99 0.11 implemented the following ioctl's: SOUND_PCM_READ_RATE, + * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; + * Alpha fixes reported by Peter Jones <pjones@redhat.com> + * Another Alpha fix (wait_src_ready in init routine) + * reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru> + * Note: joystick address handling might still be wrong on archs + * other than i386 * */ @@ -330,7 +341,8 @@ struct es1371_state { int dev_midi; /* hardware resources */ - unsigned int io, irq; + unsigned long io; /* long for SPARC */ + unsigned int irq; /* mixer registers; there is no HW readback */ struct { @@ -1542,7 +1554,7 @@ static ssize_t es1371_read(struct file *file, char *buffer, size_t count, loff_t if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_adc.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1597,7 +1609,7 @@ static ssize_t es1371_write(struct file *file, const char *buffer, size_t count, if (cnt <= 0) { start_dac2(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_dac2.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1675,8 +1687,6 @@ static int es1371_mmap(struct file *file, struct vm_area_struct *vma) if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) return -EAGAIN; db->mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1899,7 +1909,7 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1912,7 +1922,7 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac2.total_bytes; - cinfo.blocks = s->dma_dac2.total_bytes >> s->dma_dac2.fragshift; + cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift; cinfo.ptr = s->dma_dac2.hwptr; if (s->dma_dac2.mapped) s->dma_dac2.count &= s->dma_dac2.fragsize-1; @@ -1966,11 +1976,17 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd s->dma_dac2.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -2110,7 +2126,7 @@ static ssize_t es1371_write_dac(struct file *file, const char *buffer, size_t co if (cnt <= 0) { start_dac1(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_dac1.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2172,8 +2188,6 @@ static int es1371_mmap_dac(struct file *file, struct vm_area_struct *vma) if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot)) return -EAGAIN; s->dma_dac1.mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -2305,7 +2319,7 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); cinfo.bytes = s->dma_dac1.total_bytes; - cinfo.blocks = s->dma_dac1.total_bytes >> s->dma_dac1.fragshift; + cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift; cinfo.ptr = s->dma_dac1.hwptr; if (s->dma_dac1.mapped) s->dma_dac1.count &= s->dma_dac1.fragsize-1; @@ -2338,11 +2352,17 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int s->dma_dac1.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user(s->dac1rate, (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -2459,7 +2479,7 @@ static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, l cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.iwait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2506,7 +2526,7 @@ static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t c cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.owait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2712,7 +2732,7 @@ __initfunc(int init_es1371(void)) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.8 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.11 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2736,7 +2756,7 @@ __initfunc(int init_es1371(void)) s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; s->irq = pcidev->irq; if (check_region(s->io, ES1371_EXTENT)) { - printk(KERN_ERR "es1371: io ports %#x-%#x in use\n", s->io, s->io+ES1371_EXTENT-1); + printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); goto err_region; } request_region(s->io, ES1371_EXTENT, "es1371"); @@ -2744,7 +2764,7 @@ __initfunc(int init_es1371(void)) printk(KERN_ERR "es1371: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_INFO "es1371: found adapter at io %#06x irq %u\n" + printk(KERN_INFO "es1371: found adapter at io %#lx irq %u\n" KERN_INFO "es1371: features: joystick 0x%x\n", s->io, s->irq, joystick[index]); /* register devices */ if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) @@ -2796,6 +2816,7 @@ __initfunc(int init_es1371(void)) * be stuck high, and I've found no way to rectify this other than * power cycle) */ + wait_src_ready(s); outl(0, s->io+ES1371_REG_SRCONV); /* codec init */ wrcodec(s, 0x00, 0); /* reset codec */ diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index a00ffb63a..f1ab09179 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -44,8 +44,6 @@ static int db16 = 0; /* Has a Gus16 AD1848 on it */ void attach_gus_card(struct address_info *hw_config) { - if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) - printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); gus_wave_init(hw_config); @@ -60,6 +58,9 @@ void attach_gus_card(struct address_info *hw_config) #ifdef CONFIG_MIDI gus_midi_init(hw_config); #endif + if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) + printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); + } int probe_gus(struct address_info *hw_config) diff --git a/drivers/sound/lowlevel/awe_compat.h b/drivers/sound/lowlevel/awe_compat.h index 0ad4fb062..9f9c57039 100644 --- a/drivers/sound/lowlevel/awe_compat.h +++ b/drivers/sound/lowlevel/awe_compat.h @@ -54,7 +54,7 @@ #include "../soundvers.h" #endif -#if SOUND_INTERNAL_VERSION >= 0x30803 +#if defined(SOUND_INTERNAL_VERSION) && SOUND_INTERNAL_VERSION >= 0x30803 /* OSS/Free-3.8 */ #define AWE_NO_PATCHMGR #define AWE_OSS38 @@ -151,18 +151,9 @@ static int _mem_start; /* memory pointer for permanent buffers */ #define my_malloc_memptr() _mem_start #define my_free(ptr) /* do nothing */ -static void *my_malloc(int size) -{ - char *ptr; - PERMANENT_MALLOC(ptr, char*, size, _mem_start); - return (void*)ptr; -} -#define my_kmalloc(size) my_malloc(size) -#define kfree(ptr) /* do nothing */ - /* allocate buffer only once */ #define INIT_TABLE(buffer,index,nums,type) {\ -buffer = my_malloc(sizeof(type) * (nums)); index = (nums);\ +PERMANENT_MALLOC(buffer, char*, size, _mem_start); index = (nums);\ } #else @@ -173,8 +164,6 @@ buffer = my_malloc(sizeof(type) * (nums)); index = (nums);\ #define my_malloc_memptr() 0 #define my_malloc(size) vmalloc(size) #define my_free(ptr) if (ptr) {vfree(ptr);} -#define my_kmalloc(size) kmalloc(size,GFP_KERNEL) -#define my_kfree(ptr) kfree(ptr) /* do not allocate buffer at beginning */ #define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} @@ -255,6 +244,14 @@ buffer = my_malloc(sizeof(type) * (nums)); index = (nums);\ #endif /* AWE_MODULE_SUPPORT */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +inline static void interruptible_sleep_on_timeout(struct wait_queue **q, unsigned long timeout) +{ + current->timeout = jiffies + timeout; + interruptible_sleep_on(q); +} +#endif + #endif /* CONFIG_AWE32_SYNTH */ #endif /* AWE_COMPAT_H_DEF */ diff --git a/drivers/sound/lowlevel/awe_wave.c b/drivers/sound/lowlevel/awe_wave.c index 1c2472049..8fd5431e6 100644 --- a/drivers/sound/lowlevel/awe_wave.c +++ b/drivers/sound/lowlevel/awe_wave.c @@ -2,9 +2,9 @@ * sound/awe_wave.c * * The low level driver for the AWE32/SB32/AWE64 wave table synth. - * version 0.4.3; Nov. 1, 1998 + * version 0.4.3; Feb. 1, 1999 * - * Copyright (C) 1996-1998 Takashi Iwai + * Copyright (C) 1996-1999 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -204,16 +204,20 @@ static awe_chan_info channels[AWE_MAX_CHANNELS]; #if defined(AWE_MODULE_SUPPORT) && defined(MODULE) /* replace awe_port variable with exported variable */ #define awe_port io -#define BASEVAR_DECL /**/ +#define awe_mem_size memsize +int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */ +int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */ +#ifdef MODULE_PARM +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "base i/o port of Emu8000"); +MODULE_PARM(memsize, "i"); +MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes"); +#endif #else -#define BASEVAR_DECL static +static int awe_port = AWE_DEFAULT_BASE_ADDR; +static int awe_mem_size = AWE_DEFAULT_MEM_SIZE; #endif /* module */ -/* awe32 base address (overwritten at initialization) */ -BASEVAR_DECL int awe_port = AWE_DEFAULT_BASE_ADDR; -/* memory byte size */ -BASEVAR_DECL int memsize = AWE_DEFAULT_MEM_SIZE; /* for module option */ -static int awe_mem_size = -1; /* DRAM start offset */ static int awe_mem_start = AWE_DRAM_OFFSET; @@ -669,7 +673,7 @@ static void _unload_awe(void) #include <linux/pnp.h> -BASEVAR_DECL int pnp = 1; /* use PnP as default */ +static int pnp = 1; /* use PnP as default */ #define AWE_NUM_CHIPS 3 static unsigned int pnp_ids[AWE_NUM_CHIPS] = { @@ -812,6 +816,7 @@ void cleanup_module(void) } #ifdef MODULE_PARM +EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>"); MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver"); MODULE_SUPPORTED_DEVICE("sound"); @@ -975,23 +980,9 @@ awe_wait(unsigned short delay) #else static struct wait_queue *awe_sleeper = NULL; -static void awe_wakeup(unsigned long dummy) -{ - wake_up(&awe_sleeper); -} - -static struct timer_list awe_timer = -{NULL, NULL, 0, 0, awe_wakeup}; - static void awe_wait(unsigned short delay) { - unsigned long flags; - awe_timer.expires = jiffies + (HZ * (unsigned long)delay + 44099) / 44100; - add_timer(&awe_timer); - save_flags (flags); - cli(); - sleep_on(&awe_sleeper); - restore_flags(flags); + interruptible_sleep_on_timeout(&awe_sleeper, (HZ * (unsigned long)delay + 44099) / 44100); } #endif /* wait by loop */ @@ -1553,7 +1544,7 @@ awe_note_on(int voice) vp->parm.moddcysus)); if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) { - awe_poke(AWE_ENVVAL(voice), 0xBFFF); + awe_poke(AWE_ENVVOL(voice), 0xBFFF); vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4); } else { awe_poke(AWE_ENVVOL(voice), @@ -3268,7 +3259,7 @@ static int info_duplicated(awe_voice_list *rec) sf_list *sf; /* search for all sharing lists */ - for (sf_id = rec->v.sf_id; sf_id > 0; sf_id = sf->shared) { + for (sf_id = rec->v.sf_id; sf_id > 0 && sf_id <= current_sf_id; sf_id = sf->shared) { sf = &sflists[sf_id - 1]; for (j = sf->infos; j >= 0; j = infos[j].next) { awe_voice_list *p = &infos[j]; @@ -4201,7 +4192,7 @@ static int is_identical_id(int id1, int id2) if (id1 < id2) { /* make sure id1 > id2 */ int tmp; tmp = id1; id1 = id2; id2 = tmp; } - for (i = sflists[id1-1].shared; i > 0; i = sflists[i-1].shared) { + for (i = sflists[id1-1].shared; i > 0 && i <= current_sf_id; i = sflists[i-1].shared) { if (i == id2) return TRUE; } @@ -4223,10 +4214,10 @@ static int search_sample_index(int sf, int sample, int level) return i; } #ifdef AWE_ALLOW_SAMPLE_SHARING - if (sflists[sf-1].shared) { /* search recursively */ + if ((i = sflists[sf-1].shared) > 0 && i <= current_sf_id) { /* search recursively */ if (level > current_sf_id) return -1; /* strange sharing loop.. quit */ - return search_sample_index(sflists[sf-1].shared, sample, level + 1); + return search_sample_index(i, sample, level + 1); } #endif return -1; @@ -4272,10 +4263,12 @@ awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist) note <= infos[rec].v.high && velocity >= infos[rec].v.vellow && velocity <= infos[rec].v.velhigh) { - vlist[nvoices] = &infos[rec].v; - if (infos[rec].type == V_ST_MAPPED) /* mapper */ + if (infos[rec].type == V_ST_MAPPED) { + /* mapper */ + vlist[0] = &infos[rec].v; return -1; - nvoices++; + } + vlist[nvoices++] = &infos[rec].v; if (nvoices >= AWE_MAX_VOICES) break; } @@ -5009,8 +5002,6 @@ awe_detect(void) DEBUG(0,printk("AWE32 not found\n")); return 0; } - if (memsize >= 0) /* given by config file or module option */ - awe_mem_size = memsize * 1024; /* convert to Kbytes */ return 1; } @@ -5028,9 +5019,14 @@ awe_detect(void) static void awe_check_dram(void) { - if (awe_mem_size >= 0) /* already initialized */ + if (awe_present) /* already initialized */ return; + if (awe_mem_size >= 0) { /* given by config file or module option */ + awe_mem_size *= 1024; /* convert to Kbytes */ + return; + } + awe_open_dram_for_check(); awe_mem_size = 0; diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index 41533aeda..649c9861f 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -800,7 +800,7 @@ int probe_mad16_mpu(struct address_info *hw_config) mad_write(MC3_PORT, tmp | 0x04); hw_config->driver_use_1 = SB_MIDI_ONLY; - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); #else return 0; #endif diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c index 8848f410e..03d7d284f 100644 --- a/drivers/sound/midi_synth.c +++ b/drivers/sound/midi_synth.c @@ -12,6 +12,7 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Andrew Veliath : fixed running status in MIDI input state machine */ #include <linux/config.h> @@ -83,7 +84,7 @@ do_midi_msg(int synthno, unsigned char *msg, int mlen) case 0xE0: STORE(SEQ_BENDER(synthno, msg[0] & 0x0f, - (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); + (msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7))); break; default: @@ -196,13 +197,19 @@ midi_synth_input(int orig_dev, unsigned char data) inc->m_left = len_tab[(data >> 4) - 8]; inc->m_buf[0] = inc->m_prev_status = data; } - } else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ - { /* Data byte (use running status) */ - inc->m_state = MST_DATA; + } else if (inc->m_prev_status & 0x80) { + /* Data byte (use running status) */ inc->m_ptr = 2; - inc->m_left = len_tab[(data >> 4) - 8] - 1; - inc->m_buf[0] = inc->m_prev_status; inc->m_buf[1] = data; + inc->m_buf[0] = inc->m_prev_status; + inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1; + if (inc->m_left > 0) + inc->m_state = MST_DATA; /* Not done yet */ + else { + inc->m_state = MST_INIT; + do_midi_msg(dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + } } break; /* MST_INIT */ diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index 72ede3fab..2cb785565 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -47,17 +47,14 @@ #define MDL_AZTECH 13 /* Aztech Sound Galaxy family */ #define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */ #define MDL_AEDSP 15 /* Audio Excel DSP 16 */ +#define MDL_ESSPCI 16 /* ESS PCI card */ +#define MDL_YMPCI 17 /* Yamaha PCI sb in emulation */ -#define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ -#define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ -#define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ -#define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ -#define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */ -#define SUBMDL_ES1888 0x14 /* Subtype ES1888 for specific handling */ #define SUBMDL_ALS007 42 /* ALS-007 differs from SB16 only in mixer */ /* register assignment */ #define SUBMDL_ALS100 43 /* ALS-100 allows sampling rates of up */ /* to 48kHz */ + /* * Config flags */ @@ -66,6 +63,7 @@ #define SB_NO_AUDIO 0x00000004 #define SB_NO_RECORDING 0x00000008 /* No audio recording */ #define SB_MIDI_ONLY (SB_NO_AUDIO|SB_NO_MIXER) +#define SB_PCI_IRQ 0x00000010 /* PCI shared IRQ */ struct mixer_def { unsigned int regno: 8; @@ -92,6 +90,8 @@ typedef struct sb_devc { int base; int irq; int dma8, dma16; + + int pcibase; /* For ESS Maestro etc */ /* State variables */ int opened; @@ -134,13 +134,24 @@ typedef struct sb_devc { void (*midi_input_intr) (int dev, unsigned char data); void *midi_irq_cookie; /* IRQ cookie for the midi */ } sb_devc; + +/* + * PCI card types + */ +#define SB_PCI_ESSMAESTRO 1 /* ESS Maestro Legacy */ +#define SB_PCI_YAMAHA 2 /* Yamaha Legacy */ + +/* + * Functions + */ + int sb_dsp_command (sb_devc *devc, unsigned char val); int sb_dsp_get_byte(sb_devc * devc); int sb_dsp_reset (sb_devc *devc); void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); unsigned int sb_getmixer (sb_devc *devc, unsigned int port); -int sb_dsp_detect (struct address_info *hw_config); +int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio); int sb_dsp_init (struct address_info *hw_config); void sb_dsp_unload(struct address_info *hw_config, int sbmpu); int sb_mixer_init(sb_devc *devc); diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index b85db519c..44b40e736 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -103,7 +103,7 @@ iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n", printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base); return 0; } - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); } void unload_sb(struct address_info *hw_config) @@ -113,7 +113,7 @@ void unload_sb(struct address_info *hw_config) } int sb_be_quiet=0; -int esstype = 0; /* ESS chip type */ +extern int esstype; /* ESS chip type */ #ifdef MODULE @@ -130,13 +130,14 @@ int mpu_io = 0; int io = -1; int irq = -1; int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int type = 0; /* Can set this to a specific card type */ -int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ -int trix = 0; /* Set trix=1 to load this as support for trix */ -int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* Can set this to a specific card type */ +int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ +int trix = 0; /* Set trix=1 to load this as support for trix */ +int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +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 */ +int acer = 0; /* Do acer notebook init */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -145,6 +146,7 @@ MODULE_PARM(dma16, "i"); MODULE_PARM(mpu_io, "i"); MODULE_PARM(type, "i"); MODULE_PARM(mad16, "i"); +MODULE_PARM(support, "i"); MODULE_PARM(trix, "i"); MODULE_PARM(pas2, "i"); MODULE_PARM(sm_games, "i"); @@ -156,7 +158,7 @@ int init_module(void) { printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (mad16 == 0 && trix == 0 && pas2 == 0) + if (mad16 == 0 && trix == 0 && pas2 == 0 && support == 0) { if (io == -1 || dma == -1 || irq == -1) { @@ -191,7 +193,7 @@ void cleanup_module(void) { if (smw_free) vfree(smw_free); - if (!mad16 && !trix && !pas2) + if (!mad16 && !trix && !pas2 && !support) unload_sb(&config); if (sbmpu) unload_sbmpu(&config_mpu); @@ -220,5 +222,8 @@ EXPORT_SYMBOL(attach_sb_card); EXPORT_SYMBOL(probe_sb); EXPORT_SYMBOL(unload_sb); EXPORT_SYMBOL(sb_be_quiet); +EXPORT_SYMBOL(attach_sbmpu); +EXPORT_SYMBOL(probe_sbmpu); +EXPORT_SYMBOL(unload_sbmpu); #endif diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 907250981..d162e470d 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -179,13 +179,25 @@ static void sb_intr (sb_devc *devc) status = inb(DSP_DATA_AVL16); } +static void pci_intr(sb_devc *devc) +{ + int src = inb(devc->pcibase+0x1A); + src&=3; + if(src) + sb_intr(devc); +} + static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) { - sb_devc *devc = dev_id; + sb_devc *devc = dev_id; devc->irq_ok = 1; switch (devc->model) { + case MDL_ESSPCI: + pci_intr (devc); + break; + case MDL_ESS: ess_intr (devc); break; @@ -249,7 +261,7 @@ static void dsp_get_vers(sb_devc * devc) } } } - DDB(printk("DSP version %d.%d\n", devc->major, devc->minor)); + DDB(printk("DSP version %d.%02d\n", devc->major, devc->minor)); restore_flags(flags); } @@ -478,7 +490,7 @@ static void relocate_ess1688(sb_devc * devc) #endif } -int sb_dsp_detect(struct address_info *hw_config) +int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio) { sb_devc sb_info; sb_devc *devc = &sb_info; @@ -508,7 +520,26 @@ int sb_dsp_detect(struct address_info *hw_config) devc->dma8 = hw_config->dma; devc->dma16 = -1; - + devc->pcibase = pciio; + + if(pci == SB_PCI_ESSMAESTRO) + { + devc->model = MDL_ESSPCI; + devc->caps |= SB_PCI_IRQ; + hw_config->driver_use_1 |= SB_PCI_IRQ; + hw_config->card_subtype = MDL_ESSPCI; + } + + if(pci == SB_PCI_YAMAHA) + { + devc->model = MDL_YMPCI; + devc->caps |= SB_PCI_IRQ; + hw_config->driver_use_1 |= SB_PCI_IRQ; + hw_config->card_subtype = MDL_YMPCI; + + printk("Yamaha PCI mode.\n"); + } + if (acer) { cli(); @@ -569,6 +600,16 @@ int sb_dsp_detect(struct address_info *hw_config) } } } + + if(devc->type == MDL_ESSPCI) + devc->model = MDL_ESSPCI; + + if(devc->type == MDL_YMPCI) + { + printk("YMPCI selected\n"); + devc->model = MDL_YMPCI; + } + /* * Save device information for sb_dsp_init() */ @@ -581,7 +622,7 @@ int sb_dsp_detect(struct address_info *hw_config) return 0; } memcpy((char *) detected_devc, (char *) devc, sizeof(sb_devc)); - MDB(printk(KERN_INFO "SB %d.%d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); + MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); return 1; } @@ -617,9 +658,17 @@ int sb_dsp_init(struct address_info *hw_config) devc->caps = hw_config->driver_use_1; - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && hw_config->irq > 0) + if (!((devc->caps & SB_NO_AUDIO) && (devc->caps & SB_NO_MIDI)) && hw_config->irq > 0) { /* IRQ setup */ - if (request_irq(hw_config->irq, sbintr, 0, "soundblaster", devc) < 0) + + /* + * ESS PCI cards do shared PCI IRQ stuff. Since they + * will get shared PCI irq lines we must cope. + */ + + int i=(devc->caps&SB_PCI_IRQ)?SA_SHIRQ:0; + + if (request_irq(hw_config->irq, sbintr, i, "soundblaster", devc) < 0) { printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); return 0; @@ -768,7 +817,7 @@ int sb_dsp_init(struct address_info *hw_config) if (hw_config->name == NULL) hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; - sprintf(name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); + sprintf(name, "%s (%d.%02d)", hw_config->name, devc->major, devc->minor); conf_printf(name, hw_config); /* @@ -789,7 +838,7 @@ int sb_dsp_init(struct address_info *hw_config) } else if (!sb_be_quiet && devc->model == MDL_SBPRO) { - printk(KERN_INFO "SB DSP version is just %d.%d which means that your card is\n", devc->major, devc->minor); + printk(KERN_INFO "SB DSP version is just %d.%02d which means that your card is\n", devc->major, devc->minor); printk(KERN_INFO "several years old (8 bit only device) or alternatively the sound driver\n"); printk(KERN_INFO "is incorrectly configured.\n"); } @@ -1194,6 +1243,10 @@ int probe_sbmpu(struct address_info *hw_config) return 0; break; + case MDL_YMPCI: + hw_config->name = "Yamaha PCI Legacy"; + printk("Yamaha PCI legacy UART401 check.\n"); + break; default: return 0; } diff --git a/drivers/sound/sb_ess.c b/drivers/sound/sb_ess.c index d1fdd4ccb..635be8a11 100644 --- a/drivers/sound/sb_ess.c +++ b/drivers/sound/sb_ess.c @@ -1,9 +1,46 @@ +#undef FKS_LOGGING +#undef FKS_TEST + /* - * Created: 9-Jan-1999 + * tabs should be 4 spaces, in vi(m): set tabstop=4 * * TODO: consistency speed calculations!! + * cleanup! * ????: Did I break MIDI support? * + * History: + * + * Rolf Fokkens (Dec 20 1998): ES188x recording level support on a per + * fokkensr@vertis.nl input basis. + * (Dec 24 1998): Recognition of ES1788, ES1887, ES1888, + * ES1868, ES1869 and ES1878. Could be used for + * specific handling in the future. All except + * ES1887 and ES1888 and ES688 are handled like + * ES1688. + * (Dec 27 1998): RECLEV for all (?) ES1688+ chips. ES188x now + * have the "Dec 20" support + RECLEV + * (Jan 2 1999): Preparation for Full Duplex. This means + * Audio 2 is now used for playback when dma16 + * is specified. The next step would be to use + * Audio 1 and Audio 2 at the same time. + * (Jan 9 1999): Put all ESS stuff into sb_ess.[ch], this + * includes both the ESS stuff that has been in + * sb_*[ch] before I touched it and the ESS support + * I added later + * (Jan 23 1999): Full Duplex seems to work. I wrote a small + * test proggy which works OK. Haven't found + * any applications to test it though. So why did + * I bother to create it anyway?? :) Just for + * fun. + * (May 2 1999): I tried to be too smart by "introducing" + * ess_calc_best_speed (). The idea was that two + * dividers could be used to setup a samplerate, + * ess_calc_best_speed () would choose the best. + * This works for playback, but results in + * recording problems for high samplerates. I + * fixed this by removing ess_calc_best_speed () + * and just doing what the documentation says. + * * This files contains ESS chip specifics. It's based on the existing ESS * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This * file adds features like: @@ -19,27 +56,13 @@ * * ESS detection isn't full proof (yet). If it fails an additional module * parameter esstype can be specified to be one of the following: - * 688, 1688, 1868, 1869, 1788, 1887, 1888 - * - * History: - * - * Rolf Fokkens (Dec 20 1998): ES188x recording level support on a per - * input basis. - * (Dec 24 1998): Recognition of ES1788, ES1887, ES1888, - * ES1868, ES1869 and ES1878. Could be used for - * specific handling in the future. All except - * ES1887 and ES1888 and ES688 are handled like - * ES1688. - * (Dec 27 1998): RECLEV for all (?) ES1688+ chips. ES188x now - * have the "Dec 20" support + RECLEV - * (jan 2 1999): Preparation for Full Duplex. This means - * Audio 2 is now used for playback when dma16 - * is specified. The next step would be to use - * Audio 1 and Audio 2 at the same time. + * -1, 0, 688, 1688, 1868, 1869, 1788, 1887, 1888 + * -1 means: mimic 2.0 behaviour, + * 0 means: auto detect. + * others: explicitly specify chip + * -1 is default, cause auto detect still doesn't work. */ -#undef FKS_LOGGING - /* * About the documentation * @@ -156,13 +179,25 @@ * ES1946 yes This is a PCI chip; not handled by this driver */ +#include <linux/delay.h> + #include "sound_config.h" #include "sb_mixer.h" #include "sb.h" #include "sb_ess.h" -extern int esstype; /* module parameter in sb_card.c */ +#define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */ +#define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */ + +int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */ + +#define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ +#define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ +#define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ +#define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ +#define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */ +#define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */ #ifdef FKS_LOGGING static void ess_show_mixerregs (sb_devc *devc); @@ -288,6 +323,7 @@ static int ess_calc_div (int clock, int revert, int *speedp, int *diffp) return retval; } +#ifdef OBSOLETE static int ess_calc_best_speed (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp) { @@ -311,6 +347,7 @@ static int ess_calc_best_speed return retval; } +#endif /* * Depending on the audiochannel ESS devices can @@ -322,7 +359,7 @@ static int ess_calc_best_speed */ static void ess_common_speed (sb_devc *devc, int *speedp, int *divp) { - int diff = 0, div, choice; + int diff = 0, div; if (devc->duplex) { /* @@ -330,8 +367,11 @@ static void ess_common_speed (sb_devc *devc, int *speedp, int *divp) */ div = 0x80 | ess_calc_div (795500, 128, speedp, &diff); } else { - choice = ess_calc_best_speed (397700, 128, 795500, 256, &div, speedp); - if (choice == 2) div |= 0x80; + if (*speedp > 22000) { + div = 0x80 | ess_calc_div (795500, 256, speedp, &diff); + } else { + div = 0x00 | ess_calc_div (397700, 128, speedp, &diff); + } } *divp = div; } @@ -370,45 +410,6 @@ printk (KERN_INFO "FKS: ess_speed (%d) b speed = %d, div=%x\n", audionum, devc-> } } -#if 0 -static void ess_speed(sb_devc * devc) -{ - int divider; - unsigned char bits = 0; - int speed = devc->speed; - - if (speed < 4000) - speed = 4000; - else if (speed > 48000) - speed = 48000; - - if (speed > 22000) - { - bits = 0x80; - divider = 256 - (795500 + speed / 2) / speed; - } - else - { - divider = 128 - (397700 + speed / 2) / speed; - } - - bits |= (unsigned char) divider; - - ess_write (devc, 0xa1, bits); - - /* - * Set filter divider register - */ - - speed = (speed * 9) / 20; /* Set filter roll-off to 90% of speed/2 */ - divider = 256 - 7160000 / (speed * 82); - - ess_write (devc, 0xa2, divider); - - return; -} -#endif - static int ess_audio_prepare_for_input(int dev, int bsize, int bcount) { sb_devc *devc = audio_devs[dev]->devc; @@ -931,6 +932,29 @@ static int ess_set_irq_hw (sb_devc * devc) return ess_common_set_irq_hw (devc); } +#ifdef FKS_TEST + +/* + * FKS_test: + * for ES1887: 00, 18, non wr bits: 0001 1000 + * for ES1868: 00, b8, non wr bits: 1011 1000 + * for ES1888: 00, f8, non wr bits: 1111 1000 + * for ES1688: 00, f8, non wr bits: 1111 1000 + * + ES968 + */ + +static void FKS_test (sb_devc * devc) +{ + int val1, val2; + val1 = ess_getmixer (devc, 0x64); + ess_setmixer (devc, 0x64, ~val1); + val2 = ess_getmixer (devc, 0x64) ^ ~val1; + ess_setmixer (devc, 0x64, val1); + val1 ^= ess_getmixer (devc, 0x64); +printk (KERN_INFO "FKS: FKS_test %02x, %02x\n", (val1 & 0x0ff), (val2 & 0x0ff)); +}; +#endif + static unsigned int ess_identify (sb_devc * devc) { unsigned int val; @@ -1025,42 +1049,55 @@ int ess_init(sb_devc * devc, struct address_info *hw_config) if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) { char *chip = NULL; + int submodel = -1; - if (esstype) { - int submodel = -1; - - switch (esstype) { - case 688: - submodel = 0x00; - break; - case 1688: - submodel = 0x08; - break; - case 1868: - submodel = SUBMDL_ES1868; - break; - case 1869: - submodel = SUBMDL_ES1869; - break; - case 1788: - submodel = SUBMDL_ES1788; - break; - case 1887: - submodel = SUBMDL_ES1887; - break; - case 1888: - submodel = SUBMDL_ES1888; - break; - }; - if (submodel != -1) { - devc->submodel = submodel; - sprintf (modelname, "ES%d", esstype); - chip = modelname; - }; + switch (esstype) { + case ESSTYPE_DETECT: + case ESSTYPE_LIKE20: + break; + case 688: + submodel = 0x00; + break; + case 1688: + submodel = 0x08; + break; + case 1868: + submodel = SUBMDL_ES1868; + break; + case 1869: + submodel = SUBMDL_ES1869; + break; + case 1788: + submodel = SUBMDL_ES1788; + break; + case 1887: + submodel = SUBMDL_ES1887; + break; + case 1888: + submodel = SUBMDL_ES1888; + break; + default: + printk (KERN_ERR "Invalid esstype=%d specified\n", esstype); + return 0; + }; + if (submodel != -1) { + devc->submodel = submodel; + sprintf (modelname, "ES%d", esstype); + chip = modelname; }; if (chip == NULL && (ess_minor & 0x0f) < 8) { chip = "ES688"; }; +#ifdef FKS_TEST +FKS_test (devc); +#endif + /* + * If Nothing detected yet, and we want 2.0 behaviour... + * Then let's assume it's ES1688. + */ + if (chip == NULL && esstype == ESSTYPE_LIKE20) { + chip = "ES1688"; + }; if (chip == NULL) { int type; @@ -1080,6 +1117,10 @@ int ess_init(sb_devc * devc, struct address_info *hw_config) chip = "ES1878"; devc->submodel = SUBMDL_ES1878; break; + default: + if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) { + printk ("ess_init: Unrecognized %04x\n", type); + } }; }; #if 0 @@ -1117,6 +1158,18 @@ int ess_init(sb_devc * devc, struct address_info *hw_config) chip = "ES1688"; }; + printk ( KERN_INFO "ESS chip %s %s%s\n" + , chip + , ( esstype == ESSTYPE_DETECT || esstype == ESSTYPE_LIKE20 + ? "detected" + : "specified" + ) + , ( esstype == ESSTYPE_LIKE20 + ? " (kernel 2.0 compatible)" + : "" + ) + ); + sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f); } else { strcpy(name, "Jazz16"); diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index 97ce1b39d..06af0f434 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -673,6 +673,8 @@ int sb_mixer_init(sb_devc * devc) switch (devc->model) { + case MDL_ESSPCI: + case MDL_YMPCI: case MDL_SBPRO: case MDL_AZTECH: case MDL_JAZZ: diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 44207cb62..af40a2117 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -1105,7 +1105,7 @@ int sequencer_open(int dev, struct file *file) */ for (i = 0; i < max_mididev; i++) - if (!midi_opened[i]) + if (!midi_opened[i] && midi_devs[i]) { if ((retval = midi_devs[i]->open(i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) @@ -1411,7 +1411,7 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) case SNDCTL_SEQ_TESTMIDI: if (__get_user(midi_dev, (int *)arg)) return -EFAULT; - if (midi_dev < 0 || midi_dev >= max_mididev) + if (midi_dev < 0 || midi_dev >= max_mididev || !midi_devs[midi_dev]) return -ENXIO; if (!midi_opened[midi_dev] && @@ -1529,7 +1529,7 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) case SNDCTL_MIDI_INFO: if (get_user(dev, (int *)(&(((struct midi_info *)arg)->device)))) return -EFAULT; - if (dev < 0 || dev >= max_mididev) + if (dev < 0 || dev >= max_mididev || !midi_devs[dev]) return -ENXIO; midi_devs[dev]->info.device = dev; return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0; diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index b1899e143..c6d30d43f 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -3,7 +3,7 @@ /* * sonicvibes.c -- S3 Sonic Vibes audio driver. * - * Copyright (C) 1998 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,6 +51,23 @@ * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs * 06.01.99 0.10 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes <joma@telindus.be> + * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK + * read/write cannot be executed + * 05.04.99 0.13 added code to sv_read and sv_write which should detect + * lockups of the sound chip and revive it. This is basically + * an ugly hack, but at least applications using this driver + * won't hang forever. I don't know why these lockups happen, + * it might well be the motherboard chipset (an early 486 PCI + * board with ALI chipset), since every busmastering 100MB + * ethernet card I've tried (Realtek 8139 and Macronix tulip clone) + * exhibit similar behaviour (they work for a couple of packets + * and then lock up and can be revived by ifconfig down/up). + * 07.04.99 0.14 implemented the following ioctl's: SOUND_PCM_READ_RATE, + * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; + * Alpha fixes reported by Peter Jones <pjones@redhat.com> + * Note: dmaio hack might still be wrong on archs other than i386 * */ @@ -251,7 +268,8 @@ struct sv_state { int dev_dmfm; /* hardware resources */ - unsigned int iosb, ioenh, iosynth, iomidi, iogame, iodmaa, iodmac, irq; + unsigned long iosb, ioenh, iosynth, iomidi, iogame; /* long for SPARC */ + unsigned int iodmaa, iodmac, irq; /* mixer stuff */ struct { @@ -1293,8 +1311,20 @@ static ssize_t sv_read(struct file *file, char *buffer, size_t count, loff_t *pp if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; - interruptible_sleep_on(&s->dma_adc.wait); + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, + s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); + spin_lock_irqsave(&s->lock, flags); + set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); + /* program enhanced mode registers */ + wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); + wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); + s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; @@ -1353,8 +1383,20 @@ static ssize_t sv_write(struct file *file, const char *buffer, size_t count, lof if (cnt <= 0) { start_dac(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; - interruptible_sleep_on(&s->dma_dac.wait); + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, + s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); + spin_lock_irqsave(&s->lock, flags); + set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); + /* program enhanced mode registers */ + wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); + wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); + s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; @@ -1431,8 +1473,6 @@ static int sv_mmap(struct file *file, struct vm_area_struct *vma) if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) return -EAGAIN; db->mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1648,7 +1688,7 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1661,7 +1701,7 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.total_bytes >> s->dma_dac.fragshift; + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; @@ -1715,11 +1755,19 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un s->dma_dac.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT) + : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT) + : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -1841,7 +1889,7 @@ static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_ cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.iwait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1888,7 +1936,7 @@ static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.owait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2273,7 +2321,7 @@ __initfunc(int init_sonicvibes(void)) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.10 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.14 time " __TIME__ " " __DATE__ "\n"); #if 0 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"); @@ -2327,7 +2375,7 @@ __initfunc(int init_sonicvibes(void)) } pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ - printk(KERN_DEBUG "sv: io ports: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac); if (s->ioenh == 0 || s->iodmaa == 0 || s->iodmac == 0) continue; @@ -2337,7 +2385,7 @@ __initfunc(int init_sonicvibes(void)) pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */ if (check_region(s->ioenh, SV_EXTENT_ENH)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); goto err_region5; } request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM"); @@ -2352,12 +2400,12 @@ __initfunc(int init_sonicvibes(void)) } request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC"); if (check_region(s->iomidi, SV_EXTENT_MIDI)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); goto err_region2; } request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi"); if (check_region(s->iosynth, SV_EXTENT_SYNTH)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); goto err_region1; } request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth"); @@ -2388,7 +2436,7 @@ __initfunc(int init_sonicvibes(void)) printk(KERN_ERR "sv: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_INFO "sv: found adapter at io %#06x irq %u dmaa %#06x dmac %#06x revision %u\n", + printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n", s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION)); /* register devices */ if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c index 95c332208..9bc08fbd0 100644 --- a/drivers/sound/sound_core.c +++ b/drivers/sound/sound_core.c @@ -39,7 +39,6 @@ #include <linux/malloc.h> #include <linux/types.h> #include <linux/kernel.h> -#include <linux/malloc.h> #include <linux/fs.h> #include <linux/sound.h> #include <linux/major.h> @@ -63,6 +62,10 @@ static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, int n=low; if (index < 0) { /* first free */ + + while (*list && (*list)->unit_minor<n) + list=&((*list)->next); + while(n<top) { /* Found a hole ? */ @@ -73,7 +76,7 @@ static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, } if(n>=top) - return -ENOMEM; + return -ENOENT; } else { n = low+(index*16); while (*list) { @@ -141,13 +144,13 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f int r; struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL); if(s==NULL) - return -1; + return -ENOMEM; spin_lock(&sound_loader_lock); r=__sound_insert_unit(s,list,fops,index,low,top); spin_unlock(&sound_loader_lock); - if(r==-1) + if(r<0) kfree(s); return r; } diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index cf3b70fea..6731180b4 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -67,7 +67,11 @@ caddr_t sound_mem_blocks[1024]; int sound_nblocks = 0; /* Persistent DMA buffers */ -int sound_dmap_flag = 0; /* Off by default */ +#ifdef CONFIG_SOUND_DMAP +int sound_dmap_flag = 1; +#else +int sound_dmap_flag = 0; +#endif static int soundcard_configured = 0; @@ -751,9 +755,6 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_page_prot)) return -EAGAIN; - vma->vm_file = file; - file->f_count++; - dmap->mapping_flags |= DMA_MAP_MAPPED; if( audio_devs[dev]->d->mmap) @@ -802,13 +803,6 @@ bad1: return -1; } -static void destroy_special_devices(void) -{ - unregister_sound_special(6); - unregister_sound_special(1); - unregister_sound_special(8); -} - #ifdef MODULE static void #else @@ -849,12 +843,19 @@ soundcard_init(void) #endif } +#ifdef MODULE + +static void destroy_special_devices(void) +{ + unregister_sound_special(6); + unregister_sound_special(1); + unregister_sound_special(8); +} + static int sound[20] = { 0 }; -#ifdef MODULE - int traceinit = 0; static int dmabuf = 0; MODULE_PARM(traceinit, "i"); diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index 48017eeed..25bfaf3a7 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -943,7 +943,9 @@ int init_module(void) mpu_config.irq = mpu_irq; mpu_config.io_base = mpu_io; - + /* WEH - Try to get right dma channel */ + mpu_config.dma = dma; + if(spea != -1) { old_hardware = spea; diff --git a/drivers/sound/sys_timer.c b/drivers/sound/sys_timer.c index 2e74b6055..e7ca0c84b 100644 --- a/drivers/sound/sys_timer.c +++ b/drivers/sound/sys_timer.c @@ -13,6 +13,7 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Andrew Veliath : adapted tmr2ticks from level 1 sequencer (avoid overflow) */ #include <linux/config.h> @@ -39,11 +40,17 @@ static unsigned long tmr2ticks(int tmr_value) { /* - * Convert system timer ticks (HZ) to MIDI ticks - * (divide # of MIDI ticks/minute by # of system ticks/minute). + * Convert timer ticks to MIDI ticks */ - return ((tmr_value * curr_tempo * curr_timebase) + (30 * 100)) / (60 * HZ); + unsigned long tmp; + unsigned long scale; + + /* tmr_value (ticks per sec) * + 1000000 (usecs per sec) / HZ (ticks per sec) -=> usecs */ + tmp = tmr_value * (1000000 / HZ); + scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ + return (tmp + scale / 2) / scale; } static void diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index 1a6b79c76..70b4af6d3 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -323,7 +323,7 @@ int probe_trix_sb(struct address_info *hw_config) hw_config->name = "AudioTrix SB"; #ifdef CONFIG_SBDSP - return sb_dsp_detect(hw_config); + return sb_dsp_detect(hw_config, 0, 0); #else return 0; #endif |