📄 nm256.c
字号:
switch (cmd) { 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_SUSPEND: s->suspended = 1; /* fallthru */ case SNDRV_PCM_TRIGGER_STOP: if (s->running) { snd_nm256_playback_stop(chip); s->running = 0; } break; default: err = -EINVAL; break; } spin_unlock(&chip->reg_lock); return err;}static intsnd_nm256_capture_trigger(snd_pcm_substream_t *substream, int cmd){ nm256_t *chip = snd_pcm_substream_chip(substream); nm256_stream_t *s = (nm256_stream_t*)substream->runtime->private_data; int err = 0; snd_assert(s != NULL, return -ENXIO); spin_lock(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (! s->running) { snd_nm256_capture_start(chip, s, substream); s->running = 1; } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (s->running) { snd_nm256_capture_stop(chip); s->running = 0; } break; default: err = -EINVAL; break; } spin_unlock(&chip->reg_lock); return err;}/* * prepare playback/capture channel */static int snd_nm256_pcm_prepare(snd_pcm_substream_t *substream){ nm256_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; nm256_stream_t *s = (nm256_stream_t*)runtime->private_data; snd_assert(s, return -ENXIO); s->dma_size = frames_to_bytes(runtime, substream->runtime->buffer_size); s->period_size = frames_to_bytes(runtime, substream->runtime->period_size); s->periods = substream->runtime->periods; s->cur_period = 0; spin_lock_irq(&chip->reg_lock); s->running = 0; snd_nm256_set_format(chip, s, substream); spin_unlock_irq(&chip->reg_lock); return 0;}/* * get the current pointer */static snd_pcm_uframes_tsnd_nm256_playback_pointer(snd_pcm_substream_t * substream){ nm256_t *chip = snd_pcm_substream_chip(substream); nm256_stream_t *s = (nm256_stream_t*)substream->runtime->private_data; unsigned long curp; snd_assert(s, return 0); curp = snd_nm256_readl(chip, NM_PBUFFER_CURRP) - (unsigned long)s->buf; curp %= s->dma_size; return bytes_to_frames(substream->runtime, curp);}static snd_pcm_uframes_tsnd_nm256_capture_pointer(snd_pcm_substream_t * substream){ nm256_t *chip = snd_pcm_substream_chip(substream); nm256_stream_t *s = (nm256_stream_t*)substream->runtime->private_data; unsigned long curp; snd_assert(s != NULL, return 0); curp = snd_nm256_readl(chip, NM_RBUFFER_CURRP) - (unsigned long)s->buf; curp %= s->dma_size; return bytes_to_frames(substream->runtime, curp);}/* Remapped I/O space can be accessible as pointer on i386 *//* This might be changed in the future */#ifndef __i386__/* * silence / copy for playback */static intsnd_nm256_playback_silence(snd_pcm_substream_t *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, snd_pcm_uframes_t count){ snd_pcm_runtime_t *runtime = substream->runtime; nm256_stream_t *s = (nm256_stream_t*)runtime->private_data; count = frames_to_bytes(runtime, count); pos = frames_to_bytes(runtime, pos); memset_io(s->bufptr + pos, 0, count); return 0;}static intsnd_nm256_playback_copy(snd_pcm_substream_t *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count){ snd_pcm_runtime_t *runtime = substream->runtime; nm256_stream_t *s = (nm256_stream_t*)runtime->private_data; count = frames_to_bytes(runtime, count); pos = frames_to_bytes(runtime, pos); if (copy_from_user_toio(s->bufptr + pos, src, count)) return -EFAULT; return 0;}/* * copy to user */static intsnd_nm256_capture_copy(snd_pcm_substream_t *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count){ snd_pcm_runtime_t *runtime = substream->runtime; nm256_stream_t *s = (nm256_stream_t*)runtime->private_data; count = frames_to_bytes(runtime, count); pos = frames_to_bytes(runtime, pos); if (copy_to_user_fromio(dst, s->bufptr + pos, count)) return -EFAULT; return 0;}#endif /* !__i386__ *//* * update playback/capture watermarks *//* spinlock held! */static voidsnd_nm256_playback_update(nm256_t *chip){ nm256_stream_t *s; s = &chip->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (s->running && s->substream) { spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(s->substream); spin_lock(&chip->reg_lock); snd_nm256_playback_mark(chip, s); }}/* spinlock held! */static voidsnd_nm256_capture_update(nm256_t *chip){ nm256_stream_t *s; s = &chip->streams[SNDRV_PCM_STREAM_CAPTURE]; if (s->running && s->substream) { spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(s->substream); spin_lock(&chip->reg_lock); snd_nm256_capture_mark(chip, s); }}/* * hardware info */static snd_pcm_hardware_t snd_nm256_playback ={ .info = SNDRV_PCM_INFO_MMAP_IOMEM |SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT/*24k*/ | SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .periods_min = 2, .periods_max = 1024, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 256, .period_bytes_max = 128 * 1024,};static snd_pcm_hardware_t snd_nm256_capture ={ .info = SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT/*24k*/ | SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .periods_min = 2, .periods_max = 1024, .buffer_bytes_max = 128 * 1024, .period_bytes_min = 256, .period_bytes_max = 128 * 1024,};/* set dma transfer size */static int snd_nm256_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params){ /* area and addr are already set and unchanged */ substream->runtime->dma_bytes = params_buffer_bytes(hw_params); return 0;}/* * open */static void snd_nm256_setup_stream(nm256_t *chip, nm256_stream_t *s, snd_pcm_substream_t *substream, snd_pcm_hardware_t *hw_ptr){ snd_pcm_runtime_t *runtime = substream->runtime; s->running = 0; runtime->hw = *hw_ptr; runtime->hw.buffer_bytes_max = s->bufsize; runtime->hw.period_bytes_max = s->bufsize / 2; runtime->dma_area = (void __force *) s->bufptr; runtime->dma_addr = s->bufptr_addr; runtime->dma_bytes = s->bufsize; runtime->private_data = s; s->substream = substream; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);}static intsnd_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;}static intsnd_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;}/* * close - we don't have to do special.. */static intsnd_nm256_playback_close(snd_pcm_substream_t *substream){ nm256_t *chip = snd_pcm_substream_chip(substream); snd_nm256_release_irq(chip); return 0;}static intsnd_nm256_capture_close(snd_pcm_substream_t *substream){ nm256_t *chip = snd_pcm_substream_chip(substream); snd_nm256_release_irq(chip); return 0;}/* * create a pcm instance */static snd_pcm_ops_t snd_nm256_playback_ops = { .open = snd_nm256_playback_open, .close = snd_nm256_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_nm256_pcm_hw_params, .prepare = snd_nm256_pcm_prepare, .trigger = snd_nm256_playback_trigger, .pointer = snd_nm256_playback_pointer,#ifndef __i386__ .copy = snd_nm256_playback_copy, .silence = snd_nm256_playback_silence,#endif .mmap = snd_pcm_lib_mmap_iomem,};static snd_pcm_ops_t snd_nm256_capture_ops = { .open = snd_nm256_capture_open, .close = snd_nm256_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_nm256_pcm_hw_params, .prepare = snd_nm256_pcm_prepare, .trigger = snd_nm256_capture_trigger, .pointer = snd_nm256_capture_pointer,#ifndef __i386__ .copy = snd_nm256_capture_copy,#endif .mmap = snd_pcm_lib_mmap_iomem,};static int __devinitsnd_nm256_pcm(nm256_t *chip, int device){ snd_pcm_t *pcm; int i, err; for (i = 0; i < 2; i++) { nm256_stream_t *s = &chip->streams[i]; s->bufptr = chip->buffer + (s->buf - chip->buffer_start); s->bufptr_addr = chip->buffer_addr + (s->buf - chip->buffer_start); } err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_nm256_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_nm256_capture_ops); pcm->private_data = chip; pcm->info_flags = 0; chip->pcm = pcm; return 0;}/* * Initialize the hardware. */static voidsnd_nm256_init_chip(nm256_t *chip){ /* 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);}static irqreturn_tsnd_nm256_intr_check(nm256_t *chip){ if (chip->badintrcount++ > 1000) { /* * I'm not sure if the best thing is to stop the card from * playing or just release the interrupt (after all, we're in * a bad situation, so doing fancy stuff may not be such a good * idea). * * I worry about the card engine continuing to play noise * over and over, however--that could become a very * obnoxious problem. And we know that when this usually * happens things are fairly safe, it just means the user's * inserted a PCMCIA card and someone's spamming us with IRQ 9s. */ if (chip->streams[SNDRV_PCM_STREAM_PLAYBACK].running) snd_nm256_playback_stop(chip); if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running) snd_nm256_capture_stop(chip); chip->badintrcount = 0; return IRQ_HANDLED; } return IRQ_NONE;}/* * Handle a potential interrupt for the device referred to by DEV_ID. * * I don't like the cut-n-paste job here either between the two routines, * but there are sufficient differences between the two interrupt handlers * that parameterizing it isn't all that great either. (Could use a macro, * I suppose...yucky bleah.) */static irqreturn_tsnd_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) return snd_nm256_intr_check(chip); 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;}/* * Handle a potential interrupt for the device referred to by DEV_ID. * This handler is for the 256ZX, and is very similar to the non-ZX * routine. */static irqreturn_tsnd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy){ nm256_t *chip = dev_id; u32 status; u8 cbyte; status = snd_nm256_readl(chip, NM_INT_REG); /* Not ours. */ if (status == 0) return snd_nm256_intr_check(chip); chip->badintrcount = 0; /* Rather boring; check for individual interrupts and process them. */ spin_lock(&chip->reg_lock); if (status & NM2_PLAYBACK_INT) { status &= ~NM2_PLAYBACK_INT; NM2_ACK_INT(chip, NM2_PLAYBACK_INT); snd_nm256_playback_update(chip); } if (status & NM2_RECORD_INT) { status &= ~NM2_RECORD_INT; NM2_ACK_INT(chip, NM2_RECORD_INT); snd_nm256_capture_update(chip); } if (status & NM2_MISC_INT_1) { status &= ~NM2_MISC_INT_1; NM2_ACK_INT(chip, NM2_MISC_INT_1); snd_printd("NM256: Got misc interrupt #1\n"); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte | 2); } if (status & NM2_MISC_INT_2) { status &= ~NM2_MISC_INT_2; NM2_ACK_INT(chip, NM2_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. */ NM2_ACK_INT(chip, status); } spin_unlock(&chip->reg_lock); return IRQ_HANDLED;}/* * AC97 interface *//* * Waits for the mixer to become ready to be written; returns a zero value
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -