/*
* Driver for Cirrus Logic CS4281 based PCI soundcard
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
*
*
* This program is free software; you can redistribute it and/or modify
*
*/
-#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <sound/pcm.h>
#include <sound/rawmidi.h>
#include <sound/ac97_codec.h>
+#include <sound/tlv.h>
#include <sound/opl3.h>
#include <sound/initval.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Cirrus Logic CS4281");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,CS4281}}");
};
-static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
static struct pci_device_id snd_cs4281_ids[] = {
- { 0x1013, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CS4281 */
+ { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */
{ 0, }
};
if (!capture) {
if (dma->left_slot == chip->src_left_play_slot) {
unsigned int val = snd_cs4281_rate(runtime->rate, NULL);
- snd_assert(dma->right_slot == chip->src_right_play_slot, );
+ snd_BUG_ON(dma->right_slot != chip->src_right_play_slot);
snd_cs4281_pokeBA0(chip, BA0_DACSR, val);
}
} else {
if (dma->left_slot == chip->src_left_rec_slot) {
unsigned int val = snd_cs4281_rate(runtime->rate, NULL);
- snd_assert(dma->right_slot == chip->src_right_rec_slot, );
+ snd_BUG_ON(dma->right_slot != chip->src_right_rec_slot);
snd_cs4281_pokeBA0(chip, BA0_ADCSR, val);
}
}
struct cs4281_dma *dma = runtime->private_data;
struct cs4281 *chip = snd_pcm_substream_chip(substream);
- // printk("DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n", snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size, jiffies);
+ /*
+ printk(KERN_DEBUG "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n",
+ snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size,
+ jiffies);
+ */
return runtime->buffer_size -
snd_cs4281_peekBA0(chip, dma->regDCC) - 1;
}
static struct snd_pcm_hardware snd_cs4281_playback =
{
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_RESUME |
- SNDRV_PCM_INFO_SYNC_START),
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
static struct snd_pcm_hardware snd_cs4281_capture =
{
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_RESUME |
- SNDRV_PCM_INFO_SYNC_START),
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
dma->right_slot = 1;
runtime->private_data = dma;
runtime->hw = snd_cs4281_playback;
- snd_pcm_set_sync(substream);
/* should be detected from the AC'97 layer, but it seems
that although CS4297A rev B reports 18-bit ADC resolution,
samples are 20-bit */
dma->right_slot = 11;
runtime->private_data = dma;
runtime->hw = snd_cs4281_capture;
- snd_pcm_set_sync(substream);
/* should be detected from the AC'97 layer, but it seems
that although CS4297A rev B reports 18-bit ADC resolution,
samples are 20-bit */
snd_cs4281_pokeBA0(chip, regL, volL);
change = 1;
}
- if (ucontrol->value.integer.value[0] != volL) {
+ if (ucontrol->value.integer.value[1] != volR) {
volR = CS_VOL_MASK - (ucontrol->value.integer.value[1] & CS_VOL_MASK);
snd_cs4281_pokeBA0(chip, regR, volR);
change = 1;
return change;
}
+static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
+
static struct snd_kcontrol_new snd_cs4281_fm_vol =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.get = snd_cs4281_get_volume,
.put = snd_cs4281_put_volume,
.private_value = ((BA0_FMLVC << 16) | BA0_FMRVC),
+ .tlv = { .p = db_scale_dsp },
};
static struct snd_kcontrol_new snd_cs4281_pcm_vol =
.get = snd_cs4281_get_volume,
.put = snd_cs4281_put_volume,
.private_value = ((BA0_PPLVC << 16) | BA0_PPRVC),
+ .tlv = { .p = db_scale_dsp },
};
static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
struct snd_info_entry *entry;
if (! snd_card_proc_new(chip->card, "cs4281", &entry))
- snd_info_set_text_ops(entry, chip, 1024, snd_cs4281_proc_read);
+ snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read);
if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) {
entry->content = SNDRV_INFO_CONTENT_DATA;
entry->private_data = chip;
{
struct cs4281 *chip = gameport_get_port_data(gameport);
- snd_assert(chip, return);
+ if (snd_BUG_ON(!chip))
+ return;
snd_cs4281_pokeBA0(chip, BA0_JSPT, 0xff);
}
{
struct cs4281 *chip = gameport_get_port_data(gameport);
- snd_assert(chip, return 0);
+ if (snd_BUG_ON(!chip))
+ return 0;
return snd_cs4281_peekBA0(chip, BA0_JSPT);
}
struct cs4281 *chip = gameport_get_port_data(gameport);
unsigned js1, js2, jst;
- snd_assert(chip, return 0);
+ if (snd_BUG_ON(!chip))
+ return 0;
js1 = snd_cs4281_peekBA0(chip, BA0_JSC1);
js2 = snd_cs4281_peekBA0(chip, BA0_JSC2);
chip->ba0_addr = pci_resource_start(pci, 0);
chip->ba1_addr = pci_resource_start(pci, 1);
- if (request_irq(pci->irq, snd_cs4281_interrupt, SA_INTERRUPT|SA_SHIRQ,
+ chip->ba0 = pci_ioremap_bar(pci, 0);
+ chip->ba1 = pci_ioremap_bar(pci, 1);
+ if (!chip->ba0 || !chip->ba1) {
+ snd_cs4281_free(chip);
+ return -ENOMEM;
+ }
+
+ if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,
"CS4281", chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_cs4281_free(chip);
}
chip->irq = pci->irq;
- chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0));
- chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1));
- if (!chip->ba0 || !chip->ba1) {
- snd_cs4281_free(chip);
- return -ENOMEM;
- }
-
tmp = snd_cs4281_chip_init(chip);
if (tmp) {
snd_cs4281_free(chip);
static int snd_cs4281_chip_init(struct cs4281 *chip)
{
unsigned int tmp;
- int timeout;
+ unsigned long end_time;
int retry_count = 2;
/* Having EPPMC.FPDN=1 prevent proper chip initialisation */
/*
* Wait for the DLL ready signal from the clock logic.
*/
- timeout = 100;
+ end_time = jiffies + HZ;
do {
/*
* Read the AC97 status register to see if we've seen a CODEC
*/
if (snd_cs4281_peekBA0(chip, BA0_CLKCR1) & BA0_CLKCR1_DLLRDY)
goto __ok0;
- msleep(1);
- } while (timeout-- > 0);
+ schedule_timeout_uninterruptible(1);
+ } while (time_after_eq(end_time, jiffies));
snd_printk(KERN_ERR "DLLRDY not seen\n");
return -EIO;
/*
* Wait for the codec ready signal from the AC97 codec.
*/
- timeout = 100;
+ end_time = jiffies + HZ;
do {
/*
* Read the AC97 status register to see if we've seen a CODEC
*/
if (snd_cs4281_peekBA0(chip, BA0_ACSTS) & BA0_ACSTS_CRDY)
goto __ok1;
- msleep(1);
- } while (timeout-- > 0);
+ schedule_timeout_uninterruptible(1);
+ } while (time_after_eq(end_time, jiffies));
snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS));
return -EIO;
__ok1:
if (chip->dual_codec) {
- timeout = 100;
+ end_time = jiffies + HZ;
do {
if (snd_cs4281_peekBA0(chip, BA0_ACSTS2) & BA0_ACSTS_CRDY)
goto __codec2_ok;
- msleep(1);
- } while (timeout-- > 0);
+ schedule_timeout_uninterruptible(1);
+ } while (time_after_eq(end_time, jiffies));
snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n");
chip->dual_codec = 0;
__codec2_ok: ;
* the codec is pumping ADC data across the AC-link.
*/
- timeout = 100;
+ end_time = jiffies + HZ;
do {
/*
* Read the input slot valid register and see if input slots 3
*/
if ((snd_cs4281_peekBA0(chip, BA0_ACISV) & (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4))) == (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4)))
goto __ok2;
- msleep(1);
- } while (timeout-- > 0);
+ schedule_timeout_uninterruptible(1);
+ } while (time_after_eq(end_time, jiffies));
if (--retry_count > 0)
goto __retry;
* Interrupt handler
*/
-static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id)
{
struct cs4281 *chip = dev_id;
unsigned int status, dma, val;
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_cs4281_create(card, pci, &chip, dual_codec[dev])) < 0) {
snd_card_free(card);
pci_disable_device(pci);
pci_save_state(pci);
+ pci_set_power_state(pci, pci_choose_state(pci, state));
return 0;
}
unsigned int i;
u32 ulCLK;
+ pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
- pci_enable_device(pci);
+ if (pci_enable_device(pci) < 0) {
+ printk(KERN_ERR "cs4281: pci_enable_device failed, "
+ "disabling device\n");
+ snd_card_disconnect(card);
+ return -EIO;
+ }
pci_set_master(pci);
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);