kahlua.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 233 行

C
233
字号
/* *	Initialisation code for Cyrix/NatSemi VSA1 softaudio * *	(C) Copyright 2003 Red Hat Inc <alan@redhat.com> * * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems. * The older version (VSA1) provides fairly good soundblaster emulation * although there are a couple of bugs: large DMA buffers break record, * and the MPU event handling seems suspect. VSA2 allows the native driver * to control the AC97 audio engine directly and requires a different driver. * * Thanks to National Semiconductor for providing the needed information * on the XpressAudio(tm) internals. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * TO DO: *	Investigate whether we can portably support Cognac (5520) in the *	same manner. */#include <linux/config.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/module.h>#include <linux/pci.h>#include "sound_config.h"#include "sb.h"/* *	Read a soundblaster compatible mixer register. *	In this case we are actually reading an SMI trap *	not real hardware. */static u8 __devinit mixer_read(unsigned long io, u8 reg){	outb(reg, io + 4);	udelay(20);	reg = inb(io + 5);	udelay(20);	return reg;}static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id *ent){	struct address_info *hw_config;	unsigned long base;	void *mem;	unsigned long io;	u16 map;	u8 irq, dma8, dma16;	int oldquiet;	extern int sb_be_quiet;			base = pci_resource_start(pdev, 0);	if(base == 0UL)		return 1;		mem = ioremap(base, 128);	if(mem == 0UL)		return 1;	map = readw(mem + 0x18);	/* Read the SMI enables */	iounmap(mem);		/* Map bits		0:1	* 0x20 + 0x200 = sb base		2	sb enable		3	adlib enable		5	MPU enable 0x330		6	MPU enable 0x300			   The other bits may be used internally so must be masked */	io = 0x220 + 0x20 * (map & 3);	   		if(map & (1<<2))		printk(KERN_INFO "kahlua: XpressAudio at 0x%lx\n", io);	else		return 1;			if(map & (1<<5))		printk(KERN_INFO "kahlua: MPU at 0x300\n");	else if(map & (1<<6))		printk(KERN_INFO "kahlua: MPU at 0x330\n");		irq = mixer_read(io, 0x80) & 0x0F;	dma8 = mixer_read(io, 0x81);	// printk("IRQ=%x MAP=%x DMA=%x\n", irq, map, dma8);		if(dma8 & 0x20)		dma16 = 5;	else if(dma8 & 0x40)		dma16 = 6;	else if(dma8 & 0x80)		dma16 = 7;	else	{		printk(KERN_ERR "kahlua: No 16bit DMA enabled.\n");		return 1;	}			if(dma8 & 0x01)		dma8 = 0;	else if(dma8 & 0x02)		dma8 = 1;	else if(dma8 & 0x08)		dma8 = 3;	else	{		printk(KERN_ERR "kahlua: No 8bit DMA enabled.\n");		return 1;	}		if(irq & 1)		irq = 9;	else if(irq & 2)		irq = 5;	else if(irq & 4)		irq = 7;	else if(irq & 8)		irq = 10;	else	{		printk(KERN_ERR "kahlua: SB IRQ not set.\n");		return 1;	}		printk(KERN_INFO "kahlua: XpressAudio on IRQ %d, DMA %d, %d\n",		irq, dma8, dma16);		hw_config = kmalloc(sizeof(struct address_info), GFP_KERNEL);	if(hw_config == NULL)	{		printk(KERN_ERR "kahlua: out of memory.\n");		return 1;	}	memset(hw_config, 0, sizeof(*hw_config));		pci_set_drvdata(pdev, hw_config);		hw_config->io_base = io;	hw_config->irq = irq;	hw_config->dma = dma8;	hw_config->dma2 = dma16;	hw_config->name = "Cyrix XpressAudio";	hw_config->driver_use_1 = SB_NO_MIDI | SB_PCI_IRQ;	if (!request_region(io, 16, "soundblaster"))		goto err_out_free;		if(sb_dsp_detect(hw_config, 0, 0, NULL)==0)	{		printk(KERN_ERR "kahlua: audio not responding.\n");		release_region(io, 16);		goto err_out_free;	}	oldquiet = sb_be_quiet;		sb_be_quiet = 1;	if(sb_dsp_init(hw_config, THIS_MODULE))	{		sb_be_quiet = oldquiet;		goto err_out_free;	}	sb_be_quiet = oldquiet;		return 0;err_out_free:	pci_set_drvdata(pdev, NULL);	kfree(hw_config);	return 1;}static void __devexit remove_one(struct pci_dev *pdev){	struct address_info *hw_config = pci_get_drvdata(pdev);	sb_dsp_unload(hw_config, 0);	pci_set_drvdata(pdev, NULL);	kfree(hw_config);}MODULE_AUTHOR("Alan Cox");MODULE_DESCRIPTION("Kahlua VSA1 PCI Audio");MODULE_LICENSE("GPL");/* *	5530 only. The 5510/5520 decode is different. */static struct pci_device_id id_tbl[] = {	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ }};MODULE_DEVICE_TABLE(pci, id_tbl);static struct pci_driver kahlua_driver = {	.name		= "kahlua",	.id_table	= id_tbl,	.probe		= probe_one,	.remove		= __devexit_p(remove_one),};static int __init kahlua_init_module(void){	printk(KERN_INFO "Cyrix Kahlua VSA1 XpressAudio support (c) Copyright 2003 Red Hat Inc\n");	return pci_module_init(&kahlua_driver);}static void __devexit kahlua_cleanup_module(void){	pci_unregister_driver(&kahlua_driver);}module_init(kahlua_init_module);module_exit(kahlua_cleanup_module);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?