⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bt87x.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 + -