static irqreturn_t snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy) { nm256_t *chip = dev_id; u16 status; u8 cbyte; status = snd_nm256_readw(chip, NM_INT_REG); /* Not ours. */ if (status == 0) { snd_nm256_intr_check(chip); return IRQ_NONE; } chip->badintrcount = 0; /* Rather boring; check for individual interrupts and process them. */ spin_lock(&chip->reg_lock); if (status & NM_PLAYBACK_INT) { status &= ~NM_PLAYBACK_INT; NM_ACK_INT(chip, NM_PLAYBACK_INT); snd_nm256_playback_update(chip); } if (status & NM_RECORD_INT) { status &= ~NM_RECORD_INT; NM_ACK_INT(chip, NM_RECORD_INT); snd_nm256_capture_update(chip); } if (status & NM_MISC_INT_1) { status &= ~NM_MISC_INT_1; NM_ACK_INT(chip, NM_MISC_INT_1); snd_printd("NM256: Got misc interrupt #1\n"); snd_nm256_writew(chip, NM_INT_REG, 0x8000); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte | 2); } if (status & NM_MISC_INT_2) { status &= ~NM_MISC_INT_2; NM_ACK_INT(chip, NM_MISC_INT_2); snd_printd("NM256: Got misc interrupt #2\n"); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte & ~2); } /* Unknown interrupt. */ if (status) { snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n", status); /* Pray. */ NM_ACK_INT(chip, status); } spin_unlock(&chip->reg_lock); return IRQ_HANDLED; }
static irqreturn_t snd_nm256_interrupt(int irq, void *dev_id) { struct nm256 *chip = dev_id; u16 status; u8 cbyte; status = snd_nm256_readw(chip, NM_INT_REG); if (status == 0) return snd_nm256_intr_check(chip); chip->badintrcount = 0; spin_lock(&chip->reg_lock); if (status & NM_PLAYBACK_INT) { status &= ~NM_PLAYBACK_INT; NM_ACK_INT(chip, NM_PLAYBACK_INT); snd_nm256_playback_update(chip); } if (status & NM_RECORD_INT) { status &= ~NM_RECORD_INT; NM_ACK_INT(chip, NM_RECORD_INT); snd_nm256_capture_update(chip); } if (status & NM_MISC_INT_1) { status &= ~NM_MISC_INT_1; NM_ACK_INT(chip, NM_MISC_INT_1); snd_printd("NM256: Got misc interrupt #1\n"); snd_nm256_writew(chip, NM_INT_REG, 0x8000); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte | 2); } if (status & NM_MISC_INT_2) { status &= ~NM_MISC_INT_2; NM_ACK_INT(chip, NM_MISC_INT_2); snd_printd("NM256: Got misc interrupt #2\n"); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte & ~2); } if (status) { snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n", status); NM_ACK_INT(chip, status); } spin_unlock(&chip->reg_lock); return IRQ_HANDLED; }
static void snd_nm256_load_coefficient(struct nm256 *chip, int stream, int number) { /* The enable register for the specified engine. */ u32 poffset = (stream == SNDRV_PCM_STREAM_CAPTURE ? NM_RECORD_ENABLE_REG : NM_PLAYBACK_ENABLE_REG); u32 addr = NM_COEFF_START_OFFSET; addr += (stream == SNDRV_PCM_STREAM_CAPTURE ? NM_RECORD_REG_OFFSET : NM_PLAYBACK_REG_OFFSET); if (snd_nm256_readb(chip, poffset) & 1) { snd_printd("NM256: Engine was enabled while loading coefficients!\n"); return; } /* The recording engine uses coefficient values 8-15. */ number &= 7; if (stream == SNDRV_PCM_STREAM_CAPTURE) number += 8; if (! chip->use_cache) { snd_nm256_load_one_coefficient(chip, stream, addr, number); return; } if (! chip->coeffs_current) { snd_nm256_write_buffer(chip, coefficients, chip->all_coeff_buf, NM_TOTAL_COEFF_COUNT * 4); chip->coeffs_current = 1; } else { u32 base = chip->all_coeff_buf; u32 offset = snd_nm256_get_start_offset(number); u32 end_offset = offset + coefficient_sizes[number]; snd_nm256_writel(chip, addr, base + offset); if (stream == SNDRV_PCM_STREAM_PLAYBACK) end_offset--; snd_nm256_writel(chip, addr + 4, base + end_offset); } }
static int __devinit snd_nm256_create(struct snd_card *card, struct pci_dev *pci, struct nm256 **chip_ret) { struct nm256 *chip; int err, pval; static struct snd_device_ops ops = { .dev_free = snd_nm256_dev_free, }; u32 addr; *chip_ret = NULL; if ((err = pci_enable_device(pci)) < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->use_cache = use_cache; spin_lock_init(&chip->reg_lock); chip->irq = -1; mutex_init(&chip->irq_mutex); /* store buffer sizes in bytes */ chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = playback_bufsize * 1024; chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capture_bufsize * 1024; /* * The NM256 has two memory ports. The first port is nothing * more than a chunk of video RAM, which is used as the I/O ring * buffer. The second port has the actual juicy stuff (like the * mixer and the playback engine control registers). */ chip->buffer_addr = pci_resource_start(pci, 0); chip->cport_addr = pci_resource_start(pci, 1); /* Init the memory port info. */ /* remap control port (#2) */ chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE, card->driver); if (chip->res_cport == NULL) { 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(KERN_ERR "unable to map control port %lx\n", chip->cport_addr); err = -ENOMEM; goto __error; } if (!strcmp(card->driver, "NM256AV")) { /* Ok, try to see if this is a non-AC97 version of the hardware. */ pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE); if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) { if (! force_ac97) { printk(KERN_ERR "nm256: no ac97 is found!\n"); printk(KERN_ERR " force the driver to load by " "passing in the module parameter\n"); printk(KERN_ERR " force_ac97=1\n"); printk(KERN_ERR " or try sb16, opl3sa2, or " "cs423x drivers instead.\n"); err = -ENXIO; goto __error; } } chip->buffer_end = 2560 * 1024; chip->interrupt = snd_nm256_interrupt; chip->mixer_status_offset = NM_MIXER_STATUS_OFFSET; chip->mixer_status_mask = NM_MIXER_READY_MASK; } else { /* Not sure if there is any relevant detect for the ZX or not. */ if (snd_nm256_readb(chip, 0xa0b) != 0) chip->buffer_end = 6144 * 1024; else chip->buffer_end = 4096 * 1024; chip->interrupt = snd_nm256_interrupt_zx; chip->mixer_status_offset = NM2_MIXER_STATUS_OFFSET; chip->mixer_status_mask = NM2_MIXER_READY_MASK; } chip->buffer_size = chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize + chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize; if (chip->use_cache) chip->buffer_size += NM_TOTAL_COEFF_COUNT * 4; else chip->buffer_size += NM_MAX_PLAYBACK_COEF_SIZE + NM_MAX_RECORD_COEF_SIZE; if (buffer_top >= chip->buffer_size && buffer_top < chip->buffer_end) chip->buffer_end = buffer_top; else { /* get buffer end pointer from signature */ if ((err = snd_nm256_peek_for_sig(chip)) < 0) goto __error; } chip->buffer_start = chip->buffer_end - chip->buffer_size; chip->buffer_addr += chip->buffer_start; printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n", chip->buffer_start, chip->buffer_end); chip->res_buffer = request_mem_region(chip->buffer_addr, chip->buffer_size, card->driver); if (chip->res_buffer == NULL) { snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n", chip->buffer_addr, chip->buffer_size); err = -EBUSY; goto __error; } chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size); if (chip->buffer == NULL) { err = -ENOMEM; snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr); goto __error; } /* set offsets */ addr = chip->buffer_start; chip->streams[SNDRV_PCM_STREAM_PLAYBACK].buf = addr; addr += chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize; chip->streams[SNDRV_PCM_STREAM_CAPTURE].buf = addr; addr += chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize; if (chip->use_cache) { chip->all_coeff_buf = addr; } else { chip->coeff_buf[SNDRV_PCM_STREAM_PLAYBACK] = addr; addr += NM_MAX_PLAYBACK_COEF_SIZE; chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr; } /* Fixed setting. */ chip->mixer_base = NM_MIXER_OFFSET; chip->coeffs_current = 0; snd_nm256_init_chip(chip); // pci_set_master(pci); /* needed? */ if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; snd_card_set_dev(card, &pci->dev); *chip_ret = chip; return 0; __error: snd_nm256_free(chip); return err; }
static int __devinit snd_nm256_create(struct snd_card *card, struct pci_dev *pci, struct nm256 **chip_ret) { struct nm256 *chip; int err, pval; static struct snd_device_ops ops = { .dev_free = snd_nm256_dev_free, }; u32 addr; *chip_ret = NULL; if ((err = pci_enable_device(pci)) < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->use_cache = use_cache; spin_lock_init(&chip->reg_lock); chip->irq = -1; mutex_init(&chip->irq_mutex); chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = playback_bufsize * 1024; chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capture_bufsize * 1024; chip->buffer_addr = pci_resource_start(pci, 0); chip->cport_addr = pci_resource_start(pci, 1); chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE, card->driver); if (chip->res_cport == NULL) { 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(KERN_ERR "unable to map control port %lx\n", chip->cport_addr); err = -ENOMEM; goto __error; } if (!strcmp(card->driver, "NM256AV")) { pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE); if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) { if (! force_ac97) { printk(KERN_ERR "nm256: no ac97 is found!\n"); printk(KERN_ERR " force the driver to load by " "passing in the module parameter\n"); printk(KERN_ERR " force_ac97=1\n"); printk(KERN_ERR " or try sb16, opl3sa2, or " "cs423x drivers instead.\n"); err = -ENXIO; goto __error; } } chip->buffer_end = 2560 * 1024; chip->interrupt = snd_nm256_interrupt; chip->mixer_status_offset = NM_MIXER_STATUS_OFFSET; chip->mixer_status_mask = NM_MIXER_READY_MASK; } else { if (snd_nm256_readb(chip, 0xa0b) != 0) chip->buffer_end = 6144 * 1024; else chip->buffer_end = 4096 * 1024; chip->interrupt = snd_nm256_interrupt_zx; chip->mixer_status_offset = NM2_MIXER_STATUS_OFFSET; chip->mixer_status_mask = NM2_MIXER_READY_MASK; } chip->buffer_size = chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize + chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize; if (chip->use_cache) chip->buffer_size += NM_TOTAL_COEFF_COUNT * 4; else chip->buffer_size += NM_MAX_PLAYBACK_COEF_SIZE + NM_MAX_RECORD_COEF_SIZE; if (buffer_top >= chip->buffer_size && buffer_top < chip->buffer_end) chip->buffer_end = buffer_top; else { if ((err = snd_nm256_peek_for_sig(chip)) < 0) goto __error; } chip->buffer_start = chip->buffer_end - chip->buffer_size; chip->buffer_addr += chip->buffer_start; printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n", chip->buffer_start, chip->buffer_end); chip->res_buffer = request_mem_region(chip->buffer_addr, chip->buffer_size, card->driver); if (chip->res_buffer == NULL) { snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n", chip->buffer_addr, chip->buffer_size); err = -EBUSY; goto __error; } chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size); if (chip->buffer == NULL) { err = -ENOMEM; snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr); goto __error; } addr = chip->buffer_start; chip->streams[SNDRV_PCM_STREAM_PLAYBACK].buf = addr; addr += chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize; chip->streams[SNDRV_PCM_STREAM_CAPTURE].buf = addr; addr += chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize; if (chip->use_cache) { chip->all_coeff_buf = addr; } else { chip->coeff_buf[SNDRV_PCM_STREAM_PLAYBACK] = addr; addr += NM_MAX_PLAYBACK_COEF_SIZE; chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr; } chip->mixer_base = NM_MIXER_OFFSET; chip->coeffs_current = 0; snd_nm256_init_chip(chip); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; snd_card_set_dev(card, &pci->dev); *chip_ret = chip; return 0; __error: snd_nm256_free(chip); return err; }