cs4232.c

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

C
522
字号
/* * Copyright (C) by Hannu Savolainen 1993-1997 * *	cs4232.c * * The low level driver for Crystal CS4232 based cards. The CS4232 is * a PnP compatible chip which contains a CS4231A codec, SB emulation, * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM  * interfaces. This is just a temporary driver until full PnP support * gets implemented. Just the WSS codec, FM synth and the MIDI ports are * supported. Other interfaces are left uninitialized. * * ifdef ...WAVEFRONT... *  *   Support is provided for initializing the WaveFront synth *   interface as well, which is logical device #4. Note that if *   you have a Tropez+ card, you probably don't need to setup *   the CS4232-supported MIDI interface, since it corresponds to *   the internal 26-pin header that's hard to access. Using this *   requires an additional IRQ, a resource none too plentiful in *   this environment. Just don't set module parameters mpuio and *   mpuirq, and the MIDI port will be left uninitialized. You can *   still use the ICS2115 hosted MIDI interface which corresponds *   to the 9-pin D connector on the back of the card. * * endif  ...WAVEFRONT... * * Supported chips are: *      CS4232 *      CS4236 *      CS4236B * * Note: You will need a PnP config setup to initialise some CS4232 boards * anyway. * * Changes *      John Rood               Added Bose Sound System Support. *      Toshio Spoor *	Alan Cox		Modularisation, Basic cleanups. *      Paul Barton-Davis	Separated MPU configuration, added *                                       Tropez+ (WaveFront) support *	Christoph Hellwig	Adapted to module_init/module_exit, * 					simple cleanups * 	Arnaldo C. de Melo	got rid of attach_uart401 *	Bartlomiej Zolnierkiewicz *				Added some __init/__initdata/__exit *	Marcus Meissner		Added ISA PnP support. */#include <linux/config.h>#include <linux/pnp.h>#include <linux/module.h>#include <linux/init.h>#include "sound_config.h"#include "cs4232.h"#include "ad1848.h"#include "mpu401.h"#define KEY_PORT	0x279	/* Same as LPT1 status port */#define CSN_NUM		0x99	/* Just a random number */#define INDEX_ADDRESS   0x00    /* (R0) Index Address Register */#define INDEX_DATA      0x01    /* (R1) Indexed Data Register */#define PIN_CONTROL     0x0a    /* (I10) Pin Control */#define ENABLE_PINS     0xc0    /* XCTRL0/XCTRL1 enable */static void CS_OUT(unsigned char a){	outb(a, KEY_PORT);}#define CS_OUT2(a, b)		{CS_OUT(a);CS_OUT(b);}#define CS_OUT3(a, b, c)	{CS_OUT(a);CS_OUT(b);CS_OUT(c);}static int __initdata bss       = 0;static int mpu_base, mpu_irq;static int synth_base, synth_irq;static int mpu_detected;int probe_cs4232_mpu(struct address_info *hw_config){	/*	 *	Just write down the config values.	 */	mpu_base = hw_config->io_base;	mpu_irq = hw_config->irq;	return 1;}static unsigned char crystal_key[] =	/* A 32 byte magic key sequence */{	0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,	0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,	0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,	0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a};static void sleep(unsigned howlong){	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(howlong);}static void enable_xctrl(int baseio){        unsigned char regd;                        /*         * Some IBM Aptiva's have the Bose Sound System. By default         * the Bose Amplifier is disabled. The amplifier will be          * activated, by setting the XCTRL0 and XCTRL1 bits.         * Volume of the monitor bose speakers/woofer, can then         * be set by changing the PCM volume.         *         */                        printk("cs4232: enabling Bose Sound System Amplifier.\n");                /* Switch to Pin Control Address */                           regd = inb(baseio + INDEX_ADDRESS) & 0xe0;        outb(((unsigned char) (PIN_CONTROL | regd)), baseio + INDEX_ADDRESS );                /* Activate the XCTRL0 and XCTRL1 Pins */        regd = inb(baseio + INDEX_DATA);        outb(((unsigned char) (ENABLE_PINS | regd)), baseio + INDEX_DATA );}static int __init probe_cs4232(struct address_info *hw_config, int isapnp_configured){	int i, n;	int base = hw_config->io_base, irq = hw_config->irq;	int dma1 = hw_config->dma, dma2 = hw_config->dma2;	struct resource *ports;	if (base == -1 || irq == -1 || dma1 == -1) {		printk(KERN_ERR "cs4232: dma, irq and io must be set.\n");		return 0;	}	/*	 * Verify that the I/O port range is free.	 */	ports = request_region(base, 4, "ad1848");	if (!ports) {		printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base);		return 0;	}	if (ad1848_detect(ports, NULL, hw_config->osp)) {		goto got_it;	/* The card is already active */	}	if (isapnp_configured) {		printk(KERN_ERR "cs4232.c: ISA PnP configured, but not detected?\n");		goto fail;	}	/*	 * This version of the driver doesn't use the PnP method when configuring	 * the card but a simplified method defined by Crystal. This means that	 * just one CS4232 compatible device can exist on the system. Also this	 * method conflicts with possible PnP support in the OS. For this reason 	 * driver is just a temporary kludge.	 *	 * Also the Cirrus/Crystal method doesn't always work. Try ISA PnP first ;)	 */	/*	 * Repeat initialization few times since it doesn't always succeed in	 * first time.	 */	for (n = 0; n < 4; n++)	{			/*		 *	Wake up the card by sending a 32 byte Crystal key to the key port.		 */				for (i = 0; i < 32; i++)			CS_OUT(crystal_key[i]);		sleep(HZ / 10);		/*		 *	Now set the CSN (Card Select Number).		 */		CS_OUT2(0x06, CSN_NUM);		/*		 *	Then set some config bytes. First logical device 0 		 */		CS_OUT2(0x15, 0x00);	/* Select logical device 0 (WSS/SB/FM) */		CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff);	/* WSS base */		if (check_region(0x388, 4))	/* Not free */			CS_OUT3(0x48, 0x00, 0x00)	/* FM base off */		else			CS_OUT3(0x48, 0x03, 0x88);	/* FM base 0x388 */		CS_OUT3(0x42, 0x00, 0x00);	/* SB base off */		CS_OUT2(0x22, irq);		/* SB+WSS IRQ */		CS_OUT2(0x2a, dma1);		/* SB+WSS DMA */		if (dma2 != -1)			CS_OUT2(0x25, dma2)	/* WSS DMA2 */		else			CS_OUT2(0x25, 4);	/* No WSS DMA2 */		CS_OUT2(0x33, 0x01);	/* Activate logical dev 0 */		sleep(HZ / 10);		/*		 * Initialize logical device 3 (MPU)		 */		if (mpu_base != 0 && mpu_irq != 0)		{			CS_OUT2(0x15, 0x03);	/* Select logical device 3 (MPU) */			CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff);	/* MPU base */			CS_OUT2(0x22, mpu_irq);	/* MPU IRQ */			CS_OUT2(0x33, 0x01);	/* Activate logical dev 3 */		}		if(synth_base != 0)		{		    CS_OUT2 (0x15, 0x04);	        /* logical device 4 (WaveFront) */		    CS_OUT3 (0x47, (synth_base >> 8) & 0xff,			     synth_base & 0xff);	/* base */		    CS_OUT2 (0x22, synth_irq);     	/* IRQ */		    CS_OUT2 (0x33, 0x01);	        /* Activate logical dev 4 */		}		/*		 * Finally activate the chip		 */				CS_OUT(0x79);		sleep(HZ / 5);		/*		 * Then try to detect the codec part of the chip		 */		if (ad1848_detect(ports, NULL, hw_config->osp))			goto got_it;				sleep(HZ);	}fail:	release_region(base, 4);	return 0;got_it:	if (dma2 == -1)		dma2 = dma1;	hw_config->slots[0] = ad1848_init("Crystal audio controller", ports,					  irq,					  dma1,		/* Playback DMA */					  dma2,		/* Capture DMA */					  0,					  hw_config->osp,					  THIS_MODULE);	if (hw_config->slots[0] != -1 &&		audio_devs[hw_config->slots[0]]->mixer_dev!=-1)	{			/* Assume the mixer map is as suggested in the CS4232 databook */		AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);		AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);		AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH);		/* FM synth */	}	if (mpu_base != 0 && mpu_irq != 0)	{		static struct address_info hw_config2 = {			0		};		/* Ensure it's initialized */		hw_config2.io_base = mpu_base;		hw_config2.irq = mpu_irq;		hw_config2.dma = -1;		hw_config2.dma2 = -1;		hw_config2.always_detect = 0;		hw_config2.name = NULL;		hw_config2.driver_use_1 = 0;		hw_config2.driver_use_2 = 0;		hw_config2.card_subtype = 0;		if (probe_uart401(&hw_config2, THIS_MODULE))		{			mpu_detected = 1;		}		else		{			mpu_base = mpu_irq = 0;		}		hw_config->slots[1] = hw_config2.slots[1];	}		if (bss)        	enable_xctrl(base);	return 1;}static void __devexit unload_cs4232(struct address_info *hw_config){	int base = hw_config->io_base, irq = hw_config->irq;	int dma1 = hw_config->dma, dma2 = hw_config->dma2;	if (dma2 == -1)		dma2 = dma1;	ad1848_unload(base,		      irq,		      dma1,	/* Playback DMA */		      dma2,	/* Capture DMA */		      0);	sound_unload_audiodev(hw_config->slots[0]);	if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)	{		static struct address_info hw_config2 =		{			0		};		/* Ensure it's initialized */		hw_config2.io_base = mpu_base;		hw_config2.irq = mpu_irq;		hw_config2.dma = -1;		hw_config2.dma2 = -1;		hw_config2.always_detect = 0;		hw_config2.name = NULL;		hw_config2.driver_use_1 = 0;		hw_config2.driver_use_2 = 0;		hw_config2.card_subtype = 0;		hw_config2.slots[1] = hw_config->slots[1];		unload_uart401(&hw_config2);	}}static struct address_info cfg;static struct address_info cfg_mpu;static int __initdata io	= -1;static int __initdata irq	= -1;static int __initdata dma	= -1;static int __initdata dma2	= -1;static int __initdata mpuio	= -1;static int __initdata mpuirq	= -1;static int __initdata synthio	= -1;static int __initdata synthirq	= -1;static int __initdata isapnp	= 1;MODULE_DESCRIPTION("CS4232 based soundcard driver"); MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis"); MODULE_LICENSE("GPL");MODULE_PARM(io,"i");MODULE_PARM_DESC(io,"base I/O port for AD1848");MODULE_PARM(irq,"i");MODULE_PARM_DESC(irq,"IRQ for AD1848 chip");MODULE_PARM(dma,"i");MODULE_PARM_DESC(dma,"8 bit DMA for AD1848 chip");MODULE_PARM(dma2,"i");MODULE_PARM_DESC(dma2,"16 bit DMA for AD1848 chip");MODULE_PARM(mpuio,"i");MODULE_PARM_DESC(mpuio,"MPU 401 base address");MODULE_PARM(mpuirq,"i");MODULE_PARM_DESC(mpuirq,"MPU 401 IRQ");MODULE_PARM(synthio,"i");MODULE_PARM_DESC(synthio,"Maui WaveTable base I/O port");MODULE_PARM(synthirq,"i");MODULE_PARM_DESC(synthirq,"Maui WaveTable IRQ");MODULE_PARM(isapnp,"i");MODULE_PARM_DESC(isapnp,"Enable ISAPnP probing (default 1)");MODULE_PARM(bss,"i");MODULE_PARM_DESC(bss,"Enable Bose Sound System Support (default 0)");/* *	Install a CS4232 based card. Need to have ad1848 and mpu401 *	loaded ready. *//* All cs4232 based cards have the main ad1848 card either as CSC0000 or * CSC0100. */static const struct pnp_device_id cs4232_pnp_table[] = {	{ .id = "CSC0100", .driver_data = 0 },	{ .id = "CSC0000", .driver_data = 0 },	/* Guillemot Turtlebeach something appears to be cs4232 compatible	 * (untested) */	{ .id = "GIM0100", .driver_data = 0 },	{ .id = ""}};MODULE_DEVICE_TABLE(pnp, cs4232_pnp_table);static int cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id){	struct address_info *isapnpcfg;	isapnpcfg=(struct address_info*)kmalloc(sizeof(*isapnpcfg),GFP_KERNEL);	if (!isapnpcfg)		return -ENOMEM;	isapnpcfg->irq		= pnp_irq(dev, 0);	isapnpcfg->dma		= pnp_dma(dev, 0);	isapnpcfg->dma2		= pnp_dma(dev, 1);	isapnpcfg->io_base	= pnp_port_start(dev, 0);	if (probe_cs4232(isapnpcfg,TRUE) == 0) {		printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n");		kfree(isapnpcfg);		return -ENODEV;	}	pnp_set_drvdata(dev,isapnpcfg);	return 0;}static void __devexit cs4232_pnp_remove(struct pnp_dev *dev){	struct address_info *cfg = pnp_get_drvdata(dev);	if (cfg) {		unload_cs4232(cfg);		kfree(cfg);	}}static struct pnp_driver cs4232_driver = {	.name		= "cs4232",	.id_table	= cs4232_pnp_table,	.probe		= cs4232_pnp_probe,	.remove		= __devexit_p(cs4232_pnp_remove),};static int __init init_cs4232(void){#ifdef CONFIG_SOUND_WAVEFRONT_MODULE	if(synthio == -1)		printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n");	else {		synth_base = synthio;		synth_irq =  synthirq;	}#else	if(synthio != -1)		printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n");#endif	cfg.irq = -1;	if (isapnp &&	    (pnp_register_driver(&cs4232_driver) > 0)	)		return 0;	if(io==-1||irq==-1||dma==-1)	{		printk(KERN_ERR "cs4232: Must set io, irq and dma.\n");		return -ENODEV;	}	cfg.io_base = io;	cfg.irq = irq;	cfg.dma = dma;	cfg.dma2 = dma2;	cfg_mpu.io_base = -1;	cfg_mpu.irq = -1;	if (mpuio != -1 && mpuirq != -1) {		cfg_mpu.io_base = mpuio;		cfg_mpu.irq = mpuirq;		probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */	}	if (probe_cs4232(&cfg,FALSE) == 0)		return -ENODEV;	return 0;}static void __exit cleanup_cs4232(void){	pnp_unregister_driver(&cs4232_driver);        if (cfg.irq != -1)		unload_cs4232(&cfg); /* Unloads global MPU as well, if needed */}module_init(init_cs4232);module_exit(cleanup_cs4232);#ifndef MODULEstatic int __init setup_cs4232(char *str){	/* io, irq, dma, dma2 mpuio, mpuirq*/	int ints[7];	/* If we have isapnp cards, no need for options */	if (pnp_register_driver(&cs4232_driver) > 0)		return 1;		str = get_options(str, ARRAY_SIZE(ints), ints);		io	= ints[1];	irq	= ints[2];	dma	= ints[3];	dma2	= ints[4];	mpuio	= ints[5];	mpuirq	= ints[6];	return 1;}__setup("cs4232=", setup_cs4232);#endif

⌨️ 快捷键说明

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