📄 fm801.c
字号:
static snd_pcm_uframes_t snd_fm801_capture_pointer(snd_pcm_substream_t * substream){ fm801_t *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 pt_regs *regs){ fm801_t *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, regs); if (status & FM801_IRQ_VOLUME) ;/* TODO */ return IRQ_HANDLED;}static snd_pcm_hardware_t snd_fm801_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_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 snd_pcm_hardware_t snd_fm801_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_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(snd_pcm_substream_t * substream){ fm801_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *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(snd_pcm_substream_t * substream){ fm801_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *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(snd_pcm_substream_t * substream){ fm801_t *chip = snd_pcm_substream_chip(substream); chip->playback_substream = NULL; return 0;}static int snd_fm801_capture_close(snd_pcm_substream_t * substream){ fm801_t *chip = snd_pcm_substream_chip(substream); chip->capture_substream = NULL; return 0;}static snd_pcm_ops_t 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 snd_pcm_ops_t 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 void snd_fm801_pcm_free(snd_pcm_t *pcm){ fm801_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}static int __devinit snd_fm801_pcm(fm801_t *chip, int device, snd_pcm_t ** rpcm){ snd_pcm_t *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->private_free = snd_fm801_pcm_free; 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(tea575x_t *tea, unsigned int val){ fm801_t *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(tea575x_t *tea){ fm801_t *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)); udelay(1); val <<= 1; if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCS_DATA)) val |= 1; } spin_unlock_irq(&chip->reg_lock); return val;}/* 256PCPR GPIO numbers */#define TEA_256PCPR_BUS_CLOCK 0#define TEA_256PCPR_DATA 1#define TEA_256PCPR_WRITE_ENABLE 2 /* inverted */static void snd_fm801_tea575x_256pcpr_write(tea575x_t *tea, unsigned int val){ fm801_t *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_256PCPR_DATA) | FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) | FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK); /* all of lines are in the write direction */ /* clear data and clock lines */ reg &= ~(FM801_GPIO_GD(TEA_256PCPR_DATA) | FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) | FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) | FM801_GPIO_GP(TEA_256PCPR_DATA) | FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK) | FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE)); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); while (i--) { if (val & (1 << i)) reg |= FM801_GPIO_GP(TEA_256PCPR_DATA); else reg &= ~FM801_GPIO_GP(TEA_256PCPR_DATA); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); } /* and reset the write enable bit */ reg |= FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE) | FM801_GPIO_GP(TEA_256PCPR_DATA); outw(reg, FM801_REG(chip, GPIO_CTRL)); spin_unlock_irq(&chip->reg_lock);}static unsigned int snd_fm801_tea575x_256pcpr_read(tea575x_t *tea){ fm801_t *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_256PCPR_DATA) | FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) | FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK) | FM801_GPIO_GD(TEA_256PCPR_DATA) | FM801_GPIO_GP(TEA_256PCPR_DATA) | FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE); /* all of lines are in the write direction, except data */ /* clear data, write enable and clock lines */ reg &= ~(FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) | FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) | FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK)); for (i = 0; i < 24; i++) { reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); val <<= 1; if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCPR_DATA)) val |= 1; } spin_unlock_irq(&chip->reg_lock); return val;}/* 64PCR GPIO numbers */#define TEA_64PCR_BUS_CLOCK 0#define TEA_64PCR_WRITE_ENABLE 1 /* inverted */#define TEA_64PCR_DATA 2static void snd_fm801_tea575x_64pcr_write(tea575x_t *tea, unsigned int val){ fm801_t *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_64PCR_DATA) | FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) | FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK); /* all of lines are in the write direction */ /* clear data and clock lines */ reg &= ~(FM801_GPIO_GD(TEA_64PCR_DATA) | FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) | FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) | FM801_GPIO_GP(TEA_64PCR_DATA) | FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK) | FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE)); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); while (i--) { if (val & (1 << i)) reg |= FM801_GPIO_GP(TEA_64PCR_DATA); else reg &= ~FM801_GPIO_GP(TEA_64PCR_DATA); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); } /* and reset the write enable bit */ reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE) | FM801_GPIO_GP(TEA_64PCR_DATA); outw(reg, FM801_REG(chip, GPIO_CTRL)); spin_unlock_irq(&chip->reg_lock);}static unsigned int snd_fm801_tea575x_64pcr_read(tea575x_t *tea){ fm801_t *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_64PCR_DATA) | FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) | FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK) | FM801_GPIO_GD(TEA_64PCR_DATA) | FM801_GPIO_GP(TEA_64PCR_DATA) | FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); /* all of lines are in the write direction, except data */ /* clear data, write enable and clock lines */ reg &= ~(FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) | FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) | FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK)); for (i = 0; i < 24; i++) { reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK); outw(reg, FM801_REG(chip, GPIO_CTRL)); udelay(1); val <<= 1; if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_64PCR_DATA)) val |= 1; } spin_unlock_irq(&chip->reg_lock); return val;}static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { { /* 1 = MediaForte 256-PCS */ .write = snd_fm801_tea575x_256pcs_write, .read = snd_fm801_tea575x_256pcs_read, }, { /* 2 = MediaForte 256-PCPR */ .write = snd_fm801_tea575x_256pcpr_write, .read = snd_fm801_tea575x_256pcpr_read, }, { /* 3 = MediaForte 64-PCR */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -