📄 maestro3.c
字号:
case 0xaa: /* volume up */ if ((val & 0x7f) > 0) val--; if ((val & 0x7f00) > 0) val -= 0x0100; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); break; case 0x66: /* volume down */ if ((val & 0x7f) < 0x1f) val++; if ((val & 0x7f00) < 0x1f00) val += 0x0100; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); break; } spin_unlock_irqrestore(&chip->ac97_lock, flags);}static irqreturn_t snd_m3_interrupt(int irq, void *dev_id){ struct snd_m3 *chip = dev_id; u8 status; int i; status = inb(chip->iobase + HOST_INT_STATUS); if (status == 0xff) return IRQ_NONE; if (status & HV_INT_PENDING) tasklet_hi_schedule(&chip->hwvol_tq); /* * ack an assp int if its running * and has an int pending */ if (status & ASSP_INT_PENDING) { u8 ctl = inb(chip->iobase + ASSP_CONTROL_B); if (!(ctl & STOP_ASSP_CLOCK)) { ctl = inb(chip->iobase + ASSP_HOST_INT_STATUS); if (ctl & DSP2HOST_REQ_TIMER) { outb(DSP2HOST_REQ_TIMER, chip->iobase + ASSP_HOST_INT_STATUS); /* update adc/dac info if it was a timer int */ spin_lock(&chip->reg_lock); for (i = 0; i < chip->num_substreams; i++) { struct m3_dma *s = &chip->substreams[i]; if (s->running) snd_m3_update_ptr(chip, s); } spin_unlock(&chip->reg_lock); } } }#if 0 /* TODO: not supported yet */ if ((status & MPU401_INT_PENDING) && chip->rmidi) snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);#endif /* ack ints */ outb(status, chip->iobase + HOST_INT_STATUS); return IRQ_HANDLED;}/* */static struct snd_pcm_hardware snd_m3_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (512*1024), .period_bytes_min = 64, .period_bytes_max = (512*1024), .periods_min = 1, .periods_max = 1024,};static struct snd_pcm_hardware snd_m3_capture ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (512*1024), .period_bytes_min = 64, .period_bytes_max = (512*1024), .periods_min = 1, .periods_max = 1024,};/* */static intsnd_m3_substream_open(struct snd_m3 *chip, struct snd_pcm_substream *subs){ int i; struct m3_dma *s; spin_lock_irq(&chip->reg_lock); for (i = 0; i < chip->num_substreams; i++) { s = &chip->substreams[i]; if (! s->opened) goto __found; } spin_unlock_irq(&chip->reg_lock); return -ENOMEM;__found: s->opened = 1; s->running = 0; spin_unlock_irq(&chip->reg_lock); subs->runtime->private_data = s; s->substream = subs; /* set list owners */ if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) { s->index_list[0] = &chip->mixer_list; } else s->index_list[0] = &chip->adc1_list; s->index_list[1] = &chip->msrc_list; s->index_list[2] = &chip->dma_list; return 0;}static voidsnd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs){ struct m3_dma *s = subs->runtime->private_data; if (s == NULL) return; /* not opened properly */ spin_lock_irq(&chip->reg_lock); if (s->substream && s->running) snd_m3_pcm_stop(chip, s, s->substream); /* does this happen? */ if (s->in_lists) { snd_m3_remove_list(chip, s->index_list[0], s->index[0]); snd_m3_remove_list(chip, s->index_list[1], s->index[1]); snd_m3_remove_list(chip, s->index_list[2], s->index[2]); s->in_lists = 0; } s->running = 0; s->opened = 0; spin_unlock_irq(&chip->reg_lock);}static intsnd_m3_playback_open(struct snd_pcm_substream *subs){ struct snd_m3 *chip = snd_pcm_substream_chip(subs); struct snd_pcm_runtime *runtime = subs->runtime; int err; if ((err = snd_m3_substream_open(chip, subs)) < 0) return err; runtime->hw = snd_m3_playback; return 0;}static intsnd_m3_playback_close(struct snd_pcm_substream *subs){ struct snd_m3 *chip = snd_pcm_substream_chip(subs); snd_m3_substream_close(chip, subs); return 0;}static intsnd_m3_capture_open(struct snd_pcm_substream *subs){ struct snd_m3 *chip = snd_pcm_substream_chip(subs); struct snd_pcm_runtime *runtime = subs->runtime; int err; if ((err = snd_m3_substream_open(chip, subs)) < 0) return err; runtime->hw = snd_m3_capture; return 0;}static intsnd_m3_capture_close(struct snd_pcm_substream *subs){ struct snd_m3 *chip = snd_pcm_substream_chip(subs); snd_m3_substream_close(chip, subs); return 0;}/* * create pcm instance */static struct snd_pcm_ops snd_m3_playback_ops = { .open = snd_m3_playback_open, .close = snd_m3_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_m3_pcm_hw_params, .hw_free = snd_m3_pcm_hw_free, .prepare = snd_m3_pcm_prepare, .trigger = snd_m3_pcm_trigger, .pointer = snd_m3_pcm_pointer,};static struct snd_pcm_ops snd_m3_capture_ops = { .open = snd_m3_capture_open, .close = snd_m3_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_m3_pcm_hw_params, .hw_free = snd_m3_pcm_hw_free, .prepare = snd_m3_pcm_prepare, .trigger = snd_m3_pcm_trigger, .pointer = snd_m3_pcm_pointer,};static int __devinitsnd_m3_pcm(struct snd_m3 * chip, int device){ struct snd_pcm *pcm; int err; err = snd_pcm_new(chip->card, chip->card->driver, device, MAX_PLAYBACKS, MAX_CAPTURES, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_m3_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_m3_capture_ops); pcm->private_data = chip; pcm->info_flags = 0; strcpy(pcm->name, chip->card->driver); chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 64*1024); return 0;}/* * ac97 interface *//* * Wait for the ac97 serial bus to be free. * return nonzero if the bus is still busy. */static int snd_m3_ac97_wait(struct snd_m3 *chip){ int i = 10000; do { if (! (snd_m3_inb(chip, 0x30) & 1)) return 0; cpu_relax(); } while (i-- > 0); snd_printk(KERN_ERR "ac97 serial bus busy\n"); return 1;}static unsigned shortsnd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg){ struct snd_m3 *chip = ac97->private_data; unsigned long flags; unsigned short data = 0xffff; if (snd_m3_ac97_wait(chip)) goto fail; spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); if (snd_m3_ac97_wait(chip)) goto fail_unlock; data = snd_m3_inw(chip, CODEC_DATA);fail_unlock: spin_unlock_irqrestore(&chip->ac97_lock, flags);fail: return data;}static voidsnd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val){ struct snd_m3 *chip = ac97->private_data; unsigned long flags; if (snd_m3_ac97_wait(chip)) return; spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outw(chip, val, CODEC_DATA); snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); spin_unlock_irqrestore(&chip->ac97_lock, flags);}static void snd_m3_remote_codec_config(int io, int isremote){ isremote = isremote ? 1 : 0; outw((inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote, io + RING_BUS_CTRL_B); outw((inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote, io + SDO_OUT_DEST_CTRL); outw((inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote, io + SDO_IN_DEST_CTRL);}/* * hack, returns non zero on err */static int snd_m3_try_read_vendor(struct snd_m3 *chip){ u16 ret; if (snd_m3_ac97_wait(chip)) return 1; snd_m3_outb(chip, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30); if (snd_m3_ac97_wait(chip)) return 1; ret = snd_m3_inw(chip, 0x32); return (ret == 0) || (ret == 0xffff);}static void snd_m3_ac97_reset(struct snd_m3 *chip){ u16 dir; int delay1 = 0, delay2 = 0, i; int io = chip->iobase; if (chip->allegro_flag) { /* * the onboard codec on the allegro seems * to want to wait a very long time before * coming back to life */ delay1 = 50; delay2 = 800; } else { /* maestro3 */ delay1 = 20; delay2 = 500; } for (i = 0; i < 5; i++) { dir = inw(io + GPIO_DIRECTION); if (!chip->irda_workaround) dir |= 0x10; /* assuming pci bus master? */ snd_m3_remote_codec_config(io, 0); outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A); udelay(20); outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION); outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK); outw(0, io + GPIO_DATA); outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION); schedule_timeout_uninterruptib
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -