X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=sound%2Fpci%2Fnm256%2Fnm256.c;h=e7aa15178453bf6366afaccaa6a1d31737d0eedb;hb=89de09a9ba9ce293228b1f1aa3c68b5af33a70ce;hp=7eb20b8f89f62c160d27f97965b3067e2fd86502;hpb=c1b054d03f5b31c33eaa0b267c629b118eaf3790;p=linux-2.6 diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 7eb20b8f89..e7aa151784 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -52,37 +52,43 @@ MODULE_SUPPORTED_DEVICE("{{NeoMagic,NM256AV}," * some compile conditions. */ -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; -static int playback_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 16}; -static int capture_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 16}; -static int force_ac97[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* disabled as default */ -static int buffer_top[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* not specified */ -static int use_cache[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* disabled */ -static int vaio_hack[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* disabled */ -static int reset_workaround[SNDRV_CARDS]; - -module_param_array(index, int, NULL, 0444); +static int index = SNDRV_DEFAULT_IDX1; /* Index */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int playback_bufsize = 16; +static int capture_bufsize = 16; +static int force_ac97; /* disabled as default */ +static int buffer_top; /* not specified */ +static int use_cache; /* disabled */ +static int vaio_hack; /* disabled */ +static int reset_workaround; +static int reset_workaround_2; + +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable this soundcard."); -module_param_array(playback_bufsize, int, NULL, 0444); +module_param(playback_bufsize, int, 0444); MODULE_PARM_DESC(playback_bufsize, "DAC frame size in kB for " CARD_NAME " soundcard."); -module_param_array(capture_bufsize, int, NULL, 0444); +module_param(capture_bufsize, int, 0444); MODULE_PARM_DESC(capture_bufsize, "ADC frame size in kB for " CARD_NAME " soundcard."); -module_param_array(force_ac97, bool, NULL, 0444); +module_param(force_ac97, bool, 0444); MODULE_PARM_DESC(force_ac97, "Force to use AC97 codec for " CARD_NAME " soundcard."); -module_param_array(buffer_top, int, NULL, 0444); +module_param(buffer_top, int, 0444); MODULE_PARM_DESC(buffer_top, "Set the top address of audio buffer for " CARD_NAME " soundcard."); -module_param_array(use_cache, bool, NULL, 0444); +module_param(use_cache, bool, 0444); MODULE_PARM_DESC(use_cache, "Enable the cache for coefficient table access."); -module_param_array(vaio_hack, bool, NULL, 0444); +module_param(vaio_hack, bool, 0444); MODULE_PARM_DESC(vaio_hack, "Enable workaround for Sony VAIO notebooks."); -module_param_array(reset_workaround, bool, NULL, 0444); +module_param(reset_workaround, bool, 0444); MODULE_PARM_DESC(reset_workaround, "Enable AC97 RESET workaround for some laptops."); +module_param(reset_workaround_2, bool, 0444); +MODULE_PARM_DESC(reset_workaround_2, "Enable extended AC97 RESET workaround for some other laptops."); + +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + + /* * hw definitions @@ -189,6 +195,7 @@ struct snd_nm256_stream { nm256_t *chip; snd_pcm_substream_t *substream; int running; + int suspended; u32 buf; /* offset from chip->buffer */ int bufsize; /* buffer size in bytes */ @@ -225,14 +232,17 @@ struct snd_nm256 { unsigned int coeffs_current: 1; /* coeff. table is loaded? */ unsigned int use_cache: 1; /* use one big coef. table */ unsigned int reset_workaround: 1; /* Workaround for some laptops to avoid freeze */ + unsigned int reset_workaround_2: 1; /* Extended workaround for some other laptops to avoid freeze */ int mixer_base; /* register offset of ac97 mixer */ int mixer_status_offset; /* offset of mixer status reg. */ int mixer_status_mask; /* bit mask to test the mixer status */ int irq; + int irq_acks; irqreturn_t (*interrupt)(int, void *, struct pt_regs *); int badintrcount; /* counter to check bogus interrupts */ + struct semaphore irq_mutex; nm256_stream_t streams[2]; @@ -256,21 +266,6 @@ struct snd_nm256 { /* * PCI ids */ - -#ifndef PCI_VENDOR_ID_NEOMAGIC -#define PCI_VENDOR_ID_NEOMEGIC 0x10c8 -#endif -#ifndef PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO -#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 -#endif -#ifndef PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO -#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 -#endif -#ifndef PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO -#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016 -#endif - - static struct pci_device_id snd_nm256_ids[] = { {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -325,9 +320,9 @@ static inline void snd_nm256_write_buffer(nm256_t *chip, void *src, int offset, int size) { offset -= chip->buffer_start; -#ifdef SNDRV_CONFIG_DEBUG +#ifdef CONFIG_SND_DEBUG if (offset < 0 || offset >= chip->buffer_size) { - snd_printk("write_buffer invalid offset = %d size = %d\n", offset, size); + snd_printk(KERN_ERR "write_buffer invalid offset = %d size = %d\n", offset, size); return; } #endif @@ -464,6 +459,37 @@ snd_nm256_set_format(nm256_t *chip, nm256_stream_t *s, snd_pcm_substream_t *subs } } +/* acquire interrupt */ +static int snd_nm256_acquire_irq(nm256_t *chip) +{ + down(&chip->irq_mutex); + if (chip->irq < 0) { + if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ, + chip->card->driver, (void*)chip)) { + snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq); + up(&chip->irq_mutex); + return -EBUSY; + } + chip->irq = chip->pci->irq; + } + chip->irq_acks++; + up(&chip->irq_mutex); + return 0; +} + +/* release interrupt */ +static void snd_nm256_release_irq(nm256_t *chip) +{ + down(&chip->irq_mutex); + if (chip->irq_acks > 0) + chip->irq_acks--; + if (chip->irq_acks == 0 && chip->irq >= 0) { + free_irq(chip->irq, (void*)chip); + chip->irq = -1; + } + up(&chip->irq_mutex); +} + /* * start / stop */ @@ -538,15 +564,19 @@ snd_nm256_playback_trigger(snd_pcm_substream_t *substream, int cmd) spin_lock(&chip->reg_lock); switch (cmd) { - case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: + s->suspended = 0; + /* fallthru */ + case SNDRV_PCM_TRIGGER_START: if (! s->running) { snd_nm256_playback_start(chip, s, substream); s->running = 1; } break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: + s->suspended = 1; + /* fallthru */ + case SNDRV_PCM_TRIGGER_STOP: if (s->running) { snd_nm256_playback_stop(chip); s->running = 0; @@ -802,7 +832,7 @@ static void snd_nm256_setup_stream(nm256_t *chip, nm256_stream_t *s, runtime->hw = *hw_ptr; runtime->hw.buffer_bytes_max = s->bufsize; runtime->hw.period_bytes_max = s->bufsize / 2; - runtime->dma_area = (void*) s->bufptr; + runtime->dma_area = (void __force *) s->bufptr; runtime->dma_addr = s->bufptr_addr; runtime->dma_bytes = s->bufsize; runtime->private_data = s; @@ -818,6 +848,8 @@ snd_nm256_playback_open(snd_pcm_substream_t *substream) { nm256_t *chip = snd_pcm_substream_chip(substream); + if (snd_nm256_acquire_irq(chip) < 0) + return -EBUSY; snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK], substream, &snd_nm256_playback); return 0; @@ -828,6 +860,8 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream) { nm256_t *chip = snd_pcm_substream_chip(substream); + if (snd_nm256_acquire_irq(chip) < 0) + return -EBUSY; snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE], substream, &snd_nm256_capture); return 0; @@ -839,6 +873,9 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream) static int snd_nm256_playback_close(snd_pcm_substream_t *substream) { + nm256_t *chip = snd_pcm_substream_chip(substream); + + snd_nm256_release_irq(chip); return 0; } @@ -846,6 +883,9 @@ snd_nm256_playback_close(snd_pcm_substream_t *substream) static int snd_nm256_capture_close(snd_pcm_substream_t *substream) { + nm256_t *chip = snd_pcm_substream_chip(substream); + + snd_nm256_release_irq(chip); return 0; } @@ -915,18 +955,16 @@ snd_nm256_pcm(nm256_t *chip, int device) static void snd_nm256_init_chip(nm256_t *chip) { - spin_lock_irq(&chip->reg_lock); /* Reset everything. */ snd_nm256_writeb(chip, 0x0, 0x11); snd_nm256_writew(chip, 0x214, 0); /* stop sounds.. */ //snd_nm256_playback_stop(chip); //snd_nm256_capture_stop(chip); - spin_unlock_irq(&chip->reg_lock); } -static inline void +static irqreturn_t snd_nm256_intr_check(nm256_t *chip) { if (chip->badintrcount++ > 1000) { @@ -947,7 +985,9 @@ snd_nm256_intr_check(nm256_t *chip) if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running) snd_nm256_capture_stop(chip); chip->badintrcount = 0; + return IRQ_HANDLED; } + return IRQ_NONE; } /* @@ -969,10 +1009,8 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy) status = snd_nm256_readw(chip, NM_INT_REG); /* Not ours. */ - if (status == 0) { - snd_nm256_intr_check(chip); - return IRQ_NONE; - } + if (status == 0) + return snd_nm256_intr_check(chip); chip->badintrcount = 0; @@ -1036,10 +1074,8 @@ snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy) status = snd_nm256_readl(chip, NM_INT_REG); /* Not ours. */ - if (status == 0) { - snd_nm256_intr_check(chip); - return IRQ_NONE; - } + if (status == 0) + return snd_nm256_intr_check(chip); chip->badintrcount = 0; @@ -1170,8 +1206,11 @@ snd_nm256_ac97_reset(ac97_t *ac97) /* Dell latitude LS will lock up by this */ snd_nm256_writeb(chip, 0x6cc, 0x87); } - snd_nm256_writeb(chip, 0x6cc, 0x80); - snd_nm256_writeb(chip, 0x6cc, 0x0); + if (! chip->reset_workaround_2) { + /* Dell latitude CSx will lock up by this */ + snd_nm256_writeb(chip, 0x6cc, 0x80); + snd_nm256_writeb(chip, 0x6cc, 0x0); + } } /* create an ac97 mixer interface */ @@ -1192,7 +1231,7 @@ snd_nm256_mixer(nm256_t *chip) AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD, AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL, AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL, - AC97_EXTENDED_ID, + /*AC97_EXTENDED_ID,*/ AC97_VENDOR_ID1, AC97_VENDOR_ID2, -1 }; @@ -1206,6 +1245,7 @@ snd_nm256_mixer(nm256_t *chip) for (i = 0; mixer_regs[i] >= 0; i++) set_bit(mixer_regs[i], ac97.reg_accessed); ac97.private_data = chip; + pbus->no_vra = 1; err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); if (err < 0) return err; @@ -1233,7 +1273,7 @@ snd_nm256_peek_for_sig(nm256_t *chip) temp = ioremap_nocache(chip->buffer_addr + chip->buffer_end - 0x400, 16); if (temp == NULL) { - snd_printk("Unable to scan for card signature in video RAM\n"); + snd_printk(KERN_ERR "Unable to scan for card signature in video RAM\n"); return -EBUSY; } @@ -1247,7 +1287,7 @@ snd_nm256_peek_for_sig(nm256_t *chip) if (pointer == 0xffffffff || pointer < chip->buffer_size || pointer > chip->buffer_end) { - snd_printk("invalid signature found: 0x%x\n", pointer); + snd_printk(KERN_ERR "invalid signature found: 0x%x\n", pointer); iounmap(temp); return -ENODEV; } else { @@ -1281,6 +1321,7 @@ static int nm256_suspend(snd_card_t *card, pm_message_t state) static int nm256_resume(snd_card_t *card) { nm256_t *chip = card->pm_private_data; + int i; /* Perform a full reset on the hardware */ pci_enable_device(chip->pci); @@ -1289,6 +1330,15 @@ static int nm256_resume(snd_card_t *card) /* restore ac97 */ snd_ac97_resume(chip->ac97); + for (i = 0; i < 2; i++) { + nm256_stream_t *s = &chip->streams[i]; + if (s->substream && s->suspended) { + spin_lock_irq(&chip->reg_lock); + snd_nm256_set_format(chip, s, s->substream); + spin_unlock_irq(&chip->reg_lock); + } + } + return 0; } #endif /* CONFIG_PM */ @@ -1307,14 +1357,8 @@ static int snd_nm256_free(nm256_t *chip) iounmap(chip->cport); if (chip->buffer) iounmap(chip->buffer); - if (chip->res_cport) { - release_resource(chip->res_cport); - kfree_nocheck(chip->res_cport); - } - if (chip->res_buffer) { - release_resource(chip->res_buffer); - kfree_nocheck(chip->res_buffer); - } + release_and_free_resource(chip->res_cport); + release_and_free_resource(chip->res_buffer); if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); @@ -1349,7 +1393,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1360,6 +1404,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, chip->use_cache = usecache; spin_lock_init(&chip->reg_lock); chip->irq = -1; + init_MUTEX(&chip->irq_mutex); chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize; chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize; @@ -1379,14 +1424,14 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE, card->driver); if (chip->res_cport == NULL) { - snd_printk("memory region 0x%lx (size 0x%x) busy\n", + snd_printk(KERN_ERR "memory region 0x%lx (size 0x%x) busy\n", chip->cport_addr, NM_PORT2_SIZE); err = -EBUSY; goto __error; } chip->cport = ioremap_nocache(chip->cport_addr, NM_PORT2_SIZE); if (chip->cport == NULL) { - snd_printk("unable to map control port %lx\n", chip->cport_addr); + snd_printk(KERN_ERR "unable to map control port %lx\n", chip->cport_addr); err = -ENOMEM; goto __error; } @@ -1444,7 +1489,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, chip->buffer_size, card->driver); if (chip->res_buffer == NULL) { - snd_printk("nm256: buffer 0x%lx (size 0x%x) busy\n", + snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n", chip->buffer_addr, chip->buffer_size); err = -EBUSY; goto __error; @@ -1452,7 +1497,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size); if (chip->buffer == NULL) { err = -ENOMEM; - snd_printk("unable to map ring buffer at %lx\n", chip->buffer_addr); + snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr); goto __error; } @@ -1470,15 +1515,6 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr; } - /* acquire interrupt */ - if (request_irq(pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ, - card->driver, (void*)chip)) { - err = -EBUSY; - snd_printk("unable to grab IRQ %d\n", pci->irq); - goto __error; - } - chip->irq = pci->irq; - /* Fixed setting. */ chip->mixer_base = NM_MIXER_OFFSET; @@ -1510,7 +1546,7 @@ struct nm256_quirk { int type; }; -enum { NM_BLACKLISTED, NM_RESET_WORKAROUND }; +enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 }; static struct nm256_quirk nm256_quirks[] __devinitdata = { /* HP omnibook 4150 has cs4232 codec internally */ @@ -1519,6 +1555,8 @@ static struct nm256_quirk nm256_quirks[] __devinitdata = { { .vendor = 0x104d, .device = 0x8041, .type = NM_RESET_WORKAROUND }, /* Dell Latitude LS */ { .vendor = 0x1028, .device = 0x0080, .type = NM_RESET_WORKAROUND }, + /* Dell Latitude CSx */ + { .vendor = 0x1028, .device = 0x0091, .type = NM_RESET_WORKAROUND_2 }, { } /* terminator */ }; @@ -1526,7 +1564,6 @@ static struct nm256_quirk nm256_quirks[] __devinitdata = { static int __devinit snd_nm256_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; nm256_t *chip; int err; @@ -1534,13 +1571,6 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, struct nm256_quirk *q; u16 subsystem_vendor, subsystem_device; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); @@ -1550,14 +1580,17 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, case NM_BLACKLISTED: printk(KERN_INFO "nm256: The device is blacklisted. Loading stopped\n"); return -ENODEV; + case NM_RESET_WORKAROUND_2: + reset_workaround_2 = 1; + /* Fall-through */ case NM_RESET_WORKAROUND: - reset_workaround[dev] = 1; + reset_workaround = 1; break; } } } - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; @@ -1572,40 +1605,45 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, strcpy(card->driver, "NM256XL+"); break; default: - snd_printk("invalid device id 0x%x\n", pci->device); + snd_printk(KERN_ERR "invalid device id 0x%x\n", pci->device); snd_card_free(card); return -EINVAL; } - if (vaio_hack[dev]) + if (vaio_hack) xbuffer_top = 0x25a800; /* this avoids conflicts with XFree86 server */ else - xbuffer_top = buffer_top[dev]; - - if (playback_bufsize[dev] < 4) - playback_bufsize[dev] = 4; - if (playback_bufsize[dev] > 128) - playback_bufsize[dev] = 128; - if (capture_bufsize[dev] < 4) - capture_bufsize[dev] = 4; - if (capture_bufsize[dev] > 128) - capture_bufsize[dev] = 128; + xbuffer_top = buffer_top; + + if (playback_bufsize < 4) + playback_bufsize = 4; + if (playback_bufsize > 128) + playback_bufsize = 128; + if (capture_bufsize < 4) + capture_bufsize = 4; + if (capture_bufsize > 128) + capture_bufsize = 128; if ((err = snd_nm256_create(card, pci, - playback_bufsize[dev] * 1024, /* in bytes */ - capture_bufsize[dev] * 1024, /* in bytes */ - force_ac97[dev], + playback_bufsize * 1024, /* in bytes */ + capture_bufsize * 1024, /* in bytes */ + force_ac97, xbuffer_top, - use_cache[dev], + use_cache, &chip)) < 0) { snd_card_free(card); return err; } - if (reset_workaround[dev]) { + if (reset_workaround) { snd_printdd(KERN_INFO "nm256: reset_workaround activated\n"); chip->reset_workaround = 1; } + if (reset_workaround_2) { + snd_printdd(KERN_INFO "nm256: reset_workaround_2 activated\n"); + chip->reset_workaround_2 = 1; + } + if ((err = snd_nm256_pcm(chip, 0)) < 0 || (err = snd_nm256_mixer(chip)) < 0) { snd_card_free(card); @@ -1623,7 +1661,6 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, } pci_set_drvdata(pci, card); - dev++; return 0; } @@ -1636,6 +1673,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "NeoMagic 256", + .owner = THIS_MODULE, .id_table = snd_nm256_ids, .probe = snd_nm256_probe, .remove = __devexit_p(snd_nm256_remove),