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

📄 ad1816.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		return -(EINVAL);}/* ------------------------------------------------------------------- *//* Mixer structure */static struct mixer_operations ad1816_mixer_operations = {	owner:	THIS_MODULE,	id:	"AD1816",	name:	"AD1816 Mixer",	ioctl:	ad1816_mixer_ioctl};/* ------------------------------------------------------------------- *//* stuff for card recognition, init and unloading *//* replace with probe routine */static int __init probe_ad1816 ( struct address_info *hw_config ){	ad1816_info    *devc = &dev_info[nr_ad1816_devs];	int io_base=hw_config->io_base;	int *osp=hw_config->osp;	int tmp;	printk("ad1816: AD1816 sounddriver Copyright (C) 1998 by Thorsten Knabe\n");	printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, clockfreq=%d, options=%d isadmabug=%d\n",	       hw_config->io_base,	       hw_config->irq,	       hw_config->dma,	       hw_config->dma2,	       ad1816_clockfreq,	       options,	       isa_dma_bridge_buggy);	if (check_region (io_base, 16)) {		printk ("ad1816: I/O port 0x%03x not free\n", io_base);		return 0;	}	DEBUGLOG(printk ("ad1816: detect(%x)\n", io_base));		if (nr_ad1816_devs >= MAX_AUDIO_DEV) {		printk ("ad1816: detect error - step 0\n");		return 0;	}	devc->base = io_base;	devc->irq_ok = 0;	devc->irq = 0;	devc->opened = 0;	devc->osp = osp;	/* base+0: bit 1 must be set but not 255 */	tmp=inb(devc->base);	if ( (tmp&0x80)==0 || tmp==255 ) {		DEBUGLOG (printk ("ad1816: Chip is not an AD1816 or chip is not active (Test 0)\n"));		return(0);	}	/* writes to ireg 8 are copied to ireg 9 */	ad_write(devc,8,12345); 	if (ad_read(devc,9)!=12345) {		DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 1)\n"));		return(0);	}  	/* writes to ireg 8 are copied to ireg 9 */	ad_write(devc,8,54321); 	if (ad_read(devc,9)!=54321) {		DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 2)\n"));		return(0);	}	/* writes to ireg 10 are copied to ireg 11 */	ad_write(devc,10,54321); 	if (ad_read(devc,11)!=54321) {		DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 3)\n"));		return(0);	}	/* writes to ireg 10 are copied to ireg 11 */	ad_write(devc,10,12345); 	if (ad_read(devc,11)!=12345) {		DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 4)\n"));		return(0);	}	/* bit in base +1 cannot be set to 1 */	tmp=inb(devc->base+1);	outb(0xff,devc->base+1); 	if (inb(devc->base+1)!=tmp) {		DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 5)\n"));		return(0);	}  	DEBUGLOG (printk ("ad1816: detect() - Detected OK\n"));	DEBUGLOG (printk ("ad1816: AD1816 Version: %d\n",ad_read(devc,45)));	/*  detection was successful */	return 1; }/* allocate resources from the kernel. If any allocation fails, free   all allocated resources and exit attach.   */static void __init attach_ad1816 (struct address_info *hw_config){	int             my_dev;	char            dev_name[100];	ad1816_info    *devc = &dev_info[nr_ad1816_devs];		/* allocate i/o ports */       	request_region (hw_config->io_base, 16, "AD1816 Sound");	devc->base = hw_config->io_base;		/* disable all interrupts */	ad_write(devc,1,0);     	/* Clear pending interrupts */	outb (0, devc->base+1);		/* allocate irq */	if (hw_config->irq < 0 || hw_config->irq > 15) {		release_region(hw_config->io_base, 16);		return;	  	}	if (request_irq(hw_config->irq, ad1816_interrupt,0,			"SoundPort",			hw_config->osp) < 0)	{	        printk ("ad1816: IRQ in use\n");		release_region(hw_config->io_base, 16);		return;	}	devc->irq=hw_config->irq;	/* DMA stuff */	if (sound_alloc_dma (hw_config->dma, "Sound System")) {		printk ("ad1816: Can't allocate DMA%d\n", hw_config->dma);		free_irq(hw_config->irq,hw_config->osp);		release_region(hw_config->io_base, 16);		return;	}	devc->dma_playback=hw_config->dma;		if ( hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) {		if (sound_alloc_dma (hw_config->dma2, "Sound System (capture)")) {			printk ("ad1816: Can't allocate DMA%d\n", hw_config->dma2);			sound_free_dma(hw_config->dma);			free_irq(hw_config->irq,hw_config->osp);			release_region(hw_config->io_base, 16);			return;		}		devc->dma_capture=hw_config->dma2;		devc->audio_mode=DMA_AUTOMODE|DMA_DUPLEX;	} else {	        devc->dma_capture=-1;		devc->audio_mode=DMA_AUTOMODE;	}	sprintf (dev_name,"AD1816 audio driver");  	conf_printf2 (dev_name,		      devc->base, devc->irq, hw_config->dma, hw_config->dma2);	/* register device */	if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION,					      dev_name,					      &ad1816_audio_driver,					      sizeof (struct audio_driver),					      devc->audio_mode,					      ad_format_mask,					      devc,					      hw_config->dma, 					      hw_config->dma2)) < 0) {		printk ("ad1816: Can't install sound driver\n");		if (devc->dma_capture>=0) {		        sound_free_dma(hw_config->dma2);		}		sound_free_dma(hw_config->dma);		free_irq(hw_config->irq,hw_config->osp);		release_region(hw_config->io_base, 16);		return;	}	/* fill rest of structure with reasonable default values */	irq2dev[hw_config->irq] = devc->dev_no = my_dev;	devc->opened = 0;	devc->irq_ok = 0;	devc->osp = hw_config->osp;  	nr_ad1816_devs++;	ad_write(devc,32,0x80f0); /* sound system mode */	if (options&1) {	        ad_write(devc,33,0); /* disable all audiosources for dsp */	} else {	        ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */	}	ad_write(devc,4,0x8080);  /* default values for volumes (muted)*/	ad_write(devc,5,0x8080);	ad_write(devc,6,0x8080);	ad_write(devc,7,0x8080);	ad_write(devc,15,0x8888);	ad_write(devc,16,0x8888);	ad_write(devc,17,0x8888);	ad_write(devc,18,0x8888);	ad_write(devc,19,0xc888); /* +20db mic active */	ad_write(devc,14,0x0000); /* Master volume unmuted */	ad_write(devc,39,0x009f); /* 3D effect on 0% phone out muted */	ad_write(devc,44,0x0080); /* everything on power, 3d enabled for d/a */	outb(0x10,devc->base+8); /* set dma mode */	outb(0x10,devc->base+9);  	/* enable capture + playback interrupt */	ad_write(devc,1,0xc000); 		/* set mixer defaults */	ad1816_mixer_reset (devc);   	/* register mixer */	if ((audio_devs[my_dev]->mixer_dev=sound_install_mixer(				       MIXER_DRIVER_VERSION,				       dev_name,				       &ad1816_mixer_operations,				       sizeof (struct mixer_operations),				       devc)) >= 0) {		audio_devs[my_dev]->min_fragment = 0;	}}static void __exit unload_card(ad1816_info *devc){	int  mixer, dev = 0;		if (devc != NULL) {		DEBUGLOG (printk("ad1816: Unloading card at base=%x\n",devc->base));				dev = devc->dev_no;		mixer = audio_devs[dev]->mixer_dev;		/* unreg mixer*/		if(mixer>=0) {			sound_unload_mixerdev(mixer);		}		sound_unload_audiodev(dev);				/* free dma channels */		if (devc->dma_capture>=0) {			sound_free_dma(devc->dma_capture);		}		/* card wont get added if resources could not be allocated		   thus we need not ckeck if allocation was successful */		sound_free_dma (devc->dma_playback);		free_irq(devc->irq, devc->osp);		release_region (devc->base, 16);				DEBUGLOG (printk("ad1816: Unloading card at base=%x was successful\n",devc->base));			} else {		printk ("ad1816: no device/card specified\n");	}}static struct address_info cfg;static int __initdata io = -1;static int __initdata irq = -1;static int __initdata dma = -1;static int __initdata dma2 = -1;#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULEstruct pci_dev	*ad1816_dev  = NULL;static int activated	= 1;static int isapnp	= 1;static int isapnpjump	= 0;MODULE_PARM(isapnp, "i");MODULE_PARM(isapnpjump, "i");#elsestatic int isapnp = 0;#endifMODULE_PARM(io,"i");MODULE_PARM(irq,"i");MODULE_PARM(dma,"i");MODULE_PARM(dma2,"i");MODULE_PARM(ad1816_clockfreq,"i");MODULE_PARM(options,"i");#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULEstatic struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev){	int err;		if(dev->active) {		activated = 0;		return(dev);	}	if((err = dev->activate(dev)) < 0) {		printk(KERN_ERR "ad1816: %s %s config failed (out of resources?)[%d]\n",			devname, resname, err);		dev->deactivate(dev);		return(NULL);	}			return(dev);}static struct pci_dev *ad1816_init_generic(struct pci_bus *bus, struct pci_dev *card,	struct address_info *hw_config){	if((ad1816_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL))) {		ad1816_dev->prepare(ad1816_dev);				if((ad1816_dev = activate_dev("Analog Devices 1816(A)", "ad1816", ad1816_dev))) {			hw_config->io_base	= ad1816_dev->resource[2].start;			hw_config->irq		= ad1816_dev->irq_resource[0].start;			hw_config->dma		= ad1816_dev->dma_resource[0].start;			hw_config->dma2		= ad1816_dev->dma_resource[1].start;		}	}		return(ad1816_dev);}static struct {	unsigned short vendor;	unsigned short function;	struct pci_dev * (*initfunc)(struct pci_bus*, struct pci_dev *, struct address_info *);	char *name;} isapnp_ad1816_list[] __initdata = {	{ISAPNP_VENDOR('A','D','S'), ISAPNP_FUNCTION(0x7150), &ad1816_init_generic, "Analog Devices 1815" },	{ISAPNP_VENDOR('A','D','S'), ISAPNP_FUNCTION(0x7180), &ad1816_init_generic, "Analog Devices 1816A" },	{0}};static int __init ad1816_init_isapnp(struct address_info *hw_config,	struct pci_bus *bus, struct pci_dev *card, int slot){	struct pci_dev *idev = NULL;		/* You missed the init func? That's bad. */	if(isapnp_ad1816_list[slot].initfunc) {		char *busname = bus->name[0] ? bus->name : isapnp_ad1816_list[slot].name;				printk(KERN_INFO "ad1816: %s detected\n", busname);				/* Initialize this baby. */		if((idev = isapnp_ad1816_list[slot].initfunc(bus, card, hw_config))) {			/* We got it. */			printk(KERN_NOTICE "ad1816: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n",				busname,				hw_config->io_base, hw_config->irq, hw_config->dma,				hw_config->dma2);			return 1;		} else			printk(KERN_INFO "ad1816: Failed to initialize %s\n", busname);	} else		printk(KERN_ERR "ad1816: Bad entry in ad1816.c PnP table\n");		return 0;}/* * Actually this routine will detect and configure only the first card with successful * initialization. isapnpjump could be used to jump to a specific entry. * Please always add entries at the end of the array. * Should this be fixed? - azummo */int __init ad1816_probe_isapnp(struct address_info *hw_config){	int i;		/* Count entries in isapnp_ad1816_list */	for (i = 0; isapnp_ad1816_list[i].vendor != 0; i++)		;	/* Check and adjust isapnpjump */	if( isapnpjump < 0 || isapnpjump > ( i - 1 ) ) {		printk(KERN_ERR "ad1816: Valid range for isapnpjump is 0-%d. Adjusted to 0.\n", i-1);		isapnpjump = 0;	}	 for (i = isapnpjump; isapnp_ad1816_list[i].vendor != 0; i++) {	 	struct pci_dev *card = NULL;				while ((card = isapnp_find_dev(NULL, isapnp_ad1816_list[i].vendor,		  isapnp_ad1816_list[i].function, card)))			if(ad1816_init_isapnp(hw_config, card->bus, card, i))				return 0;	}	return -ENODEV;}#endifstatic int __init init_ad1816(void){#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE	if(isapnp && (ad1816_probe_isapnp(&cfg) < 0) ) {		printk(KERN_NOTICE "ad1816: No ISAPnP cards found, trying standard ones...\n");		isapnp = 0;	}#endif	if( isapnp == 0) {		cfg.io_base	= io;		cfg.irq		= irq;		cfg.dma		= dma;		cfg.dma2	= dma2;	}	if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.dma2 == -1) {		printk(KERN_INFO "ad1816: dma, dma2, irq and io must be set.\n");		return -EINVAL;	}	if (probe_ad1816(&cfg) == 0) {		return -ENODEV;	}	attach_ad1816(&cfg);	return 0;}static void __exit cleanup_ad1816 (void){	int          i;	ad1816_info  *devc = NULL;  	/* remove any soundcard */	for (i = 0;  i < nr_ad1816_devs; i++) {		devc = &dev_info[i];		unload_card(devc);	}     	nr_ad1816_devs=0;#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE	if(activated)		if(ad1816_dev)			ad1816_dev->deactivate(ad1816_dev);#endif}module_init(init_ad1816);module_exit(cleanup_ad1816);#ifndef MODULEstatic int __init setup_ad1816(char *str){	/* io, irq, dma, dma2 */	int ints[5];		str = get_options(str, ARRAY_SIZE(ints), ints);		io	= ints[1];	irq	= ints[2];	dma	= ints[3];	dma2	= ints[4];	return 1;}__setup("ad1816=", setup_ad1816);#endif

⌨️ 快捷键说明

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