📄 fm801.c
字号:
break; case SNDRV_PCM_TRIGGER_STOP: chip->cap_ctrl &= ~(FM801_START | FM801_PAUSE); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: chip->cap_ctrl |= FM801_PAUSE; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: chip->cap_ctrl &= ~FM801_PAUSE; break; default: spin_unlock(&chip->reg_lock); snd_BUG(); return -EINVAL; } outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL)); spin_unlock(&chip->reg_lock); return 0;}static int snd_fm801_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_fm801_hw_free(struct snd_pcm_substream *substream){ return snd_pcm_lib_free_pages(substream);}static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream){ struct fm801 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; chip->ply_size = snd_pcm_lib_buffer_bytes(substream); chip->ply_count = snd_pcm_lib_period_bytes(substream); spin_lock_irq(&chip->reg_lock); chip->ply_ctrl &= ~(FM801_START | FM801_16BIT | FM801_STEREO | FM801_RATE_MASK | FM801_CHANNELS_MASK); if (snd_pcm_format_width(runtime->format) == 16) chip->ply_ctrl |= FM801_16BIT; if (runtime->channels > 1) { chip->ply_ctrl |= FM801_STEREO; if (runtime->channels == 4) chip->ply_ctrl |= FM801_CHANNELS_4; else if (runtime->channels == 6) chip->ply_ctrl |= FM801_CHANNELS_6; } chip->ply_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT; chip->ply_buf = 0; outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL)); outw(chip->ply_count - 1, FM801_REG(chip, PLY_COUNT)); chip->ply_buffer = runtime->dma_addr; chip->ply_pos = 0; outl(chip->ply_buffer, FM801_REG(chip, PLY_BUF1)); outl(chip->ply_buffer + (chip->ply_count % chip->ply_size), FM801_REG(chip, PLY_BUF2)); spin_unlock_irq(&chip->reg_lock); return 0;}static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream){ struct fm801 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; chip->cap_size = snd_pcm_lib_buffer_bytes(substream); chip->cap_count = snd_pcm_lib_period_bytes(substream); spin_lock_irq(&chip->reg_lock); chip->cap_ctrl &= ~(FM801_START | FM801_16BIT | FM801_STEREO | FM801_RATE_MASK); if (snd_pcm_format_width(runtime->format) == 16) chip->cap_ctrl |= FM801_16BIT; if (runtime->channels > 1) chip->cap_ctrl |= FM801_STEREO; chip->cap_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT; chip->cap_buf = 0; outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL)); outw(chip->cap_count - 1, FM801_REG(chip, CAP_COUNT)); chip->cap_buffer = runtime->dma_addr; chip->cap_pos = 0; outl(chip->cap_buffer, FM801_REG(chip, CAP_BUF1)); outl(chip->cap_buffer + (chip->cap_count % chip->cap_size), FM801_REG(chip, CAP_BUF2)); spin_unlock_irq(&chip->reg_lock); return 0;}static snd_pcm_uframes_t snd_fm801_playback_pointer(struct snd_pcm_substream *substream){ struct fm801 *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->ply_ctrl & FM801_START)) return 0; spin_lock(&chip->reg_lock); ptr = chip->ply_pos + (chip->ply_count - 1) - inw(FM801_REG(chip, PLY_COUNT)); if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_PLAYBACK) { ptr += chip->ply_count; ptr %= chip->ply_size; } spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *substream){ struct fm801 *chip = snd_pcm_substream_chip(substream); size_t ptr; if (!(chip->cap_ctrl & FM801_START)) return 0; spin_lock(&chip->reg_lock); ptr = chip->cap_pos + (chip->cap_count - 1) - inw(FM801_REG(chip, CAP_COUNT)); if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_CAPTURE) { ptr += chip->cap_count; ptr %= chip->cap_size; } spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, ptr);}static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id){ struct fm801 *chip = dev_id; unsigned short status; unsigned int tmp; status = inw(FM801_REG(chip, IRQ_STATUS)); status &= FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU|FM801_IRQ_VOLUME; if (! status) return IRQ_NONE; /* ack first */ outw(status, FM801_REG(chip, IRQ_STATUS)); if (chip->pcm && (status & FM801_IRQ_PLAYBACK) && chip->playback_substream) { spin_lock(&chip->reg_lock); chip->ply_buf++; chip->ply_pos += chip->ply_count; chip->ply_pos %= chip->ply_size; tmp = chip->ply_pos + chip->ply_count; tmp %= chip->ply_size; outl(chip->ply_buffer + tmp, (chip->ply_buf & 1) ? FM801_REG(chip, PLY_BUF1) : FM801_REG(chip, PLY_BUF2)); spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(chip->playback_substream); } if (chip->pcm && (status & FM801_IRQ_CAPTURE) && chip->capture_substream) { spin_lock(&chip->reg_lock); chip->cap_buf++; chip->cap_pos += chip->cap_count; chip->cap_pos %= chip->cap_size; tmp = chip->cap_pos + chip->cap_count; tmp %= chip->cap_size; outl(chip->cap_buffer + tmp, (chip->cap_buf & 1) ? FM801_REG(chip, CAP_BUF1) : FM801_REG(chip, CAP_BUF2)); spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(chip->capture_substream); } if (chip->rmidi && (status & FM801_IRQ_MPU)) snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); if (status & FM801_IRQ_VOLUME) ;/* TODO */ return IRQ_HANDLED;}static struct snd_pcm_hardware snd_fm801_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rate_min = 5500, .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 = 1, .periods_max = 1024, .fifo_size = 0,};static struct snd_pcm_hardware snd_fm801_capture ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rate_min = 5500, .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 = 1, .periods_max = 1024, .fifo_size = 0,};static int snd_fm801_playback_open(struct snd_pcm_substream *substream){ struct fm801 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; chip->playback_substream = substream; runtime->hw = snd_fm801_playback; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); if (chip->multichannel) { runtime->hw.channels_max = 6; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels); } if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; return 0;}static int snd_fm801_capture_open(struct snd_pcm_substream *substream){ struct fm801 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; chip->capture_substream = substream; runtime->hw = snd_fm801_capture; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; return 0;}static int snd_fm801_playback_close(struct snd_pcm_substream *substream){ struct fm801 *chip = snd_pcm_substream_chip(substream); chip->playback_substream = NULL; return 0;}static int snd_fm801_capture_close(struct snd_pcm_substream *substream){ struct fm801 *chip = snd_pcm_substream_chip(substream); chip->capture_substream = NULL; return 0;}static struct snd_pcm_ops snd_fm801_playback_ops = { .open = snd_fm801_playback_open, .close = snd_fm801_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_fm801_hw_params, .hw_free = snd_fm801_hw_free, .prepare = snd_fm801_playback_prepare, .trigger = snd_fm801_playback_trigger, .pointer = snd_fm801_playback_pointer,};static struct snd_pcm_ops snd_fm801_capture_ops = { .open = snd_fm801_capture_open, .close = snd_fm801_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_fm801_hw_params, .hw_free = snd_fm801_hw_free, .prepare = snd_fm801_capture_prepare, .trigger = snd_fm801_capture_trigger, .pointer = snd_fm801_capture_pointer,};static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm ** rpcm){ struct snd_pcm *pcm; int err; if (rpcm) *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm)) < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_fm801_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_fm801_capture_ops); pcm->private_data = chip; pcm->info_flags = 0; strcpy(pcm->name, "FM801"); chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), chip->multichannel ? 128*1024 : 64*1024, 128*1024); if (rpcm) *rpcm = pcm; return 0;}/* * TEA5757 radio */#ifdef TEA575X_RADIO/* 256PCS GPIO numbers */#define TEA_256PCS_DATA 1#define TEA_256PCS_WRITE_ENABLE 2 /* inverted */#define TEA_256PCS_BUS_CLOCK 3static void snd_fm801_tea575x_256pcs_write(struct snd_tea575x *tea, unsigned int val){ struct fm801 *chip = tea->private_data; unsigned short reg; int i = 25; spin_lock_irq(&chip->reg_lock); reg = inw(FM801_REG(chip, GPIO_CTRL)); /* use GPIO lines and set write enable bit */ reg |= FM801_GPIO_GS(TEA_256PCS_DATA) | FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) | FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK); /* all of lines are in the write direction */ /* clear data and clock lines */ reg &= ~(FM801_GPIO_GD(TEA_256PCS_DATA) | FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) | FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) | FM801_GPIO_GP(TEA_256PCS_DATA) | FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK) | FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE)); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); while (i--) { if (val & (1 << i)) reg |= FM801_GPIO_GP(TEA_256PCS_DATA); else reg &= ~FM801_GPIO_GP(TEA_256PCS_DATA); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); } /* and reset the write enable bit */ reg |= FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE) | FM801_GPIO_GP(TEA_256PCS_DATA); outw(reg, FM801_REG(chip, GPIO_CTRL)); spin_unlock_irq(&chip->reg_lock);}static unsigned int snd_fm801_tea575x_256pcs_read(struct snd_tea575x *tea){ struct fm801 *chip = tea->private_data; unsigned short reg; unsigned int val = 0; int i; spin_lock_irq(&chip->reg_lock); reg = inw(FM801_REG(chip, GPIO_CTRL)); /* use GPIO lines, set data direction to input */ reg |= FM801_GPIO_GS(TEA_256PCS_DATA) | FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) | FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK) | FM801_GPIO_GD(TEA_256PCS_DATA) | FM801_GPIO_GP(TEA_256PCS_DATA) | FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE); /* all of lines are in the write direction, except data */ /* clear data, write enable and clock lines */ reg &= ~(FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) | FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) | FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK)); for (i = 0; i < 24; i++) { reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -