📄 ac97_codec.c
字号:
*r_result |= SNDRV_PCM_RATE_96000; return; } saved = snd_ac97_read(ac97, reg); if ((ac97->ext_id & AC97_EI_DRA) && reg == AC97_PCM_FRONT_DAC_RATE) snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_DRA, 0); /* test a non-standard rate */ if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11000)) result |= SNDRV_PCM_RATE_CONTINUOUS; /* let's try to obtain standard rates */ if (snd_ac97_test_rate(ac97, reg, shadow_reg, 8000)) result |= SNDRV_PCM_RATE_8000; if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11025)) result |= SNDRV_PCM_RATE_11025; if (snd_ac97_test_rate(ac97, reg, shadow_reg, 16000)) result |= SNDRV_PCM_RATE_16000; if (snd_ac97_test_rate(ac97, reg, shadow_reg, 22050)) result |= SNDRV_PCM_RATE_22050; if (snd_ac97_test_rate(ac97, reg, shadow_reg, 32000)) result |= SNDRV_PCM_RATE_32000; if (snd_ac97_test_rate(ac97, reg, shadow_reg, 44100)) result |= SNDRV_PCM_RATE_44100; if (snd_ac97_test_rate(ac97, reg, shadow_reg, 48000)) result |= SNDRV_PCM_RATE_48000; if ((ac97->flags & AC97_DOUBLE_RATE) && reg == AC97_PCM_FRONT_DAC_RATE) { /* test standard double rates */ snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_DRA, AC97_EA_DRA); if (snd_ac97_test_rate(ac97, reg, shadow_reg, 64000 / 2)) result |= SNDRV_PCM_RATE_64000; if (snd_ac97_test_rate(ac97, reg, shadow_reg, 88200 / 2)) result |= SNDRV_PCM_RATE_88200; if (snd_ac97_test_rate(ac97, reg, shadow_reg, 96000 / 2)) result |= SNDRV_PCM_RATE_96000; /* some codecs don't support variable double rates */ if (!snd_ac97_test_rate(ac97, reg, shadow_reg, 76100 / 2)) result &= ~SNDRV_PCM_RATE_CONTINUOUS; snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_DRA, 0); } /* restore the default value */ snd_ac97_write_cache(ac97, reg, saved); if (shadow_reg) snd_ac97_write_cache(ac97, shadow_reg, saved); *r_result = result;}/* check AC97_SPDIF register to accept which sample rates */static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97){ unsigned int result = 0; int i; static unsigned short ctl_bits[] = { AC97_SC_SPSR_44K, AC97_SC_SPSR_32K, AC97_SC_SPSR_48K }; static unsigned int rate_bits[] = { SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_32000, SNDRV_PCM_RATE_48000 }; for (i = 0; i < (int)ARRAY_SIZE(ctl_bits); i++) { snd_ac97_update_bits(ac97, AC97_SPDIF, AC97_SC_SPSR_MASK, ctl_bits[i]); if ((snd_ac97_read(ac97, AC97_SPDIF) & AC97_SC_SPSR_MASK) == ctl_bits[i]) result |= rate_bits[i]; } return result;}/* look for the codec id table matching with the given id */static const struct ac97_codec_id *look_for_codec_id(const struct ac97_codec_id *table, unsigned int id){ const struct ac97_codec_id *pid; for (pid = table; pid->id; pid++) if (pid->id == (id & pid->mask)) return pid; return NULL;}void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int modem){ const struct ac97_codec_id *pid; sprintf(name, "0x%x %c%c%c", id, printable(id >> 24), printable(id >> 16), printable(id >> 8)); pid = look_for_codec_id(snd_ac97_codec_id_vendors, id); if (! pid) return; strcpy(name, pid->name); if (ac97 && pid->patch) { if ((modem && (pid->flags & AC97_MODEM_PATCH)) || (! modem && ! (pid->flags & AC97_MODEM_PATCH))) pid->patch(ac97); } pid = look_for_codec_id(snd_ac97_codec_ids, id); if (pid) { strcat(name, " "); strcat(name, pid->name); if (pid->mask != 0xffffffff) sprintf(name + strlen(name), " rev %d", id & ~pid->mask); if (ac97 && pid->patch) { if ((modem && (pid->flags & AC97_MODEM_PATCH)) || (! modem && ! (pid->flags & AC97_MODEM_PATCH))) pid->patch(ac97); } } else sprintf(name + strlen(name), " id %x", id & 0xff);}/** * snd_ac97_get_short_name - retrieve codec name * @ac97: the codec instance * * Returns the short identifying name of the codec. */const char *snd_ac97_get_short_name(struct snd_ac97 *ac97){ const struct ac97_codec_id *pid; for (pid = snd_ac97_codec_ids; pid->id; pid++) if (pid->id == (ac97->id & pid->mask)) return pid->name; return "unknown codec";}/* wait for a while until registers are accessible after RESET * return 0 if ok, negative not ready */static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem){ unsigned long end_time; unsigned short val; end_time = jiffies + timeout; do { /* use preliminary reads to settle the communication */ snd_ac97_read(ac97, AC97_RESET); snd_ac97_read(ac97, AC97_VENDOR_ID1); snd_ac97_read(ac97, AC97_VENDOR_ID2); /* modem? */ if (with_modem) { val = snd_ac97_read(ac97, AC97_EXTENDED_MID); if (val != 0xffff && (val & 1) != 0) return 0; } if (ac97->scaps & AC97_SCAP_DETECT_BY_VENDOR) { /* probably only Xbox issue - all registers are read as zero */ val = snd_ac97_read(ac97, AC97_VENDOR_ID1); if (val != 0 && val != 0xffff) return 0; } else { /* because the PCM or MASTER volume registers can be modified, * the REC_GAIN register is used for tests */ /* test if we can write to the record gain volume register */ snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05); if ((snd_ac97_read(ac97, AC97_REC_GAIN) & 0x7fff) == 0x0a05) return 0; } schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); return -ENODEV;}/** * snd_ac97_bus - create an AC97 bus component * @card: the card instance * @num: the bus number * @ops: the bus callbacks table * @private_data: private data pointer for the new instance * @rbus: the pointer to store the new AC97 bus instance. * * Creates an AC97 bus component. An struct snd_ac97_bus instance is newly * allocated and initialized. * * The ops table must include valid callbacks (at least read and * write). The other callbacks, wait and reset, are not mandatory. * * The clock is set to 48000. If another clock is needed, set * (*rbus)->clock manually. * * The AC97 bus instance is registered as a low-level device, so you don't * have to release it manually. * * Returns zero if successful, or a negative error code on failure. */int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops, void *private_data, struct snd_ac97_bus **rbus){ int err; struct snd_ac97_bus *bus; static struct snd_device_ops dev_ops = { .dev_free = snd_ac97_bus_dev_free, }; snd_assert(card != NULL, return -EINVAL); snd_assert(rbus != NULL, return -EINVAL); bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (bus == NULL) return -ENOMEM; bus->card = card; bus->num = num; bus->ops = ops; bus->private_data = private_data; bus->clock = 48000; spin_lock_init(&bus->bus_lock); snd_ac97_bus_proc_init(bus); if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) { snd_ac97_bus_free(bus); return err; } *rbus = bus; return 0;}/* stop no dev release warning */static void ac97_device_release(struct device * dev){}/* register ac97 codec to bus */static int snd_ac97_dev_register(struct snd_device *device){ struct snd_ac97 *ac97 = device->device_data; int err; ac97->dev.bus = &ac97_bus_type; ac97->dev.parent = ac97->bus->card->dev; ac97->dev.release = ac97_device_release; snprintf(ac97->dev.bus_id, BUS_ID_SIZE, "%d-%d:%s", ac97->bus->card->number, ac97->num, snd_ac97_get_short_name(ac97)); if ((err = device_register(&ac97->dev)) < 0) { snd_printk(KERN_ERR "Can't register ac97 bus\n"); ac97->dev.bus = NULL; return err; } return 0;}/* unregister ac97 codec */static int snd_ac97_dev_unregister(struct snd_device *device){ struct snd_ac97 *ac97 = device->device_data; if (ac97->dev.bus) device_unregister(&ac97->dev); return snd_ac97_free(ac97);}/* build_ops to do nothing */static struct snd_ac97_build_ops null_build_ops;/** * snd_ac97_mixer - create an Codec97 component * @bus: the AC97 bus which codec is attached to * @template: the template of ac97, including index, callbacks and * the private data. * @rac97: the pointer to store the new ac97 instance. * * Creates an Codec97 component. An struct snd_ac97 instance is newly * allocated and initialized from the template. The codec * is then initialized by the standard procedure. * * The template must include the codec number (num) and address (addr), * and the private data (private_data). * * The ac97 instance is registered as a low-level device, so you don't * have to release it manually. * * Returns zero if successful, or a negative error code on failure. */int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, struct snd_ac97 **rac97){ int err; struct snd_ac97 *ac97; struct snd_card *card; char name[64]; unsigned long end_time; unsigned int reg; const struct ac97_codec_id *pid; static struct snd_device_ops ops = { .dev_free = snd_ac97_dev_free, .dev_register = snd_ac97_dev_register, .dev_unregister = snd_ac97_dev_unregister, }; snd_assert(rac97 != NULL, return -EINVAL); *rac97 = NULL; snd_assert(bus != NULL && template != NULL, return -EINVAL); snd_assert(template->num < 4 && bus->codec[template->num] == NULL, return -EINVAL); card = bus->card; ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL); if (ac97 == NULL) return -ENOMEM; ac97->private_data = template->private_data; ac97->private_free = template->private_free; ac97->bus = bus; ac97->pci = template->pci; ac97->num = template->num; ac97->addr = template->addr; ac97->scaps = template->scaps; ac97->limited_regs = template->limited_regs; memcpy(ac97->reg_accessed, template->reg_accessed, sizeof(ac97->reg_accessed)); bus->codec[ac97->num] = ac97; init_MUTEX(&ac97->reg_mutex); init_MUTEX(&ac97->page_mutex);#ifdef CONFIG_PCI if (ac97->pci) { pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor); pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device); }#endif if (bus->ops->reset) { bus->ops->reset(ac97); goto __access_ok; } ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); if (ac97->id && ac97->id != (unsigned int)-1) { pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id); if (pid && (pid->flags & AC97_DEFAULT_POWER_OFF)) goto __access_ok; } /* reset to defaults */ if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO)) snd_ac97_write(ac97, AC97_RESET, 0); if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM)) snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); if (bus->ops->wait) bus->ops->wait(ac97); else { udelay(50); if (ac97->scaps & AC97_SCAP_SKIP_AUDIO) err = ac97_reset_wait(ac97, HZ/2, 1); else { err = ac97_reset_wait(ac97, HZ/2, 0); if (err < 0) err = ac97_reset_wait(ac97, HZ/2, 1); } if (err < 0) { snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num); /* proceed anyway - it's often non-critical */ } } __access_ok: ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); if (! (ac97->scaps & AC97_SCAP_DETECT_BY_VENDOR) && (ac97->id == 0x00000000 || ac97->id == 0xffffffff)) { snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id); snd_ac97_free(ac97); return -EIO; } pid = look_for_codec_id(snd_ac97_codec_ids, ac97->id); if (pid) ac97->flags |= pid->flags; /* test for AC'97 */ if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) { /* test if we can write to the record gain volume register */ snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a06); if (((err = snd_ac97_read(ac97, AC97_REC_GAIN)) & 0x7fff) == 0x0a06) ac97->scaps |= AC97_SCAP_AUDIO; } if (ac97->scaps & AC97_SCAP_AUDIO) { ac97->caps = snd_ac97_read(ac97, AC97_RESET); ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID); if (ac97->ext_id == 0xffff) /* invalid combination */ ac97->ext_id = 0; } /* test for MC'97 */ if (!(ac97->scaps & A
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -