📄 bt87x.c
字号:
snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); spin_unlock(&chip->reg_lock); return 0;}static int snd_bt87x_stop(struct snd_bt87x *chip){ spin_lock(&chip->reg_lock); chip->reg_control &= ~(CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); snd_bt87x_writel(chip, REG_INT_MASK, 0); snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); spin_unlock(&chip->reg_lock); return 0;}static int snd_bt87x_trigger(struct snd_pcm_substream *substream, int cmd){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: return snd_bt87x_start(chip); case SNDRV_PCM_TRIGGER_STOP: return snd_bt87x_stop(chip); default: return -EINVAL; }}static snd_pcm_uframes_t snd_bt87x_pointer(struct snd_pcm_substream *substream){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; return (snd_pcm_uframes_t)bytes_to_frames(runtime, chip->current_line * chip->line_bytes);}static struct snd_pcm_ops snd_bt87x_pcm_ops = { .open = snd_bt87x_pcm_open, .close = snd_bt87x_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_bt87x_hw_params, .hw_free = snd_bt87x_hw_free, .prepare = snd_bt87x_prepare, .trigger = snd_bt87x_trigger, .pointer = snd_bt87x_pointer, .page = snd_pcm_sgbuf_ops_page,};static int snd_bt87x_capture_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info){ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; info->count = 1; info->value.integer.min = 0; info->value.integer.max = 15; return 0;}static int snd_bt87x_capture_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); value->value.integer.value[0] = (chip->reg_control & CTL_A_GAIN_MASK) >> CTL_A_GAIN_SHIFT; return 0;}static int snd_bt87x_capture_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); u32 old_control; int changed; spin_lock_irq(&chip->reg_lock); old_control = chip->reg_control; chip->reg_control = (chip->reg_control & ~CTL_A_GAIN_MASK) | (value->value.integer.value[0] << CTL_A_GAIN_SHIFT); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); changed = old_control != chip->reg_control; spin_unlock_irq(&chip->reg_lock); return changed;}static struct snd_kcontrol_new snd_bt87x_capture_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Volume", .info = snd_bt87x_capture_volume_info, .get = snd_bt87x_capture_volume_get, .put = snd_bt87x_capture_volume_put,};static int snd_bt87x_capture_boost_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info){ info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; info->count = 1; info->value.integer.min = 0; info->value.integer.max = 1; return 0;}static int snd_bt87x_capture_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); value->value.integer.value[0] = !! (chip->reg_control & CTL_A_G2X); return 0;}static int snd_bt87x_capture_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); u32 old_control; int changed; spin_lock_irq(&chip->reg_lock); old_control = chip->reg_control; chip->reg_control = (chip->reg_control & ~CTL_A_G2X) | (value->value.integer.value[0] ? CTL_A_G2X : 0); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); changed = chip->reg_control != old_control; spin_unlock_irq(&chip->reg_lock); return changed;}static struct snd_kcontrol_new snd_bt87x_capture_boost = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Boost", .info = snd_bt87x_capture_boost_info, .get = snd_bt87x_capture_boost_get, .put = snd_bt87x_capture_boost_put,};static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info){ static char *texts[3] = {"TV Tuner", "FM", "Mic/Line"}; info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = 1; info->value.enumerated.items = 3; if (info->value.enumerated.item > 2) info->value.enumerated.item = 2; strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]); return 0;}static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); value->value.enumerated.item[0] = (chip->reg_control & CTL_A_SEL_MASK) >> CTL_A_SEL_SHIFT; return 0;}static int snd_bt87x_capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); u32 old_control; int changed; spin_lock_irq(&chip->reg_lock); old_control = chip->reg_control; chip->reg_control = (chip->reg_control & ~CTL_A_SEL_MASK) | (value->value.enumerated.item[0] << CTL_A_SEL_SHIFT); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); changed = chip->reg_control != old_control; spin_unlock_irq(&chip->reg_lock); return changed;}static struct snd_kcontrol_new snd_bt87x_capture_source = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = snd_bt87x_capture_source_info, .get = snd_bt87x_capture_source_get, .put = snd_bt87x_capture_source_put,};static int snd_bt87x_free(struct snd_bt87x *chip){ if (chip->mmio) { snd_bt87x_stop(chip); if (chip->irq >= 0) synchronize_irq(chip->irq); iounmap(chip->mmio); } if (chip->irq >= 0) free_irq(chip->irq, chip); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); return 0;}static int snd_bt87x_dev_free(struct snd_device *device){ struct snd_bt87x *chip = device->device_data; return snd_bt87x_free(chip);}static int __devinit snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name){ int err; struct snd_pcm *pcm; err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); if (err < 0) return err; pcm->private_data = chip; strcpy(pcm->name, name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops); return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 128 * 1024, (255 * 4092 + 1023) & ~1023);}static int __devinit snd_bt87x_create(struct snd_card *card, struct pci_dev *pci, struct snd_bt87x **rchip){ struct snd_bt87x *chip; int err; static struct snd_device_ops ops = { .dev_free = snd_bt87x_dev_free }; *rchip = NULL; err = pci_enable_device(pci); if (err < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->irq = -1; spin_lock_init(&chip->reg_lock); if ((err = pci_request_regions(pci, "Bt87x audio")) < 0) { kfree(chip); pci_disable_device(pci); return err; } chip->mmio = ioremap_nocache(pci_resource_start(pci, 0), pci_resource_len(pci, 0)); if (!chip->mmio) { snd_bt87x_free(chip); snd_printk(KERN_ERR "cannot remap io memory\n"); return -ENOMEM; } chip->reg_control = CTL_DA_ES2 | CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT); chip->interrupt_mask = MY_INTERRUPTS; snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); snd_bt87x_writel(chip, REG_INT_MASK, 0); snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); if (request_irq(pci->irq, snd_bt87x_interrupt, SA_INTERRUPT | SA_SHIRQ, "Bt87x audio", chip)) { snd_bt87x_free(chip); snd_printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { snd_bt87x_free(chip); return err; } snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0;}#define BT_DEVICE(chip, subvend, subdev, rate) \ { .vendor = PCI_VENDOR_ID_BROOKTREE, \ .device = chip, \ .subvendor = subvend, .subdevice = subdev, \ .driver_data = rate }/* driver_data is the default digital_rate value for that device */static struct pci_device_id snd_bt87x_ids[] = { /* Hauppauge WinTV series */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, 32000), /* Hauppauge WinTV series */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000), /* Viewcast Osprey 200 */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100), /* AVerMedia Studio No. 103, 203, ...? */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000), /* Leadtek Winfast tv 2000xp delux */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000), { }};MODULE_DEVICE_TABLE(pci, snd_bt87x_ids);/* cards known not to have audio * (DVB cards use the audio function to transfer MPEG data) */static struct { unsigned short subvendor, subdevice;} blacklist[] __devinitdata = { {0x0071, 0x0101}, /* Nebula Electronics DigiTV */ {0x11bd, 0x001c}, /* Pinnacle PCTV Sat */ {0x11bd, 0x0026}, /* Pinnacle PCTV SAT CI */ {0x1461, 0x0761}, /* AVermedia AverTV DVB-T */ {0x1461, 0x0771}, /* AVermedia DVB-T 771 */ {0x1822, 0x0001}, /* Twinhan VisionPlus DVB-T */ {0x18ac, 0xd500}, /* DVICO FusionHDTV 5 Lite */ {0x18ac, 0xdb10}, /* DVICO FusionHDTV DVB-T Lite */ {0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */ {0x7063, 0x2000}, /* pcHDTV HD-2000 TV */};static struct pci_driver driver;/* return the rate of the card, or a negative value if it's blacklisted */static int __devinit snd_bt87x_detect_card(struct pci_dev *pci){ int i; const struct pci_device_id *supported; supported = pci_match_device(&driver, pci); if (supported && supported->driver_data > 0) return supported->driver_data; for (i = 0; i < ARRAY_SIZE(blacklist); ++i) if (blacklist[i].subvendor == pci->subsystem_vendor && blacklist[i].subdevice == pci->subsystem_device) {#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) snd_printdd(KERN_INFO "card %#04x:%#04x has no audio\n", pci->subsystem_vendor, pci->subsystem_device);#else snd_printdd(KERN_INFO "card %#04x-%#04x:%#04x has no audio\n", pci->device, pci->subsystem_vendor, pci->subsystem_device);#endif return -EBUSY; }#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) snd_printk(KERN_INFO "unknown card %#04x:%#04x, using default rate 32000\n", pci->subsystem_vendor, pci->subsystem_device);#else snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x, using default rate 32000\n", pci->device, pci->subsystem_vendor, pci->subsystem_device);#endif snd_printk(KERN_DEBUG "please mail id, board name, and, " "if it works, the correct digital_rate option to " "<alsa-devel@lists.sf.net>\n"); return 32000; /* default rate */}static int __devinit snd_bt87x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ static int dev; struct snd_card *card; struct snd_bt87x *chip; int err, rate; rate = pci_id->driver_data; if (! rate) if ((rate = snd_bt87x_detect_card(pci)) <= 0) return -ENODEV; if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { ++dev; return -ENOENT; } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (!card) return -ENOMEM; err = snd_bt87x_create(card, pci, &chip); if (err < 0) goto _error; if (digital_rate[dev] > 0) chip->dig_rate = digital_rate[dev]; else chip->dig_rate = rate; err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital"); if (err < 0) goto _error; err = snd_bt87x_pcm(chip, DEVICE_ANALOG, "Bt87x Analog"); if (err < 0) goto _error; err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_volume, chip)); if (err < 0) goto _error; err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_boost, chip)); if (err < 0) goto _error; err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_source, chip)); if (err < 0) goto _error; strcpy(card->driver, "Bt87x"); sprintf(card->shortname, "Brooktree Bt%x", pci->device); sprintf(card->longname, "%s at %#lx, irq %i", card->shortname, pci_resource_start(pci, 0), chip->irq); strcpy(card->mixername, "Bt87x"); err = snd_card_register(card); if (err < 0) goto _error; pci_set_drvdata(pci, card); ++dev; return 0;_error: snd_card_free(card); return err;}static void __devexit snd_bt87x_remove(struct pci_dev *pci){ snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL);}/* default entries for all Bt87x cards - it's not exported *//* driver_data is set to 0 to call detection */static struct pci_device_id snd_bt87x_default_ids[] = { BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, 0), BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, 0), { }};static struct pci_driver driver = { .name = "Bt87x", .id_table = snd_bt87x_ids, .probe = snd_bt87x_probe, .remove = __devexit_p(snd_bt87x_remove),};static int __init alsa_card_bt87x_init(void){ if (load_all) driver.id_table = snd_bt87x_default_ids; return pci_register_driver(&driver);}static void __exit alsa_card_bt87x_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_bt87x_init)module_exit(alsa_card_bt87x_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -