📄 cmipci.c
字号:
snd_cmipci_clear_bit(cm, CM_REG_INT_HLDCLR, mask); snd_cmipci_set_bit(cm, CM_REG_INT_HLDCLR, mask); spin_unlock(&cm->reg_lock); if (cm->rmidi && (status & CM_UARTINT)) snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data, regs); if (cm->pcm) { if ((status & CM_CHINT0) && cm->channel[0].running) snd_pcm_period_elapsed(cm->channel[0].substream); if ((status & CM_CHINT1) && cm->channel[1].running) snd_pcm_period_elapsed(cm->channel[1].substream); } return IRQ_HANDLED;}/* * h/w infos *//* playback on channel A */static snd_pcm_hardware_t snd_cmipci_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, .rate_min = 5512, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), .periods_min = 2, .periods_max = 1024, .fifo_size = 0,};/* capture on channel B */static snd_pcm_hardware_t snd_cmipci_capture ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, .rate_min = 5512, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), .periods_min = 2, .periods_max = 1024, .fifo_size = 0,};/* playback on channel B - stereo 16bit only? */static snd_pcm_hardware_t snd_cmipci_playback2 ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000, .rate_min = 5512, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), .periods_min = 2, .periods_max = 1024, .fifo_size = 0,};/* spdif playback on channel A */static snd_pcm_hardware_t snd_cmipci_playback_spdif ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 44100, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), .periods_min = 2, .periods_max = 1024, .fifo_size = 0,};/* spdif playback on channel A (32bit, IEC958 subframes) */static snd_pcm_hardware_t snd_cmipci_playback_iec958_subframe ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 44100, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), .periods_min = 2, .periods_max = 1024, .fifo_size = 0,};/* spdif capture on channel B */static snd_pcm_hardware_t snd_cmipci_capture_spdif ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 44100, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), .periods_min = 2, .periods_max = 1024, .fifo_size = 0,};/* * check device open/close */static int open_device_check(cmipci_t *cm, int mode, snd_pcm_substream_t *subs){ int ch = mode & CM_OPEN_CH_MASK; /* FIXME: a file should wait until the device becomes free * when it's opened on blocking mode. however, since the current * pcm framework doesn't pass file pointer before actually opened, * we can't know whether blocking mode or not in open callback.. */ down(&cm->open_mutex); if (cm->opened[ch]) { up(&cm->open_mutex); return -EBUSY; } cm->opened[ch] = mode; cm->channel[ch].substream = subs; if (! (mode & CM_OPEN_DAC)) { /* disable dual DAC mode */ cm->channel[ch].is_dac = 0; spin_lock_irq(&cm->reg_lock); snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC); spin_unlock_irq(&cm->reg_lock); } up(&cm->open_mutex); return 0;}static void close_device_check(cmipci_t *cm, int mode){ int ch = mode & CM_OPEN_CH_MASK; down(&cm->open_mutex); if (cm->opened[ch] == mode) { if (cm->channel[ch].substream) { snd_cmipci_ch_reset(cm, ch); cm->channel[ch].running = 0; cm->channel[ch].substream = NULL; } cm->opened[ch] = 0; if (! cm->channel[ch].is_dac) { /* enable dual DAC mode again */ cm->channel[ch].is_dac = 1; spin_lock_irq(&cm->reg_lock); snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC); spin_unlock_irq(&cm->reg_lock); } } up(&cm->open_mutex);}/* */static int snd_cmipci_playback_open(snd_pcm_substream_t *substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; if ((err = open_device_check(cm, CM_OPEN_PLAYBACK, substream)) < 0) return err; runtime->hw = snd_cmipci_playback; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); cm->dig_pcm_status = cm->dig_status; return 0;}static int snd_cmipci_capture_open(snd_pcm_substream_t *substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; if ((err = open_device_check(cm, CM_OPEN_CAPTURE, substream)) < 0) return err; runtime->hw = snd_cmipci_capture; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); return 0;}static int snd_cmipci_playback2_open(snd_pcm_substream_t *substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; if ((err = open_device_check(cm, CM_OPEN_PLAYBACK2, substream)) < 0) /* use channel B */ return err; runtime->hw = snd_cmipci_playback2; down(&cm->open_mutex); if (! cm->opened[CM_CH_PLAY]) { if (cm->can_multi_ch) { runtime->hw.channels_max = cm->max_channels; if (cm->max_channels == 4) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_4); else snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_6); } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); } up(&cm->open_mutex); return 0;}static int snd_cmipci_playback_spdif_open(snd_pcm_substream_t *substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; if ((err = open_device_check(cm, CM_OPEN_SPDIF_PLAYBACK, substream)) < 0) /* use channel A */ return err; if (cm->can_ac3_hw) { runtime->hw = snd_cmipci_playback_spdif; if (cm->chip_version >= 37) runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; } else { runtime->hw = snd_cmipci_playback_iec958_subframe; } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000); cm->dig_pcm_status = cm->dig_status; return 0;}static int snd_cmipci_capture_spdif_open(snd_pcm_substream_t * substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; if ((err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream)) < 0) /* use channel B */ return err; runtime->hw = snd_cmipci_capture_spdif; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000); return 0;}/* */static int snd_cmipci_playback_close(snd_pcm_substream_t * substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); close_device_check(cm, CM_OPEN_PLAYBACK); return 0;}static int snd_cmipci_capture_close(snd_pcm_substream_t * substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); close_device_check(cm, CM_OPEN_CAPTURE); return 0;}static int snd_cmipci_playback2_close(snd_pcm_substream_t * substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); close_device_check(cm, CM_OPEN_PLAYBACK2); close_device_check(cm, CM_OPEN_PLAYBACK_MULTI); return 0;}static int snd_cmipci_playback_spdif_close(snd_pcm_substream_t * substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); close_device_check(cm, CM_OPEN_SPDIF_PLAYBACK); return 0;}static int snd_cmipci_capture_spdif_close(snd_pcm_substream_t * substream){ cmipci_t *cm = snd_pcm_substream_chip(substream); close_device_check(cm, CM_OPEN_SPDIF_CAPTURE); return 0;}/* */static snd_pcm_ops_t snd_cmipci_playback_ops = { .open = snd_cmipci_playback_open, .close = snd_cmipci_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cmipci_hw_params, .hw_free = snd_cmipci_playback_hw_free, .prepare = snd_cmipci_playback_prepare, .trigger = snd_cmipci_playback_trigger, .pointer = snd_cmipci_playback_pointer,};static snd_pcm_ops_t snd_cmipci_capture_ops = { .open = snd_cmipci_capture_open, .close = snd_cmipci_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cmipci_hw_params, .hw_free = snd_cmipci_hw_free, .prepare = snd_cmipci_capture_prepare, .trigger = snd_cmipci_capture_trigger, .pointer = snd_cmipci_capture_pointer,};static snd_pcm_ops_t snd_cmipci_playback2_ops = { .open = snd_cmipci_playback2_open, .close = snd_cmipci_playback2_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cmipci_playback2_hw_params, .hw_free = snd_cmipci_hw_free, .prepare = snd_cmipci_capture_prepare, /* channel B */ .trigger = snd_cmipci_capture_trigger, /* channel B */ .pointer = snd_cmipci_capture_pointer, /* channel B */};static snd_pcm_ops_t snd_cmipci_playback_spdif_ops = { .open = snd_cmipci_playback_spdif_open, .close = snd_cmipci_playback_spdif_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cmipci_hw_params, .hw_free = snd_cmipci_playback_hw_free, .prepare = snd_cmipci_playback_spdif_prepare, /* set up rate */ .trigger = snd_cmipci_playback_trigger, .pointer = snd_cmipci_playback_pointer,};static snd_pcm_ops_t snd_cmipci_capture_spdif_ops = { .open = snd_cmipci_capture_spdif_open, .close = snd_cmipci_capture_spdif_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cmipci_hw_params, .hw_free = snd_cmipci_capture_spdif_hw_free, .prepare = snd_cmipci_capture_spdif_prepare, .trigger = snd_cmipci_capture_trigger, .pointer = snd_cmipci_capture_pointer,};/* */static void snd_cmipci_pcm_free(snd_pcm_t *pcm){ snd_pcm_lib_preallocate_free_for_all(pcm);}static int __devinit snd_cmipci_pcm_new(cmipci_t *cm, int device){ snd_pcm_t *pcm; int err; err = snd_pcm_new(cm->card, cm->card->driver, device, 1, 1, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cmipci_capture_ops); pcm->private_data = cm; pcm->private_free = snd_cmipci_pcm_free; pcm->info_flags = 0; strcpy(pcm->name, "C-Media PCI DAC/ADC"); cm->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(cm->pci), 64*1024, 128*1024); return 0;}static int __devinit snd_cmipci_pcm2_new(cmipci_t *cm, int device){ snd_pcm_t *pcm; int err; err = snd_pcm_new(cm->card, cm->card->driver, device, 1, 0, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cmipci_playback2_ops); pcm->private_data = cm; pcm->private_free = snd_cmipci_pcm_free; pcm->info_flags = 0; strcpy(pcm->name, "C-Media PCI 2nd DAC"); cm->pcm2 = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(cm->pci), 64*1024, 128*1024); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -