Loading sound/pci/ca0106/ca0106.h +14 −1 Original line number Diff line number Diff line Loading @@ -690,7 +690,7 @@ struct snd_ca0106 { spinlock_t emu_lock; struct snd_ac97 *ac97; struct snd_pcm *pcm; struct snd_pcm *pcm[4]; struct snd_ca0106_channel playback_channels[4]; struct snd_ca0106_channel capture_channels[4]; Loading @@ -707,6 +707,11 @@ struct snd_ca0106 { struct snd_ca_midi midi2; u16 spi_dac_reg[16]; #ifdef CONFIG_PM #define NUM_SAVED_VOLUMES 9 unsigned int saved_vol[NUM_SAVED_VOLUMES]; #endif }; int snd_ca0106_mixer(struct snd_ca0106 *emu); Loading @@ -725,3 +730,11 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value); int snd_ca0106_spi_write(struct snd_ca0106 * emu, unsigned int data); #ifdef CONFIG_PM void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip); void snd_ca0106_mixer_resume(struct snd_ca0106 *chip); #else #define snd_ca0106_mixer_suspend(chip) do { } while (0) #define snd_ca0106_mixer_resume(chip) do { } while (0) #endif sound/pci/ca0106/ca0106_main.c +312 −216 Original line number Diff line number Diff line Loading @@ -853,13 +853,16 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, struct snd_pcm_substream *s; u32 basic = 0; u32 extended = 0; u32 bits; int running = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: running = 1; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: default: running = 0; break; Loading @@ -871,22 +874,32 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, runtime = s->runtime; epcm = runtime->private_data; channel = epcm->channel_id; //snd_printk("channel=%d\n",channel); /* snd_printk("channel=%d\n",channel); */ epcm->running = running; basic |= (0x1 << channel); extended |= (0x10 << channel); snd_pcm_trigger_done(s, substream); } //snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); /* snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (extended)); snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(basic)); case SNDRV_PCM_TRIGGER_RESUME: bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0); bits |= extended; snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits); bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0); bits |= basic; snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits); break; case SNDRV_PCM_TRIGGER_STOP: snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(basic)); snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(extended)); case SNDRV_PCM_TRIGGER_SUSPEND: bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0); bits &= ~basic; snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits); bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0); bits &= ~extended; snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits); break; default: result = -EINVAL; Loading Loading @@ -1109,21 +1122,13 @@ static int snd_ca0106_ac97(struct snd_ca0106 *chip) return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } static void ca0106_stop_chip(struct snd_ca0106 *chip); static int snd_ca0106_free(struct snd_ca0106 *chip) { if (chip->res_port != NULL) { /* avoid access to already used hardware */ // disable interrupts snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); outl(0, chip->port + INTE); snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); udelay(1000); // disable audio //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); outl(0, chip->port + HCFG); /* FIXME: We need to stop and DMA transfers here. * But as I am not sure how yet, we cannot from the dma pages. * So we can fix: snd-malloc: Memory leak? pages not freed = 8 */ if (chip->res_port != NULL) { /* avoid access to already used hardware */ ca0106_stop_chip(chip); } if (chip->irq >= 0) free_irq(chip->irq, chip); Loading Loading @@ -1209,15 +1214,14 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; if (rpcm) *rpcm = NULL; if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm); if (err < 0) return err; pcm->private_data = emu; Loading @@ -1244,7 +1248,6 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "CA0106"); emu->pcm = pcm; for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; Loading @@ -1266,8 +1269,7 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s return err; } if (rpcm) *rpcm = pcm; emu->pcm[device] = pcm; return 0; } Loading Loading @@ -1307,89 +1309,10 @@ static unsigned int i2c_adc_init[][2] = { { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ }; static int __devinit snd_ca0106_create(int dev, struct snd_card *card, struct pci_dev *pci, struct snd_ca0106 **rchip) static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) { struct snd_ca0106 *chip; struct snd_ca0106_details *c; int err; int ch; static struct snd_device_ops ops = { .dev_free = snd_ca0106_dev_free, }; *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "error to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->irq = -1; spin_lock_init(&chip->emu_lock); chip->port = pci_resource_start(pci, 0); if ((chip->res_port = request_region(chip->port, 0x20, "snd_ca0106")) == NULL) { snd_ca0106_free(chip); printk(KERN_ERR "cannot allocate the port\n"); return -EBUSY; } if (request_irq(pci->irq, snd_ca0106_interrupt, IRQF_SHARED, "snd_ca0106", chip)) { snd_ca0106_free(chip); printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; /* This stores the periods table. */ if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { snd_ca0106_free(chip); return -ENOMEM; } pci_set_master(pci); /* read serial */ pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); #if 1 printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, pci->revision, chip->serial); #endif strcpy(card->driver, "CA0106"); strcpy(card->shortname, "CA0106"); for (c = ca0106_chip_details; c->serial; c++) { if (subsystem[dev]) { if (c->serial == subsystem[dev]) break; } else if (c->serial == chip->serial) break; } chip->details = c; if (subsystem[dev]) { printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", c->name, chip->serial, subsystem[dev]); } sprintf(card->longname, "%s at 0x%lx irq %i", c->name, chip->port, chip->irq); unsigned int def_bits; outl(0, chip->port + INTE); Loading @@ -1407,31 +1330,22 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, * AN = 0 (Audio data) * P = 0 (Consumer) */ snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0] = def_bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; if (!resume) { chip->spdif_bits[0] = def_bits; chip->spdif_bits[1] = def_bits; chip->spdif_bits[2] = def_bits; chip->spdif_bits[3] = def_bits; } /* Only SPCS1 has been tested */ snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); Loading @@ -1439,92 +1353,124 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, /* Write 0x8000 to AC97_REC_GAIN to mute it. */ outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); outw(0x8000, chip->port + AC97DATA); #if 0 #if 0 /* FIXME: what are these? */ snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); #endif //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ /* OSS drivers set this. */ /* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */ /* Analog or Digital output */ snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. * Use 0x000f0000 for surround71 */ snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); chip->spdif_enable = 0; /* Set digital SPDIF output off */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ /*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */ /*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */ /* goes to 0x40c80000 when doing SPDIF IN/OUT */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* (Mute) CAPTURE feedback into PLAYBACK volume. * Only lower 16 bits matter. */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* SPDIF IN Volume */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); for (ch = 0; ch < 4; ch++) { snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ /* Only high 16 bits matter */ snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ #if 0 /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); #endif } if (chip->details->i2c_adc == 1) { /* Select MIC, Line in, TAD in, AUX in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Default to CAPTURE_SOURCE to i2s in */ if (!resume) chip->capture_source = 3; } else if (chip->details->ac97 == 1) { /* Default to AC97 in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); /* Default to CAPTURE_SOURCE to AC97 in */ if (!resume) chip->capture_source = 4; } else { /* Select MIC, Line in, TAD in, AUX in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Default to Set CAPTURE_SOURCE to i2s in */ if (!resume) chip->capture_source = 3; } if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. * E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. * E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ /* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */ } snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ //outl(0x00000009, chip->port+HCFG); outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ /* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */ /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ /* outl(0x00001409, chip->port+HCFG); */ /* outl(0x00000009, chip->port+HCFG); */ /* AC97 2.0, Enable outputs. */ outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ int size, n; size = ARRAY_SIZE(i2c_adc_init); //snd_printk("I2C:array size=0x%x\n", size); for (n=0; n < size; n++) { snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); } /* snd_printk("I2C:array size=0x%x\n", size); */ for (n = 0; n < size; n++) snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); for (n = 0; n < 4; n++) { chip->i2c_capture_volume[n][0] = 0xcf; chip->i2c_capture_volume[n][1] = 0xcf; } chip->i2c_capture_source = 2; /* Line in */ //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ /* Enable Line-in capture. MIC in currently untested. */ /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ } if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ int size, n; size = ARRAY_SIZE(spi_dac_init); Loading @@ -1536,9 +1482,112 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, chip->spi_dac_reg[reg] = spi_dac_init[n]; } } } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { static void ca0106_stop_chip(struct snd_ca0106 *chip) { /* disable interrupts */ snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); outl(0, chip->port + INTE); snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); udelay(1000); /* disable audio */ /* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */ outl(0, chip->port + HCFG); /* FIXME: We need to stop and DMA transfers here. * But as I am not sure how yet, we cannot from the dma pages. * So we can fix: snd-malloc: Memory leak? pages not freed = 8 */ } static int __devinit snd_ca0106_create(int dev, struct snd_card *card, struct pci_dev *pci, struct snd_ca0106 **rchip) { struct snd_ca0106 *chip; struct snd_ca0106_details *c; int err; static struct snd_device_ops ops = { .dev_free = snd_ca0106_dev_free, }; *rchip = NULL; err = pci_enable_device(pci); if (err < 0) return err; if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "error to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->irq = -1; spin_lock_init(&chip->emu_lock); chip->port = pci_resource_start(pci, 0); chip->res_port = request_region(chip->port, 0x20, "snd_ca0106"); if (!chip->res_port) { snd_ca0106_free(chip); printk(KERN_ERR "cannot allocate the port\n"); return -EBUSY; } if (request_irq(pci->irq, snd_ca0106_interrupt, IRQF_SHARED, "snd_ca0106", chip)) { snd_ca0106_free(chip); printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; /* This stores the periods table. */ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { snd_ca0106_free(chip); return -ENOMEM; } pci_set_master(pci); /* read serial */ pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, pci->revision, chip->serial); strcpy(card->driver, "CA0106"); strcpy(card->shortname, "CA0106"); for (c = ca0106_chip_details; c->serial; c++) { if (subsystem[dev]) { if (c->serial == subsystem[dev]) break; } else if (c->serial == chip->serial) break; } chip->details = c; if (subsystem[dev]) { printk(KERN_INFO "snd-ca0106: Sound card name=%s, " "subsystem=0x%x. Forced to subsystem=0x%x\n", c->name, chip->serial, subsystem[dev]); } sprintf(card->longname, "%s at 0x%lx irq %i", c->name, chip->port, chip->irq); ca0106_init_chip(chip, 0); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { snd_ca0106_free(chip); return err; } Loading Loading @@ -1635,7 +1684,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, static int dev; struct snd_card *card; struct snd_ca0106 *chip; int err; int i, err; if (dev >= SNDRV_CARDS) return -ENODEV; Loading @@ -1648,44 +1697,31 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, if (card == NULL) return -ENOMEM; if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { snd_card_free(card); return err; } err = snd_ca0106_create(dev, card, pci, &chip); if (err < 0) goto error; card->private_data = chip; if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { snd_card_free(card); return err; } if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ if ((err = snd_ca0106_ac97(chip)) < 0) { snd_card_free(card); return err; } for (i = 0; i < 4; i++) { err = snd_ca0106_pcm(chip, i); if (err < 0) goto error; } if ((err = snd_ca0106_mixer(chip)) < 0) { snd_card_free(card); return err; if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ err = snd_ca0106_ac97(chip); if (err < 0) goto error; } err = snd_ca0106_mixer(chip); if (err < 0) goto error; snd_printdd("ca0106: probe for MIDI channel A ..."); if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { snd_card_free(card); snd_printdd(" failed, err=0x%x\n",err); return err; } err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A); if (err < 0) goto error; snd_printdd(" done.\n"); #ifdef CONFIG_PROC_FS Loading @@ -1694,14 +1730,17 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_card_set_dev(card, &pci->dev); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } err = snd_card_register(card); if (err < 0) goto error; pci_set_drvdata(pci, card); dev++; return 0; error: snd_card_free(card); return err; } static void __devexit snd_ca0106_remove(struct pci_dev *pci) Loading @@ -1710,6 +1749,59 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct snd_ca0106 *chip = card->private_data; int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < 4; i++) snd_pcm_suspend_all(chip->pcm[i]); if (chip->details->ac97) snd_ac97_suspend(chip->ac97); snd_ca0106_mixer_suspend(chip); ca0106_stop_chip(chip); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; } static int snd_ca0106_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct snd_ca0106 *chip = card->private_data; int i; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { snd_card_disconnect(card); return -EIO; } pci_set_master(pci); ca0106_init_chip(chip, 1); if (chip->details->ac97) snd_ac97_resume(chip->ac97); snd_ca0106_mixer_resume(chip); if (chip->details->spi_dac) { for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]); } snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif // PCI IDs static struct pci_device_id snd_ca0106_ids[] = { { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ Loading @@ -1723,6 +1815,10 @@ static struct pci_driver driver = { .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove), #ifdef CONFIG_PM .suspend = snd_ca0106_suspend, .resume = snd_ca0106_resume, #endif }; // initialization of the module Loading Loading
sound/pci/ca0106/ca0106.h +14 −1 Original line number Diff line number Diff line Loading @@ -690,7 +690,7 @@ struct snd_ca0106 { spinlock_t emu_lock; struct snd_ac97 *ac97; struct snd_pcm *pcm; struct snd_pcm *pcm[4]; struct snd_ca0106_channel playback_channels[4]; struct snd_ca0106_channel capture_channels[4]; Loading @@ -707,6 +707,11 @@ struct snd_ca0106 { struct snd_ca_midi midi2; u16 spi_dac_reg[16]; #ifdef CONFIG_PM #define NUM_SAVED_VOLUMES 9 unsigned int saved_vol[NUM_SAVED_VOLUMES]; #endif }; int snd_ca0106_mixer(struct snd_ca0106 *emu); Loading @@ -725,3 +730,11 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value); int snd_ca0106_spi_write(struct snd_ca0106 * emu, unsigned int data); #ifdef CONFIG_PM void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip); void snd_ca0106_mixer_resume(struct snd_ca0106 *chip); #else #define snd_ca0106_mixer_suspend(chip) do { } while (0) #define snd_ca0106_mixer_resume(chip) do { } while (0) #endif
sound/pci/ca0106/ca0106_main.c +312 −216 Original line number Diff line number Diff line Loading @@ -853,13 +853,16 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, struct snd_pcm_substream *s; u32 basic = 0; u32 extended = 0; u32 bits; int running = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: running = 1; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: default: running = 0; break; Loading @@ -871,22 +874,32 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, runtime = s->runtime; epcm = runtime->private_data; channel = epcm->channel_id; //snd_printk("channel=%d\n",channel); /* snd_printk("channel=%d\n",channel); */ epcm->running = running; basic |= (0x1 << channel); extended |= (0x10 << channel); snd_pcm_trigger_done(s, substream); } //snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); /* snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (extended)); snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(basic)); case SNDRV_PCM_TRIGGER_RESUME: bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0); bits |= extended; snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits); bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0); bits |= basic; snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits); break; case SNDRV_PCM_TRIGGER_STOP: snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(basic)); snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(extended)); case SNDRV_PCM_TRIGGER_SUSPEND: bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0); bits &= ~basic; snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits); bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0); bits &= ~extended; snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits); break; default: result = -EINVAL; Loading Loading @@ -1109,21 +1122,13 @@ static int snd_ca0106_ac97(struct snd_ca0106 *chip) return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } static void ca0106_stop_chip(struct snd_ca0106 *chip); static int snd_ca0106_free(struct snd_ca0106 *chip) { if (chip->res_port != NULL) { /* avoid access to already used hardware */ // disable interrupts snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); outl(0, chip->port + INTE); snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); udelay(1000); // disable audio //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); outl(0, chip->port + HCFG); /* FIXME: We need to stop and DMA transfers here. * But as I am not sure how yet, we cannot from the dma pages. * So we can fix: snd-malloc: Memory leak? pages not freed = 8 */ if (chip->res_port != NULL) { /* avoid access to already used hardware */ ca0106_stop_chip(chip); } if (chip->irq >= 0) free_irq(chip->irq, chip); Loading Loading @@ -1209,15 +1214,14 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; if (rpcm) *rpcm = NULL; if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm); if (err < 0) return err; pcm->private_data = emu; Loading @@ -1244,7 +1248,6 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "CA0106"); emu->pcm = pcm; for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; Loading @@ -1266,8 +1269,7 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s return err; } if (rpcm) *rpcm = pcm; emu->pcm[device] = pcm; return 0; } Loading Loading @@ -1307,89 +1309,10 @@ static unsigned int i2c_adc_init[][2] = { { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ }; static int __devinit snd_ca0106_create(int dev, struct snd_card *card, struct pci_dev *pci, struct snd_ca0106 **rchip) static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) { struct snd_ca0106 *chip; struct snd_ca0106_details *c; int err; int ch; static struct snd_device_ops ops = { .dev_free = snd_ca0106_dev_free, }; *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "error to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->irq = -1; spin_lock_init(&chip->emu_lock); chip->port = pci_resource_start(pci, 0); if ((chip->res_port = request_region(chip->port, 0x20, "snd_ca0106")) == NULL) { snd_ca0106_free(chip); printk(KERN_ERR "cannot allocate the port\n"); return -EBUSY; } if (request_irq(pci->irq, snd_ca0106_interrupt, IRQF_SHARED, "snd_ca0106", chip)) { snd_ca0106_free(chip); printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; /* This stores the periods table. */ if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { snd_ca0106_free(chip); return -ENOMEM; } pci_set_master(pci); /* read serial */ pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); #if 1 printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, pci->revision, chip->serial); #endif strcpy(card->driver, "CA0106"); strcpy(card->shortname, "CA0106"); for (c = ca0106_chip_details; c->serial; c++) { if (subsystem[dev]) { if (c->serial == subsystem[dev]) break; } else if (c->serial == chip->serial) break; } chip->details = c; if (subsystem[dev]) { printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", c->name, chip->serial, subsystem[dev]); } sprintf(card->longname, "%s at 0x%lx irq %i", c->name, chip->port, chip->irq); unsigned int def_bits; outl(0, chip->port + INTE); Loading @@ -1407,31 +1330,22 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, * AN = 0 (Audio data) * P = 0 (Consumer) */ snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0] = def_bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; if (!resume) { chip->spdif_bits[0] = def_bits; chip->spdif_bits[1] = def_bits; chip->spdif_bits[2] = def_bits; chip->spdif_bits[3] = def_bits; } /* Only SPCS1 has been tested */ snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); Loading @@ -1439,92 +1353,124 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, /* Write 0x8000 to AC97_REC_GAIN to mute it. */ outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); outw(0x8000, chip->port + AC97DATA); #if 0 #if 0 /* FIXME: what are these? */ snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); #endif //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ /* OSS drivers set this. */ /* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */ /* Analog or Digital output */ snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. * Use 0x000f0000 for surround71 */ snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); chip->spdif_enable = 0; /* Set digital SPDIF output off */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ /*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */ /*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */ /* goes to 0x40c80000 when doing SPDIF IN/OUT */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* (Mute) CAPTURE feedback into PLAYBACK volume. * Only lower 16 bits matter. */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* SPDIF IN Volume */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); for (ch = 0; ch < 4; ch++) { snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ /* Only high 16 bits matter */ snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ #if 0 /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); #endif } if (chip->details->i2c_adc == 1) { /* Select MIC, Line in, TAD in, AUX in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Default to CAPTURE_SOURCE to i2s in */ if (!resume) chip->capture_source = 3; } else if (chip->details->ac97 == 1) { /* Default to AC97 in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); /* Default to CAPTURE_SOURCE to AC97 in */ if (!resume) chip->capture_source = 4; } else { /* Select MIC, Line in, TAD in, AUX in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Default to Set CAPTURE_SOURCE to i2s in */ if (!resume) chip->capture_source = 3; } if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. * E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. * E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ /* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */ } snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ //outl(0x00000009, chip->port+HCFG); outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ /* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */ /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ /* outl(0x00001409, chip->port+HCFG); */ /* outl(0x00000009, chip->port+HCFG); */ /* AC97 2.0, Enable outputs. */ outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ int size, n; size = ARRAY_SIZE(i2c_adc_init); //snd_printk("I2C:array size=0x%x\n", size); for (n=0; n < size; n++) { snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); } /* snd_printk("I2C:array size=0x%x\n", size); */ for (n = 0; n < size; n++) snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); for (n = 0; n < 4; n++) { chip->i2c_capture_volume[n][0] = 0xcf; chip->i2c_capture_volume[n][1] = 0xcf; } chip->i2c_capture_source = 2; /* Line in */ //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ /* Enable Line-in capture. MIC in currently untested. */ /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ } if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ int size, n; size = ARRAY_SIZE(spi_dac_init); Loading @@ -1536,9 +1482,112 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, chip->spi_dac_reg[reg] = spi_dac_init[n]; } } } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { static void ca0106_stop_chip(struct snd_ca0106 *chip) { /* disable interrupts */ snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); outl(0, chip->port + INTE); snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); udelay(1000); /* disable audio */ /* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */ outl(0, chip->port + HCFG); /* FIXME: We need to stop and DMA transfers here. * But as I am not sure how yet, we cannot from the dma pages. * So we can fix: snd-malloc: Memory leak? pages not freed = 8 */ } static int __devinit snd_ca0106_create(int dev, struct snd_card *card, struct pci_dev *pci, struct snd_ca0106 **rchip) { struct snd_ca0106 *chip; struct snd_ca0106_details *c; int err; static struct snd_device_ops ops = { .dev_free = snd_ca0106_dev_free, }; *rchip = NULL; err = pci_enable_device(pci); if (err < 0) return err; if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "error to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->irq = -1; spin_lock_init(&chip->emu_lock); chip->port = pci_resource_start(pci, 0); chip->res_port = request_region(chip->port, 0x20, "snd_ca0106"); if (!chip->res_port) { snd_ca0106_free(chip); printk(KERN_ERR "cannot allocate the port\n"); return -EBUSY; } if (request_irq(pci->irq, snd_ca0106_interrupt, IRQF_SHARED, "snd_ca0106", chip)) { snd_ca0106_free(chip); printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; /* This stores the periods table. */ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { snd_ca0106_free(chip); return -ENOMEM; } pci_set_master(pci); /* read serial */ pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, pci->revision, chip->serial); strcpy(card->driver, "CA0106"); strcpy(card->shortname, "CA0106"); for (c = ca0106_chip_details; c->serial; c++) { if (subsystem[dev]) { if (c->serial == subsystem[dev]) break; } else if (c->serial == chip->serial) break; } chip->details = c; if (subsystem[dev]) { printk(KERN_INFO "snd-ca0106: Sound card name=%s, " "subsystem=0x%x. Forced to subsystem=0x%x\n", c->name, chip->serial, subsystem[dev]); } sprintf(card->longname, "%s at 0x%lx irq %i", c->name, chip->port, chip->irq); ca0106_init_chip(chip, 0); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { snd_ca0106_free(chip); return err; } Loading Loading @@ -1635,7 +1684,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, static int dev; struct snd_card *card; struct snd_ca0106 *chip; int err; int i, err; if (dev >= SNDRV_CARDS) return -ENODEV; Loading @@ -1648,44 +1697,31 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, if (card == NULL) return -ENOMEM; if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { snd_card_free(card); return err; } err = snd_ca0106_create(dev, card, pci, &chip); if (err < 0) goto error; card->private_data = chip; if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { snd_card_free(card); return err; } if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ if ((err = snd_ca0106_ac97(chip)) < 0) { snd_card_free(card); return err; } for (i = 0; i < 4; i++) { err = snd_ca0106_pcm(chip, i); if (err < 0) goto error; } if ((err = snd_ca0106_mixer(chip)) < 0) { snd_card_free(card); return err; if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ err = snd_ca0106_ac97(chip); if (err < 0) goto error; } err = snd_ca0106_mixer(chip); if (err < 0) goto error; snd_printdd("ca0106: probe for MIDI channel A ..."); if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { snd_card_free(card); snd_printdd(" failed, err=0x%x\n",err); return err; } err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A); if (err < 0) goto error; snd_printdd(" done.\n"); #ifdef CONFIG_PROC_FS Loading @@ -1694,14 +1730,17 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_card_set_dev(card, &pci->dev); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } err = snd_card_register(card); if (err < 0) goto error; pci_set_drvdata(pci, card); dev++; return 0; error: snd_card_free(card); return err; } static void __devexit snd_ca0106_remove(struct pci_dev *pci) Loading @@ -1710,6 +1749,59 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct snd_ca0106 *chip = card->private_data; int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < 4; i++) snd_pcm_suspend_all(chip->pcm[i]); if (chip->details->ac97) snd_ac97_suspend(chip->ac97); snd_ca0106_mixer_suspend(chip); ca0106_stop_chip(chip); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; } static int snd_ca0106_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct snd_ca0106 *chip = card->private_data; int i; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { snd_card_disconnect(card); return -EIO; } pci_set_master(pci); ca0106_init_chip(chip, 1); if (chip->details->ac97) snd_ac97_resume(chip->ac97); snd_ca0106_mixer_resume(chip); if (chip->details->spi_dac) { for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]); } snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif // PCI IDs static struct pci_device_id snd_ca0106_ids[] = { { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ Loading @@ -1723,6 +1815,10 @@ static struct pci_driver driver = { .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove), #ifdef CONFIG_PM .suspend = snd_ca0106_suspend, .resume = snd_ca0106_resume, #endif }; // initialization of the module Loading