diff options
Diffstat (limited to 'sound/pci/es1938.c')
| -rw-r--r-- | sound/pci/es1938.c | 353 |
1 files changed, 216 insertions, 137 deletions
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 0d556b09ad0..34d95bf916b 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1,7 +1,7 @@ /* * Driver for ESS Solo-1 (ES1938, ES1946, ES1969) soundcard * Copyright (c) by Jaromir Koutek <miri@punknet.cz>, - * Jaroslav Kysela <perex@suse.cz>, + * Jaroslav Kysela <perex@perex.cz>, * Thomas Sailer <sailer@ife.ee.ethz.ch>, * Abramo Bagnara <abramo@alsa-project.org>, * Markus Gruber <gruber@eikon.tum.de> @@ -47,20 +47,21 @@ */ -#include <sound/driver.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/gameport.h> -#include <linux/moduleparam.h> +#include <linux/module.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> #include <sound/opl3.h> #include <sound/mpu401.h> #include <sound/initval.h> +#include <sound/tlv.h> #include <asm/io.h> @@ -78,7 +79,7 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES1938}," static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for ESS Solo-1 soundcard."); @@ -225,6 +226,7 @@ struct es1938 { unsigned int dma2_start; unsigned int dma1_shift; unsigned int dma2_shift; + unsigned int last_capture_dmaaddr; unsigned int active; spinlock_t reg_lock; @@ -234,15 +236,15 @@ struct es1938 { #ifdef SUPPORT_JOYSTICK struct gameport *gameport; #endif -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP unsigned char saved_regs[SAVED_REG_SIZE]; #endif }; -static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_es1938_ids[] = { - { 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Solo-1 */ +static DEFINE_PCI_DEVICE_TABLE(snd_es1938_ids) = { + { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */ { 0, } }; @@ -252,7 +254,6 @@ MODULE_DEVICE_TABLE(pci, snd_es1938_ids); #define WRITE_LOOP_TIMEOUT 0x10000 #define GET_LOOP_TIMEOUT 0x01000 -#undef REG_DEBUG /* ----------------------------------------------------------------- * Write to a mixer register * -----------------------------------------------------------------*/ @@ -263,9 +264,7 @@ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsig outb(reg, SLSB_REG(chip, MIXERADDR)); outb(val, SLSB_REG(chip, MIXERDATA)); spin_unlock_irqrestore(&chip->mixer_lock, flags); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Mixer reg %02x set to %02x\n", reg, val); -#endif + dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, val); } /* ----------------------------------------------------------------- @@ -279,9 +278,7 @@ static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg) outb(reg, SLSB_REG(chip, MIXERADDR)); data = inb(SLSB_REG(chip, MIXERDATA)); spin_unlock_irqrestore(&chip->mixer_lock, flags); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Mixer reg %02x now is %02x\n", reg, data); -#endif + dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data); return data; } @@ -300,10 +297,9 @@ static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg, if (val != oval) { new = (old & ~mask) | (val & mask); outb(new, SLSB_REG(chip, MIXERDATA)); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x\n", + dev_dbg(chip->card->dev, + "Mixer reg %02x was %02x, set to %02x\n", reg, old, new); -#endif } spin_unlock_irqrestore(&chip->mixer_lock, flags); return oval; @@ -322,7 +318,8 @@ static void snd_es1938_write_cmd(struct es1938 *chip, unsigned char cmd) return; } } - printk(KERN_ERR "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v); + dev_err(chip->card->dev, + "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v); } /* ----------------------------------------------------------------- @@ -335,7 +332,7 @@ static int snd_es1938_get_byte(struct es1938 *chip) for (i = GET_LOOP_TIMEOUT; i; i--) if ((v = inb(SLSB_REG(chip, STATUS))) & 0x80) return inb(SLSB_REG(chip, READDATA)); - snd_printk(KERN_ERR "get_byte timeout: status 0x02%x\n", v); + dev_err(chip->card->dev, "get_byte timeout: status 0x02%x\n", v); return -ENODEV; } @@ -349,9 +346,7 @@ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned ch snd_es1938_write_cmd(chip, reg); snd_es1938_write_cmd(chip, val); spin_unlock_irqrestore(&chip->reg_lock, flags); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Reg %02x set to %02x\n", reg, val); -#endif + dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, val); } /* ----------------------------------------------------------------- @@ -366,9 +361,7 @@ static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg) snd_es1938_write_cmd(chip, reg); val = snd_es1938_get_byte(chip); spin_unlock_irqrestore(&chip->reg_lock, flags); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Reg %02x now is %02x\n", reg, val); -#endif + dev_dbg(chip->card->dev, "Reg %02x now is %02x\n", reg, val); return val; } @@ -389,10 +382,8 @@ static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char snd_es1938_write_cmd(chip, reg); new = (old & ~mask) | (val & mask); snd_es1938_write_cmd(chip, new); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Reg %02x was %02x, set to %02x\n", + dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x\n", reg, old, new); -#endif } spin_unlock_irqrestore(&chip->reg_lock, flags); return oval; @@ -414,7 +405,7 @@ static void snd_es1938_reset(struct es1938 *chip) goto __next; } } - snd_printk(KERN_ERR "ESS Solo-1 reset failed\n"); + dev_err(chip->card->dev, "ESS Solo-1 reset failed\n"); __next: snd_es1938_write_cmd(chip, ESS_CMD_ENABLEEXT); @@ -527,6 +518,7 @@ static void snd_es1938_capture_setdma(struct es1938 *chip) outb(1, SLDM_REG(chip, DMAMASK)); outb(0x14, SLDM_REG(chip, DMAMODE)); outl(chip->dma1_start, SLDM_REG(chip, DMAADDR)); + chip->last_capture_dmaaddr = chip->dma1_start; outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); /* 3. Unmask DMA */ outb(0, SLDM_REG(chip, DMAMASK)); @@ -768,19 +760,40 @@ static int snd_es1938_playback_prepare(struct snd_pcm_substream *substream) return -EINVAL; } +/* during the incrementing of dma counters the DMA register reads sometimes + returns garbage. To ensure a valid hw pointer, the following checks which + should be very unlikely to fail are used: + - is the current DMA address in the valid DMA range ? + - is the sum of DMA address and DMA counter pointing to the last DMA byte ? + One can argue this could differ by one byte depending on which register is + updated first, so the implementation below allows for that. +*/ static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream) { struct es1938 *chip = snd_pcm_substream_chip(substream); size_t ptr; +#if 0 size_t old, new; -#if 1 /* This stuff is *needed*, don't ask why - AB */ old = inw(SLDM_REG(chip, DMACOUNT)); while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) old = new; ptr = chip->dma1_size - 1 - new; #else - ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start; + size_t count; + unsigned int diff; + + ptr = inl(SLDM_REG(chip, DMAADDR)); + count = inw(SLDM_REG(chip, DMACOUNT)); + diff = chip->dma1_start + chip->dma1_size - ptr - count; + + if (diff > 3 || ptr < chip->dma1_start + || ptr >= chip->dma1_start+chip->dma1_size) + ptr = chip->last_capture_dmaaddr; /* bad, use last saved */ + else + chip->last_capture_dmaaddr = ptr; /* good, remember it */ + + ptr -= chip->dma1_start; #endif return ptr >> chip->dma1_shift; } @@ -836,7 +849,8 @@ static int snd_es1938_capture_copy(struct snd_pcm_substream *substream, struct es1938 *chip = snd_pcm_substream_chip(substream); pos <<= chip->dma1_shift; count <<= chip->dma1_shift; - snd_assert(pos + count <= chip->dma1_size, return -EINVAL); + if (snd_BUG_ON(pos + count > chip->dma1_size)) + return -EINVAL; if (pos + count < chip->dma1_size) { if (copy_to_user(dst, runtime->dma_area + pos + 1, count)) return -EFAULT; @@ -1002,7 +1016,7 @@ static struct snd_pcm_ops snd_es1938_capture_ops = { .copy = snd_es1938_capture_copy, }; -static int __devinit snd_es1938_new_pcm(struct es1938 *chip, int device) +static int snd_es1938_new_pcm(struct es1938 *chip, int device) { struct snd_pcm *pcm; int err; @@ -1064,15 +1078,7 @@ static int snd_es1938_put_mux(struct snd_kcontrol *kcontrol, return snd_es1938_mixer_bits(chip, 0x1c, 0x07, val) != val; } -static int snd_es1938_info_spatializer_enable(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es1938_info_spatializer_enable snd_ctl_boolean_mono_info static int snd_es1938_get_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1118,15 +1124,7 @@ static int snd_es1938_get_hw_volume(struct snd_kcontrol *kcontrol, return 0; } -static int snd_es1938_info_hw_switch(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es1938_info_hw_switch snd_ctl_boolean_stereo_info static int snd_es1938_get_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1163,6 +1161,14 @@ static int snd_es1938_reg_read(struct es1938 *chip, unsigned char reg) return snd_es1938_read(chip, reg); } +#define ES1938_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\ + .name = xname, .index = xindex, \ + .info = snd_es1938_info_single, \ + .get = snd_es1938_get_single, .put = snd_es1938_put_single, \ + .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ + .tlv = { .p = xtlv } } #define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_es1938_info_single, \ @@ -1216,6 +1222,14 @@ static int snd_es1938_put_single(struct snd_kcontrol *kcontrol, return snd_es1938_reg_bits(chip, reg, mask, val) != val; } +#define ES1938_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\ + .name = xname, .index = xindex, \ + .info = snd_es1938_info_double, \ + .get = snd_es1938_get_double, .put = snd_es1938_put_double, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = xtlv } } #define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_es1938_info_double, \ @@ -1296,8 +1310,36 @@ static int snd_es1938_put_double(struct snd_kcontrol *kcontrol, return change; } +static const DECLARE_TLV_DB_RANGE(db_scale_master, + 0, 54, TLV_DB_SCALE_ITEM(-3600, 50, 1), + 54, 63, TLV_DB_SCALE_ITEM(-900, 100, 0), +); + +static const DECLARE_TLV_DB_RANGE(db_scale_audio1, + 0, 8, TLV_DB_SCALE_ITEM(-3300, 300, 1), + 8, 15, TLV_DB_SCALE_ITEM(-900, 150, 0), +); + +static const DECLARE_TLV_DB_RANGE(db_scale_audio2, + 0, 8, TLV_DB_SCALE_ITEM(-3450, 300, 1), + 8, 15, TLV_DB_SCALE_ITEM(-1050, 150, 0), +); + +static const DECLARE_TLV_DB_RANGE(db_scale_mic, + 0, 8, TLV_DB_SCALE_ITEM(-2400, 300, 1), + 8, 15, TLV_DB_SCALE_ITEM(0, 150, 0), +); + +static const DECLARE_TLV_DB_RANGE(db_scale_line, + 0, 8, TLV_DB_SCALE_ITEM(-3150, 300, 1), + 8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0), +); + +static const DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0); + static struct snd_kcontrol_new snd_es1938_controls[] = { -ES1938_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0), +ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0, + db_scale_master), ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1308,20 +1350,28 @@ ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), .name = "Hardware Master Playback Switch", - .access = SNDRV_CTL_ELEM_ACCESS_READ, .info = snd_es1938_info_hw_switch, .get = snd_es1938_get_hw_switch, + .tlv = { .p = db_scale_master }, }, ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0), -ES1938_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0), +ES1938_DOUBLE_TLV("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0, + db_scale_line), ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0), -ES1938_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0), -ES1938_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0), -ES1938_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0), -ES1938_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0), -ES1938_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0), -ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0), +ES1938_DOUBLE_TLV("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0, + db_scale_mic), +ES1938_DOUBLE_TLV("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0, + db_scale_line), +ES1938_DOUBLE_TLV("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0, + db_scale_mic), +ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0, + db_scale_line), +ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0, + db_scale_capture), +ES1938_SINGLE("Beep Volume", 0, 0x3c, 0, 7, 0), ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0), ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), { @@ -1331,16 +1381,26 @@ ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), .get = snd_es1938_get_mux, .put = snd_es1938_put_mux, }, -ES1938_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0), -ES1938_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0), -ES1938_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0), -ES1938_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0), -ES1938_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0), -ES1938_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0), -ES1938_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0), -ES1938_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0), -ES1938_DOUBLE("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0), -ES1938_DOUBLE("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0), +ES1938_DOUBLE_TLV("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0, + db_scale_line), +ES1938_DOUBLE_TLV("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0, + db_scale_audio2), +ES1938_DOUBLE_TLV("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0, + db_scale_mic), +ES1938_DOUBLE_TLV("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0, + db_scale_line), +ES1938_DOUBLE_TLV("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0, + db_scale_mic), +ES1938_DOUBLE_TLV("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0, + db_scale_line), +ES1938_DOUBLE_TLV("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0, + db_scale_line), +ES1938_DOUBLE_TLV("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0, + db_scale_line), +ES1938_DOUBLE_TLV("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0, + db_scale_audio2), +ES1938_DOUBLE_TLV("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0, + db_scale_audio1), ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1385,7 +1445,7 @@ static void snd_es1938_chip_init(struct es1938 *chip) outb(0, SLDM_REG(chip, DMACLEAR)); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP /* * PM support */ @@ -1398,9 +1458,10 @@ static unsigned char saved_regs[SAVED_REG_SIZE+1] = { }; -static int es1938_suspend(struct pci_dev *pci, pm_message_t state) +static int es1938_suspend(struct device *dev) { - struct snd_card *card = pci_get_drvdata(pci); + struct pci_dev *pci = to_pci_dev(dev); + struct snd_card *card = dev_get_drvdata(dev); struct es1938 *chip = card->private_data; unsigned char *s, *d; @@ -1412,23 +1473,38 @@ static int es1938_suspend(struct pci_dev *pci, pm_message_t state) *d = snd_es1938_reg_read(chip, *s); outb(0x00, SLIO_REG(chip, IRQCONTROL)); /* disable irqs */ - if (chip->irq >= 0) + if (chip->irq >= 0) { free_irq(chip->irq, chip); + chip->irq = -1; + } pci_disable_device(pci); pci_save_state(pci); + pci_set_power_state(pci, PCI_D3hot); return 0; } -static int es1938_resume(struct pci_dev *pci) +static int es1938_resume(struct device *dev) { - struct snd_card *card = pci_get_drvdata(pci); + struct pci_dev *pci = to_pci_dev(dev); + struct snd_card *card = dev_get_drvdata(dev); struct es1938 *chip = card->private_data; unsigned char *s, *d; + pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); - pci_enable_device(pci); - request_irq(pci->irq, snd_es1938_interrupt, - SA_INTERRUPT|SA_SHIRQ, "ES1938", chip); + if (pci_enable_device(pci) < 0) { + dev_err(dev, "pci_enable_device failed, disabling device\n"); + snd_card_disconnect(card); + return -EIO; + } + + if (request_irq(pci->irq, snd_es1938_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip)) { + dev_err(dev, "unable to grab IRQ %d, disabling device\n", + pci->irq); + snd_card_disconnect(card); + return -EIO; + } chip->irq = pci->irq; snd_es1938_chip_init(chip); @@ -1443,16 +1519,22 @@ static int es1938_resume(struct pci_dev *pci) snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } -#endif /* CONFIG_PM */ + +static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume); +#define ES1938_PM_OPS &es1938_pm +#else +#define ES1938_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ #ifdef SUPPORT_JOYSTICK -static int __devinit snd_es1938_create_gameport(struct es1938 *chip) +static int snd_es1938_create_gameport(struct es1938 *chip) { struct gameport *gp; chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "es1938: cannot allocate memory for gameport\n"); + dev_err(chip->card->dev, + "cannot allocate memory for gameport\n"); return -ENOMEM; } @@ -1501,9 +1583,9 @@ static int snd_es1938_dev_free(struct snd_device *device) return snd_es1938_free(chip); } -static int __devinit snd_es1938_create(struct snd_card *card, - struct pci_dev * pci, - struct es1938 ** rchip) +static int snd_es1938_create(struct snd_card *card, + struct pci_dev *pci, + struct es1938 **rchip) { struct es1938 *chip; int err; @@ -1517,9 +1599,10 @@ static int __devinit snd_es1938_create(struct snd_card *card, if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 24 bits */ - if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || - pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { - snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); + if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 || + pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) { + dev_err(card->dev, + "architecture does not support 24bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1533,6 +1616,7 @@ static int __devinit snd_es1938_create(struct snd_card *card, spin_lock_init(&chip->mixer_lock); chip->card = card; chip->pci = pci; + chip->irq = -1; if ((err = pci_request_regions(pci, "ESS Solo-1")) < 0) { kfree(chip); pci_disable_device(pci); @@ -1543,17 +1627,16 @@ static int __devinit snd_es1938_create(struct snd_card *card, chip->vc_port = pci_resource_start(pci, 2); chip->mpu_port = pci_resource_start(pci, 3); chip->game_port = pci_resource_start(pci, 4); - if (request_irq(pci->irq, snd_es1938_interrupt, SA_INTERRUPT|SA_SHIRQ, - "ES1938", chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, + KBUILD_MODNAME, chip)) { + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_es1938_free(chip); return -EBUSY; } chip->irq = pci->irq; -#ifdef ES1938_DDEBUG - snd_printk(KERN_DEBUG "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n", + dev_dbg(card->dev, + "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n", chip->io_port, chip->sb_port, chip->vc_port, chip->mpu_port, chip->game_port); -#endif chip->ddma_port = chip->vc_port + 0x00; /* fix from Thomas Sailer */ @@ -1564,8 +1647,6 @@ static int __devinit snd_es1938_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; } @@ -1573,7 +1654,7 @@ static int __devinit snd_es1938_create(struct snd_card *card, /* -------------------------------------------------------------------- * Interrupt handler * -------------------------------------------------------------------- */ -static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id) { struct es1938 *chip = dev_id; unsigned char status, audiostatus; @@ -1581,18 +1662,23 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *r status = inb(SLIO_REG(chip, IRQCONTROL)); #if 0 - printk("Es1938debug - interrupt status: =0x%x\n", status); + dev_dbg(chip->card->dev, + "Es1938debug - interrupt status: =0x%x\n", status); #endif /* AUDIO 1 */ if (status & 0x10) { #if 0 - printk("Es1938debug - AUDIO channel 1 interrupt\n"); - printk("Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n", + dev_dbg(chip->card->dev, + "Es1938debug - AUDIO channel 1 interrupt\n"); + dev_dbg(chip->card->dev, + "Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n", inw(SLDM_REG(chip, DMACOUNT))); - printk("Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n", + dev_dbg(chip->card->dev, + "Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n", inl(SLDM_REG(chip, DMAADDR))); - printk("Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n", + dev_dbg(chip->card->dev, + "Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n", inl(SLDM_REG(chip, DMASTATUS))); #endif /* clear irq */ @@ -1607,10 +1693,13 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *r /* AUDIO 2 */ if (status & 0x20) { #if 0 - printk("Es1938debug - AUDIO channel 2 interrupt\n"); - printk("Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n", + dev_dbg(chip->card->dev, + "Es1938debug - AUDIO channel 2 interrupt\n"); + dev_dbg(chip->card->dev, + "Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n", inw(SLIO_REG(chip, AUDIO2DMACOUNT))); - printk("Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n", + dev_dbg(chip->card->dev, + "Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n", inl(SLIO_REG(chip, AUDIO2DMAADDR))); #endif @@ -1645,7 +1734,7 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *r // snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0); /* ack? */ if (chip->rmidi) { handled = 1; - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); } } return IRQ_RETVAL(handled); @@ -1653,7 +1742,7 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *r #define ES1938_DMA_SIZE 64 -static int __devinit snd_es1938_mixer(struct es1938 *chip) +static int snd_es1938_mixer(struct es1938 *chip) { struct snd_card *card; unsigned int idx; @@ -1691,8 +1780,8 @@ static int __devinit snd_es1938_mixer(struct es1938 *chip) } -static int __devinit snd_es1938_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_es1938_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1707,9 +1796,10 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, return -ENOENT; } - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); - if (card == NULL) - return -ENOMEM; + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); + if (err < 0) + return err; for (idx = 0; idx < 5; idx++) { if (pci_resource_start(pci, idx) == 0 || !(pci_resource_flags(pci, idx) & IORESOURCE_IO)) { @@ -1742,7 +1832,7 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, SLSB_REG(chip, FMLOWADDR), SLSB_REG(chip, FMHIGHADDR), OPL3_HW_OPL3, 1, &opl3) < 0) { - printk(KERN_ERR "es1938: OPL3 not detected at 0x%lx\n", + dev_err(card->dev, "OPL3 not detected at 0x%lx\n", SLSB_REG(chip, FMLOWADDR)); } else { if ((err = snd_opl3_timer_new(opl3, 0, 1)) < 0) { @@ -1755,8 +1845,10 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, } } if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - chip->mpu_port, 1, chip->irq, 0, &chip->rmidi) < 0) { - printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); + chip->mpu_port, + MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, + -1, &chip->rmidi) < 0) { + dev_err(card->dev, "unable to initialize MPU-401\n"); } else { // this line is vital for MIDI interrupt handling on ess-solo1 // andreas@flying-snail.de @@ -1775,32 +1867,19 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_es1938_remove(struct pci_dev *pci) +static void snd_es1938_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } -static struct pci_driver driver = { - .name = "ESS ES1938 (Solo-1)", +static struct pci_driver es1938_driver = { + .name = KBUILD_MODNAME, .id_table = snd_es1938_ids, .probe = snd_es1938_probe, - .remove = __devexit_p(snd_es1938_remove), -#ifdef CONFIG_PM - .suspend = es1938_suspend, - .resume = es1938_resume, -#endif + .remove = snd_es1938_remove, + .driver = { + .pm = ES1938_PM_OPS, + }, }; -static int __init alsa_card_es1938_init(void) -{ - return pci_register_driver(&driver); -} - -static void __exit alsa_card_es1938_exit(void) -{ - pci_unregister_driver(&driver); -} - -module_init(alsa_card_es1938_init) -module_exit(alsa_card_es1938_exit) +module_pci_driver(es1938_driver); |
