Merge branch 'topic/sscape-fix' into for-linus

This commit is contained in:
Takashi Iwai 2009-03-24 00:36:21 +01:00
commit d080732334
3 changed files with 96 additions and 181 deletions

View file

@ -368,14 +368,17 @@ config SND_SGALAXY
will be called snd-sgalaxy.
config SND_SSCAPE
tristate "Ensoniq SoundScape PnP driver"
tristate "Ensoniq SoundScape driver"
select SND_HWDEP
select SND_MPU401_UART
select SND_WSS_LIB
help
Say Y here to include support for Ensoniq SoundScape PnP
Say Y here to include support for Ensoniq SoundScape
soundcards.
The PCM audio is supported on SoundScape Classic, Elite, PnP
and VIVO cards. The MIDI support is very experimental.
To compile this driver as a module, choose M here: the module
will be called snd-sscape.

View file

@ -89,9 +89,6 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
#endif
#define MPU401_IO(i) ((i) + 0)
#define MIDI_DATA_IO(i) ((i) + 0)
#define MIDI_CTRL_IO(i) ((i) + 1)
#define HOST_CTRL_IO(i) ((i) + 2)
#define HOST_DATA_IO(i) ((i) + 3)
#define ODIE_ADDR_IO(i) ((i) + 4)
@ -129,9 +126,6 @@ enum GA_REG {
#define DMA_8BIT 0x80
#define AD1845_FREQ_SEL_MSB 0x16
#define AD1845_FREQ_SEL_LSB 0x17
enum card_type {
SSCAPE,
SSCAPE_PNP,
@ -141,8 +135,6 @@ enum card_type {
struct soundscape {
spinlock_t lock;
unsigned io_base;
unsigned wss_base;
int codec_type;
int ic_type;
enum card_type type;
struct resource *io_res;
@ -330,7 +322,7 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
*/
static inline int verify_mpu401(const struct snd_mpu401 * mpu)
{
return ((inb(MIDI_CTRL_IO(mpu->port)) & 0xc0) == 0x80);
return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
}
/*
@ -338,7 +330,7 @@ static inline int verify_mpu401(const struct snd_mpu401 * mpu)
*/
static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
{
outb(0, MIDI_DATA_IO(mpu->port));
outb(0, MPU401D(mpu));
}
/*
@ -396,20 +388,20 @@ static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned ti
*/
static int obp_startup_ack(struct soundscape *s, unsigned timeout)
{
while (timeout != 0) {
unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
do {
unsigned long flags;
unsigned char x;
schedule_timeout_uninterruptible(1);
spin_lock_irqsave(&s->lock, flags);
x = inb(HOST_DATA_IO(s->io_base));
spin_unlock_irqrestore(&s->lock, flags);
if ((x & 0xfe) == 0xfe)
return 1;
--timeout;
} /* while */
msleep(10);
} while (time_before(jiffies, end_time));
return 0;
}
@ -423,20 +415,20 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
*/
static int host_startup_ack(struct soundscape *s, unsigned timeout)
{
while (timeout != 0) {
unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
do {
unsigned long flags;
unsigned char x;
schedule_timeout_uninterruptible(1);
spin_lock_irqsave(&s->lock, flags);
x = inb(HOST_DATA_IO(s->io_base));
spin_unlock_irqrestore(&s->lock, flags);
if (x == 0xfe)
return 1;
--timeout;
} /* while */
msleep(10);
} while (time_before(jiffies, end_time));
return 0;
}
@ -532,10 +524,10 @@ static int upload_dma_data(struct soundscape *s,
* give it 5 seconds (max) ...
*/
ret = 0;
if (!obp_startup_ack(s, 5)) {
if (!obp_startup_ack(s, 5000)) {
snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n");
ret = -EAGAIN;
} else if (!host_startup_ack(s, 5)) {
} else if (!host_startup_ack(s, 5000)) {
snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n");
ret = -EAGAIN;
}
@ -732,13 +724,7 @@ static int sscape_midi_get(struct snd_kcontrol *kctl,
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
set_host_mode_unsafe(s->io_base);
if (host_write_ctrl_unsafe(s->io_base, CMD_GET_MIDI_VOL, 100)) {
uctl->value.integer.value[0] = host_read_ctrl_unsafe(s->io_base, 100);
}
set_midi_mode_unsafe(s->io_base);
uctl->value.integer.value[0] = s->midi_vol;
spin_unlock_irqrestore(&s->lock, flags);
return 0;
}
@ -773,6 +759,7 @@ static int sscape_midi_put(struct snd_kcontrol *kctl,
change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
&& host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100)
&& host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100));
s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127;
__skip_change:
/*
@ -815,12 +802,11 @@ static unsigned __devinit get_irq_config(int irq)
* Perform certain arcane port-checks to see whether there
* is a SoundScape board lurking behind the given ports.
*/
static int __devinit detect_sscape(struct soundscape *s)
static int __devinit detect_sscape(struct soundscape *s, long wss_io)
{
unsigned long flags;
unsigned d;
int retval = 0;
int codec = s->wss_base;
spin_lock_irqsave(&s->lock, flags);
@ -836,13 +822,11 @@ static int __devinit detect_sscape(struct soundscape *s)
if ((d & 0x80) != 0)
goto _done;
if (d == 0) {
s->codec_type = 1;
if (d == 0)
s->ic_type = IC_ODIE;
} else if ((d & 0x60) != 0) {
s->codec_type = 2;
else if ((d & 0x60) != 0)
s->ic_type = IC_OPUS;
} else
else
goto _done;
outb(0xfa, ODIE_ADDR_IO(s->io_base));
@ -862,10 +846,10 @@ static int __devinit detect_sscape(struct soundscape *s)
sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
if (s->type == SSCAPE_VIVO)
codec += 4;
wss_io += 4;
/* wait for WSS codec */
for (d = 0; d < 500; d++) {
if ((inb(codec) & 0x80) == 0)
if ((inb(wss_io) & 0x80) == 0)
break;
spin_unlock_irqrestore(&s->lock, flags);
msleep(1);
@ -954,82 +938,6 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l
}
/*
* Override for the CS4231 playback format function.
* The AD1845 has much simpler format and rate selection.
*/
static void ad1845_playback_format(struct snd_wss *chip,
struct snd_pcm_hw_params *params,
unsigned char format)
{
unsigned long flags;
unsigned rate = params_rate(params);
/*
* The AD1845 can't handle sample frequencies
* outside of 4 kHZ to 50 kHZ
*/
if (rate > 50000)
rate = 50000;
else if (rate < 4000)
rate = 4000;
spin_lock_irqsave(&chip->reg_lock, flags);
/*
* Program the AD1845 correctly for the playback stream.
* Note that we do NOT need to toggle the MCE bit because
* the PLAYBACK_ENABLE bit of the Interface Configuration
* register is set.
*
* NOTE: We seem to need to write to the MSB before the LSB
* to get the correct sample frequency.
*/
snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
/*
* Override for the CS4231 capture format function.
* The AD1845 has much simpler format and rate selection.
*/
static void ad1845_capture_format(struct snd_wss *chip,
struct snd_pcm_hw_params *params,
unsigned char format)
{
unsigned long flags;
unsigned rate = params_rate(params);
/*
* The AD1845 can't handle sample frequencies
* outside of 4 kHZ to 50 kHZ
*/
if (rate > 50000)
rate = 50000;
else if (rate < 4000)
rate = 4000;
spin_lock_irqsave(&chip->reg_lock, flags);
/*
* Program the AD1845 correctly for the playback stream.
* Note that we do NOT need to toggle the MCE bit because
* the CAPTURE_ENABLE bit of the Interface Configuration
* register is set.
*
* NOTE: We seem to need to write to the MSB before the LSB
* to get the correct sample frequency.
*/
snd_wss_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
/*
* Create an AD1845 PCM subdevice on the SoundScape. The AD1845
* is very much like a CS4231, with a few extra bits. We will
@ -1055,11 +963,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
unsigned long flags;
struct snd_pcm *pcm;
#define AD1845_FREQ_SEL_ENABLE 0x08
#define AD1845_PWR_DOWN_CTRL 0x1b
#define AD1845_CRYS_CLOCK_SEL 0x1d
/*
* It turns out that the PLAYBACK_ENABLE bit is set
* by the lowlevel driver ...
@ -1074,7 +977,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
*/
if (sscape->type != SSCAPE_VIVO) {
int val;
/*
* The input clock frequency on the SoundScape must
* be 14.31818 MHz, because we must set this register
@ -1082,22 +984,10 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
*/
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
snd_wss_out(chip, AD1845_CLOCK, 0x20);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
/*
* More custom configuration:
* a) select "mode 2" and provide a current drive of 8mA
* b) enable frequency selection (for capture/playback)
*/
spin_lock_irqsave(&chip->reg_lock, flags);
snd_wss_out(chip, CS4231_MISC_INFO,
CS4231_MODE2 | 0x10);
val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL);
snd_wss_out(chip, AD1845_PWR_DOWN_CTRL,
val | AD1845_FREQ_SEL_ENABLE);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
err = snd_wss_pcm(chip, 0, &pcm);
@ -1113,11 +1003,13 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
"for AD1845 chip\n");
goto _error;
}
err = snd_wss_timer(chip, 0, NULL);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No timer device "
"for AD1845 chip\n");
goto _error;
if (chip->hardware != WSS_HW_AD1848) {
err = snd_wss_timer(chip, 0, NULL);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No timer device "
"for AD1845 chip\n");
goto _error;
}
}
if (sscape->type != SSCAPE_VIVO) {
@ -1128,8 +1020,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
"MIDI mixer control\n");
goto _error;
}
chip->set_playback_format = ad1845_playback_format;
chip->set_capture_format = ad1845_capture_format;
}
strcpy(card->driver, "SoundScape");
@ -1157,7 +1047,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
unsigned dma_cfg;
unsigned irq_cfg;
unsigned mpu_irq_cfg;
unsigned xport;
struct resource *io_res;
struct resource *wss_res;
unsigned long flags;
@ -1177,15 +1066,15 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
return -ENXIO;
}
xport = port[dev];
/*
* Grab IO ports that we will need to probe so that we
* can detect and control this hardware ...
*/
io_res = request_region(xport, 8, "SoundScape");
io_res = request_region(port[dev], 8, "SoundScape");
if (!io_res) {
snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport);
snd_printk(KERN_ERR
"sscape: can't grab port 0x%lx\n", port[dev]);
return -EBUSY;
}
wss_res = NULL;
@ -1212,10 +1101,9 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
spin_lock_init(&sscape->fwlock);
sscape->io_res = io_res;
sscape->wss_res = wss_res;
sscape->io_base = xport;
sscape->wss_base = wss_port[dev];
sscape->io_base = port[dev];
if (!detect_sscape(sscape)) {
if (!detect_sscape(sscape, wss_port[dev])) {
printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
err = -ENODEV;
goto _release_dma;
@ -1288,12 +1176,11 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
}
#define MIDI_DEVNUM 0
if (sscape->type != SSCAPE_VIVO) {
err = create_mpu401(card, MIDI_DEVNUM,
MPU401_IO(xport), mpu_irq[dev]);
err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]);
if (err < 0) {
printk(KERN_ERR "sscape: Failed to create "
"MPU-401 device at 0x%x\n",
MPU401_IO(xport));
"MPU-401 device at 0x%lx\n",
port[dev]);
goto _release_dma;
}

View file

@ -181,25 +181,6 @@ static void snd_wss_wait(struct snd_wss *chip)
udelay(100);
}
static void snd_wss_outm(struct snd_wss *chip, unsigned char reg,
unsigned char mask, unsigned char value)
{
unsigned char tmp = (chip->image[reg] & mask) | value;
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
#endif
chip->image[reg] = tmp;
if (!chip->calibrate_mute) {
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
wmb();
wss_outb(chip, CS4231P(REG), tmp);
mb();
}
}
static void snd_wss_dout(struct snd_wss *chip, unsigned char reg,
unsigned char value)
{
@ -597,7 +578,15 @@ static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute)
chip->image[CS4231_RIGHT_INPUT]);
snd_wss_dout(chip, CS4231_LOOPBACK,
chip->image[CS4231_LOOPBACK]);
} else {
snd_wss_dout(chip, CS4231_LEFT_INPUT,
0);
snd_wss_dout(chip, CS4231_RIGHT_INPUT,
0);
snd_wss_dout(chip, CS4231_LOOPBACK,
0xfd);
}
snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT,
mute | chip->image[CS4231_AUX1_LEFT_INPUT]);
snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT,
@ -640,7 +629,6 @@ static void snd_wss_playback_format(struct snd_wss *chip,
int full_calib = 1;
mutex_lock(&chip->mce_mutex);
snd_wss_calibrate_mute(chip, 1);
if (chip->hardware == WSS_HW_CS4231A ||
(chip->hardware & WSS_HW_CS4232_MASK)) {
spin_lock_irqsave(&chip->reg_lock, flags);
@ -656,6 +644,24 @@ static void snd_wss_playback_format(struct snd_wss *chip,
full_calib = 0;
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
} else if (chip->hardware == WSS_HW_AD1845) {
unsigned rate = params_rate(params);
/*
* Program the AD1845 correctly for the playback stream.
* Note that we do NOT need to toggle the MCE bit because
* the PLAYBACK_ENABLE bit of the Interface Configuration
* register is set.
*
* NOTE: We seem to need to write to the MSB before the LSB
* to get the correct sample frequency.
*/
spin_lock_irqsave(&chip->reg_lock, flags);
snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (pdfr & 0xf0));
snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
full_calib = 0;
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
if (full_calib) {
snd_wss_mce_up(chip);
@ -673,7 +679,6 @@ static void snd_wss_playback_format(struct snd_wss *chip,
udelay(100); /* this seems to help */
snd_wss_mce_down(chip);
}
snd_wss_calibrate_mute(chip, 0);
mutex_unlock(&chip->mce_mutex);
}
@ -685,7 +690,6 @@ static void snd_wss_capture_format(struct snd_wss *chip,
int full_calib = 1;
mutex_lock(&chip->mce_mutex);
snd_wss_calibrate_mute(chip, 1);
if (chip->hardware == WSS_HW_CS4231A ||
(chip->hardware & WSS_HW_CS4232_MASK)) {
spin_lock_irqsave(&chip->reg_lock, flags);
@ -700,6 +704,24 @@ static void snd_wss_capture_format(struct snd_wss *chip,
full_calib = 0;
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
} else if (chip->hardware == WSS_HW_AD1845) {
unsigned rate = params_rate(params);
/*
* Program the AD1845 correctly for the capture stream.
* Note that we do NOT need to toggle the MCE bit because
* the PLAYBACK_ENABLE bit of the Interface Configuration
* register is set.
*
* NOTE: We seem to need to write to the MSB before the LSB
* to get the correct sample frequency.
*/
spin_lock_irqsave(&chip->reg_lock, flags);
snd_wss_out(chip, CS4231_REC_FORMAT, (cdfr & 0xf0));
snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
full_calib = 0;
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
if (full_calib) {
snd_wss_mce_up(chip);
@ -724,7 +746,6 @@ static void snd_wss_capture_format(struct snd_wss *chip,
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
}
snd_wss_calibrate_mute(chip, 0);
mutex_unlock(&chip->mce_mutex);
}
@ -781,6 +802,7 @@ static void snd_wss_init(struct snd_wss *chip)
{
unsigned long flags;
snd_wss_calibrate_mute(chip, 1);
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
@ -804,6 +826,8 @@ static void snd_wss_init(struct snd_wss *chip)
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB;
snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
snd_wss_out(chip,
CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
spin_unlock_irqrestore(&chip->reg_lock, flags);
@ -837,6 +861,7 @@ static void snd_wss_init(struct snd_wss *chip)
chip->image[CS4231_REC_FORMAT]);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_mce_down(chip);
snd_wss_calibrate_mute(chip, 0);
#ifdef SNDRV_DEBUG_MCE
snd_printk(KERN_DEBUG "init: (5)\n");
@ -895,8 +920,6 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
mutex_unlock(&chip->open_mutex);
return;
}
snd_wss_calibrate_mute(chip, 1);
/* disable IRQ */
spin_lock_irqsave(&chip->reg_lock, flags);
if (!(chip->hardware & WSS_HW_AD1848_MASK))
@ -929,8 +952,6 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode)
wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_wss_calibrate_mute(chip, 0);
chip->mode = 0;
mutex_unlock(&chip->open_mutex);
}
@ -1123,7 +1144,7 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id)
if (chip->hardware & WSS_HW_AD1848_MASK)
wss_outb(chip, CS4231P(STATUS), 0);
else
snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0);
snd_wss_out(chip, CS4231_IRQ_STATUS, status);
spin_unlock(&chip->reg_lock);
return IRQ_HANDLED;
}
@ -1325,6 +1346,10 @@ static int snd_wss_probe(struct snd_wss *chip)
chip->image[CS4231_ALT_FEATURE_2] =
chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
}
/* enable fine grained frequency selection */
if (chip->hardware == WSS_HW_AD1845)
chip->image[AD1845_PWR_DOWN] = 8;
ptr = (unsigned char *) &chip->image;
regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
snd_wss_mce_down(chip);