📄 maestro3.c
字号:
unsigned int allegro_flag : 1; struct snd_ac97 *ac97; struct snd_pcm *pcm; struct pci_dev *pci; int dacs_active; int timer_users; struct m3_list msrc_list; struct m3_list mixer_list; struct m3_list adc1_list; struct m3_list dma_list; /* for storing reset state..*/ u8 reset_state; int external_amp; int amp_gpio; /* gpio pin # for external amp, -1 = default */ unsigned int hv_config; /* hardware-volume config bits */ unsigned irda_workaround :1; /* avoid to touch 0x10 on GPIO_DIRECTION (e.g. for IrDA on Dell Inspirons) */ unsigned is_omnibook :1; /* Do HP OmniBook GPIO magic? */ /* midi */ struct snd_rawmidi *rmidi; /* pcm streams */ int num_substreams; struct m3_dma *substreams; spinlock_t reg_lock; spinlock_t ac97_lock; struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; struct tasklet_struct hwvol_tq;#ifdef CONFIG_PM u16 *suspend_mem;#endif const struct firmware *assp_kernel_image; const struct firmware *assp_minisrc_image;};/* * pci ids */static struct pci_device_id snd_m3_ids[] = { {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2LE, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_1, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_HW, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_2, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {0,},};MODULE_DEVICE_TABLE(pci, snd_m3_ids);static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03), SND_PCI_QUIRK(0x1509, 0x1740, "LEGEND ZhaoYang 3100CF", 0x03), { } /* END */};static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1), SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1), SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1), { } /* END */};/* hardware volume quirks */static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = { /* Allegro chips */ SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x0E11, 0xB112, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x0E11, 0xB114, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x103C, 0x0012, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x103C, 0x0018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x103C, 0x001C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x103C, 0x001D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x103C, 0x001E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x107B, 0x3350, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x10F7, 0x8338, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x10F7, 0x833C, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x10F7, 0x833D, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x10F7, 0x833E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x10F7, 0x833F, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x13BD, 0x1018, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x13BD, 0x1019, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x13BD, 0x101A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x14FF, 0x0F03, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x14FF, 0x0F04, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x14FF, 0x0F05, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x156D, 0xB400, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x156D, 0xB795, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x156D, 0xB797, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x156D, 0xC700, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x1033, 0x80F1, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x103C, 0x001A, NULL, /* HP OmniBook 6100 */ HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x107B, 0x340A, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x107B, 0x3450, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x109F, 0x3134, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x109F, 0x3161, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x144D, 0x3280, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x144D, 0x3281, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x144D, 0xC002, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x144D, 0xC003, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x1509, 0x1740, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x1610, 0x0010, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x1042, 0x1042, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x107B, 0x9500, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x14FF, 0x0F06, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x1558, 0x8586, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x161F, 0x2011, NULL, HV_CTRL_ENABLE), /* Maestro3 chips */ SND_PCI_QUIRK(0x103C, 0x000E, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x103C, 0x0010, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x103C, 0x0011, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x103C, 0x001B, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x104D, 0x80A6, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x104D, 0x80AA, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x107B, 0x5300, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x110A, 0x1998, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x13BD, 0x1015, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x13BD, 0x101C, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x13BD, 0x1802, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x1599, 0x0715, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x5643, 0x5643, NULL, HV_CTRL_ENABLE), SND_PCI_QUIRK(0x144D, 0x3260, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x144D, 0x3261, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x144D, 0xC000, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), SND_PCI_QUIRK(0x144D, 0xC001, NULL, HV_CTRL_ENABLE | REDUCED_DEBOUNCE), { } /* END */};/* HP Omnibook quirks */static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = { SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */ SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */ { } /* END */};/* * lowlevel functions */static inline void snd_m3_outw(struct snd_m3 *chip, u16 value, unsigned long reg){ outw(value, chip->iobase + reg);}static inline u16 snd_m3_inw(struct snd_m3 *chip, unsigned long reg){ return inw(chip->iobase + reg);}static inline void snd_m3_outb(struct snd_m3 *chip, u8 value, unsigned long reg){ outb(value, chip->iobase + reg);}static inline u8 snd_m3_inb(struct snd_m3 *chip, unsigned long reg){ return inb(chip->iobase + reg);}/* * access 16bit words to the code or data regions of the dsp's memory. * index addresses 16bit words. */static u16 snd_m3_assp_read(struct snd_m3 *chip, u16 region, u16 index){ snd_m3_outw(chip, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE); snd_m3_outw(chip, index, DSP_PORT_MEMORY_INDEX); return snd_m3_inw(chip, DSP_PORT_MEMORY_DATA);}static void snd_m3_assp_write(struct snd_m3 *chip, u16 region, u16 index, u16 data){ snd_m3_outw(chip, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE); snd_m3_outw(chip, index, DSP_PORT_MEMORY_INDEX); snd_m3_outw(chip, data, DSP_PORT_MEMORY_DATA);}static void snd_m3_assp_halt(struct snd_m3 *chip){ chip->reset_state = snd_m3_inb(chip, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK; msleep(10); snd_m3_outb(chip, chip->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);}static void snd_m3_assp_continue(struct snd_m3 *chip){ snd_m3_outb(chip, chip->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);}/* * This makes me sad. the maestro3 has lists * internally that must be packed.. 0 terminates, * apparently, or maybe all unused entries have * to be 0, the lists have static lengths set * by the binary code images. */static int snd_m3_add_list(struct snd_m3 *chip, struct m3_list *list, u16 val){ snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, list->mem_addr + list->curlen, val); return list->curlen++;}static void snd_m3_remove_list(struct snd_m3 *chip, struct m3_list *list, int index){ u16 val; int lastindex = list->curlen - 1; if (index != lastindex) { val = snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, list->mem_addr + lastindex); snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, list->mem_addr + index, val); } snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, list->mem_addr + lastindex, 0); list->curlen--;}static void snd_m3_inc_timer_users(struct snd_m3 *chip){ chip->timer_users++; if (chip->timer_users != 1) return; snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, KDATA_TIMER_COUNT_RELOAD, 240); snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, KDATA_TIMER_COUNT_CURRENT, 240); snd_m3_outw(chip, snd_m3_inw(chip, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE, HOST_INT_CTRL);}static void snd_m3_dec_timer_users(struct snd_m3 *chip){ chip->timer_users--; if (chip->timer_users > 0) return; snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, KDATA_TIMER_COUNT_RELOAD, 0); snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, KDATA_TIMER_COUNT_CURRENT, 0); snd_m3_outw(chip, snd_m3_inw(chip, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE, HOST_INT_CTRL);}/* * start/stop *//* spinlock held! */static int snd_m3_pcm_start(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs){ if (! s || ! subs) return -EINVAL; snd_m3_inc_timer_users(chip); switch (subs->stream) { case SNDRV_PCM_STREAM_PLAYBACK: chip->dacs_active++; snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, s->inst.data + CDATA_INSTANCE_READY, 1); snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, KDATA_MIXER_TASK_NUMBER, chip->dacs_active); break; case SNDRV_PCM_STREAM_CAPTURE: snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, KDATA_ADC1_REQUEST, 1); snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, s->inst.data + CDATA_INSTANCE_READY, 1); break; } return 0;}/* spinlock held! */static int snd_m3_pcm_stop(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs){ if (! s || ! subs) return -EINVAL; snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, s->inst.data + CDATA_INSTANCE_READY, 0); snd_m3_dec_timer_users(chip); switch (subs->stream) { case SNDRV_PCM_STREAM_PLAYBACK: chip->dacs_active--; snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, KDATA_MIXER_TASK_NUMBER, chip->dacs_active); break; case SNDRV_PCM_STREAM_CAPTURE: snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA, KDATA_ADC1_REQUEST, 0); break; } return 0;}static intsnd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd){ struct snd_m3 *chip = snd_pcm_substream_chip(subs); struct m3_dma *s = subs->runtime->private_data; int err = -EINVAL; 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) err = -EBUSY; else { s->running = 1; err = snd_m3_pcm_start(chip, s, subs); } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (! s->running) err = 0; /* should return error? */ else { s->running = 0; err = snd_m3_pcm_stop(chip, s, subs); } break; } spin_unlock(&chip->reg_lock); return err;}/* * setup */static void snd_m3_pcm_setup1(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs){ int dsp_in_size, dsp_out_size, dsp_in_buffer, dsp_out_buffer; struct snd_pcm_runtime *runtime = subs->runtime; if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) { dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2); dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2); } else { dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x10 * 2); dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -