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

📄 ad1816.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * * AD1816 lowlevel sound driver for Linux 2.2.0 and above * * Copyright (C) 1998 by Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de> * * Based on the CS4232/AD1848 driver Copyright (C) by Hannu Savolainen 1993-1996 * * * version: 1.3.1 * status: experimental * date: 1999/4/18 * * Changes: *	Oleg Drokin: Some cleanup of load/unload functions.	1998/11/24 *	 *	Thorsten Knabe: attach and unload rewritten,  *	some argument checks added				1998/11/30 * *	Thorsten Knabe: Buggy isa bridge workaround added	1999/01/16 *	 *	David Moews/Thorsten Knabe: Introduced options  *	parameter. Added slightly modified patch from  *	David Moews to disable dsp audio sources by setting  *	bit 0 of options parameter. This seems to be *	required by some Aztech/Newcom SC-16 cards.		1999/04/18 * *	Christoph Hellwig: Adapted to module_init/module_exit.	2000/03/03 * *	Christoph Hellwig: Added isapnp support			2000/03/15 */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/isapnp.h>#include <linux/stddef.h>#include "sound_config.h"#define DEBUGNOISE(x)#define DEBUGINFO(x)#define DEBUGLOG(x)#define DEBUGWARN(x)#define CHECK_FOR_POWER { int timeout=100; \  while (timeout > 0 && (inb(devc->base)&0x80)!= 0x80) {\          timeout--; \  } \  if (timeout==0) {\          printk("ad1816: Check for power failed in %s line: %d\n",__FILE__,__LINE__); \  } \}/* structure to hold device specific information */typedef struct{        int            base;          /* set in attach */	int            irq;	int            dma_playback;        int            dma_capture;          int            speed;         /* open */	int            channels;	int            audio_format;	unsigned char  format_bits;        int            audio_mode; 	int            opened;          int            recmask;        /* setup */	int            supported_devices;	int            supported_rec_devices;	unsigned short levels[SOUND_MIXER_NRDEVICES];        int            dev_no;   /* this is the # in audio_devs and NOT 				    in ad1816_info */	int            irq_ok;	int            *osp;  } ad1816_info;static int nr_ad1816_devs = 0;static int ad1816_clockfreq=33000;static int options=0;/* for backward mapping of irq to sound device */static volatile char irq2dev[17] = {-1, -1, -1, -1, -1, -1, -1, -1,				    -1, -1, -1, -1, -1, -1, -1, -1, -1};/* supported audio formats */static int  ad_format_mask =AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW;/* array of device info structures */static ad1816_info dev_info[MAX_AUDIO_DEV];/* ------------------------------------------------------------------- *//* functions for easier access to inderect registers */static int ad_read (ad1816_info * devc, int reg){	unsigned long   flags;	int result;		CHECK_FOR_POWER;	save_flags (flags); /* make register access atomic */	cli ();	outb ((unsigned char) (reg & 0x3f), devc->base+0);	result = inb(devc->base+2);	result+= inb(devc->base+3)<<8;	restore_flags (flags);		return (result);}static void ad_write (ad1816_info * devc, int reg, int data){	unsigned long flags;		CHECK_FOR_POWER;		save_flags (flags); /* make register access atomic */	cli ();	outb ((unsigned char) (reg & 0xff), devc->base+0);	outb ((unsigned char) (data & 0xff),devc->base+2);	outb ((unsigned char) ((data>>8)&0xff),devc->base+3);	restore_flags (flags);}/* ------------------------------------------------------------------- *//* function interface required by struct audio_driver */static void ad1816_halt_input (int dev){	unsigned long flags;	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;	unsigned char buffer;		DEBUGINFO (printk("ad1816: halt_input called\n"));		save_flags (flags); 	cli ();		if(!isa_dma_bridge_buggy) {	        disable_dma(audio_devs[dev]->dmap_in->dma);	}		buffer=inb(devc->base+9);	if (buffer & 0x01) {		/* disable capture */		outb(buffer & ~0x01,devc->base+9); 	}	if(!isa_dma_bridge_buggy) {	        enable_dma(audio_devs[dev]->dmap_in->dma);	}	/* Clear interrupt status */	outb (~0x40, devc->base+1);			devc->audio_mode &= ~PCM_ENABLE_INPUT;	restore_flags (flags);}static void ad1816_halt_output (int dev){	unsigned long  flags;	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;		unsigned char buffer;	DEBUGINFO (printk("ad1816: halt_output called!\n"));	save_flags (flags); 	cli ();	/* Mute pcm output */	ad_write(devc, 4, ad_read(devc,4)|0x8080);	if(!isa_dma_bridge_buggy) {	        disable_dma(audio_devs[dev]->dmap_out->dma);	}	buffer=inb(devc->base+8);	if (buffer & 0x01) {		/* disable capture */		outb(buffer & ~0x01,devc->base+8); 	}	if(!isa_dma_bridge_buggy) {	        enable_dma(audio_devs[dev]->dmap_out->dma);	}	/* Clear interrupt status */	outb ((unsigned char)~0x80, devc->base+1);		devc->audio_mode &= ~PCM_ENABLE_OUTPUT;	restore_flags (flags);}static void ad1816_output_block (int dev, unsigned long buf, 				 int count, int intrflag){	unsigned long flags;	unsigned long cnt;	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;		DEBUGINFO(printk("ad1816: output_block called buf=%ld count=%d flags=%d\n",buf,count,intrflag));  	cnt = count/4 - 1;  	save_flags (flags);	cli ();		/* set transfer count */	ad_write (devc, 8, cnt & 0xffff); 		devc->audio_mode |= PCM_ENABLE_OUTPUT; 	restore_flags (flags);}static void ad1816_start_input (int dev, unsigned long buf, int count,				int intrflag){	unsigned long flags;	unsigned long  cnt;	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;		DEBUGINFO(printk("ad1816: start_input called buf=%ld count=%d flags=%d\n",buf,count,intrflag));	cnt = count/4 - 1;	save_flags (flags); /* make register access atomic */	cli ();	/* set transfer count */	ad_write (devc, 10, cnt & 0xffff); 	devc->audio_mode |= PCM_ENABLE_INPUT;	restore_flags (flags);}static int ad1816_prepare_for_input (int dev, int bsize, int bcount){	unsigned long flags;	unsigned int freq;	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;	unsigned char fmt_bits;		DEBUGINFO (printk ("ad1816: prepare_for_input called: bsize=%d bcount=%d\n",bsize,bcount));	save_flags (flags); 	cli ();		fmt_bits= (devc->format_bits&0x7)<<3;		/* set mono/stereo mode */	if (devc->channels > 1) {		fmt_bits |=0x4;	}	/* set Mono/Stereo in playback/capture register */	outb( (inb(devc->base+8) & ~0x3C)|fmt_bits, devc->base+8); 	outb( (inb(devc->base+9) & ~0x3C)|fmt_bits, devc->base+9);  	/* If compiled into kernel, AD1816_CLOCK is defined, so use it */#ifdef AD1816_CLOCK 	ad1816_clockfreq=AD1816_CLOCK;#endif	/* capture/playback frequency correction for soundcards 	   with clock chips != 33MHz (allowed range 5 - 100 kHz) */	if (ad1816_clockfreq<5000 || ad1816_clockfreq>100000) {		ad1816_clockfreq=33000;	}		freq=((unsigned int)devc->speed*33000)/ad1816_clockfreq; 	/* write playback/capture speeds */	ad_write (devc, 2, freq & 0xffff);		ad_write (devc, 3, freq & 0xffff);		restore_flags (flags);	ad1816_halt_input(dev);	return 0;}static int ad1816_prepare_for_output (int dev, int bsize, int bcount){	unsigned long flags;	unsigned int freq;	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;	unsigned char fmt_bits;	DEBUGINFO (printk ("ad1816: prepare_for_output called: bsize=%d bcount=%d\n",bsize,bcount));	save_flags (flags); /* make register access atomic */	cli ();	fmt_bits= (devc->format_bits&0x7)<<3;	/* set mono/stereo mode */	if (devc->channels > 1) {		fmt_bits |=0x4;	}	/* write format bits to playback/capture registers */	outb( (inb(devc->base+8) & ~0x3C)|fmt_bits, devc->base+8); 	outb( (inb(devc->base+9) & ~0x3C)|fmt_bits, devc->base+9);  #ifdef AD1816_CLOCK 	ad1816_clockfreq=AD1816_CLOCK;#endif	/* capture/playback frequency correction for soundcards 	   with clock chips != 33MHz (allowed range 5 - 100 kHz)*/	if (ad1816_clockfreq<5000 || ad1816_clockfreq>100000) {		ad1816_clockfreq=33000;	}  	freq=((unsigned int)devc->speed*33000)/ad1816_clockfreq; 		/* write playback/capture speeds */	ad_write (devc, 2, freq & 0xffff);	ad_write (devc, 3, freq & 0xffff);	restore_flags (flags);		ad1816_halt_output(dev);	return 0;}static void ad1816_trigger (int dev, int state) {	unsigned long flags;	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;	DEBUGINFO (printk("ad1816: trigger called! (devc=%d,devc->base=%d\n", devc, devc->base));	/* mode may have changed */	save_flags (flags); /* make register access atomic */	cli ();	/* mask out modes not specified on open call */	state &= devc->audio_mode; 					/* setup soundchip to new io-mode */	if (state & PCM_ENABLE_INPUT) {		/* enable capture */		outb(inb(devc->base+9)|0x01, devc->base+9);	} else {		/* disable capture */		outb(inb(devc->base+9)&~0x01, devc->base+9);	}	if (state & PCM_ENABLE_OUTPUT) {		/* enable playback */		outb(inb(devc->base+8)|0x01, devc->base+8);		/* unmute pcm output */		ad_write(devc, 4, ad_read(devc,4)&~0x8080);	} else {		/* mute pcm output */		ad_write(devc, 4, ad_read(devc,4)|0x8080);		/* disable capture */		outb(inb(devc->base+8)&~0x01, devc->base+8);	}	restore_flags (flags);}/* halt input & output */static void ad1816_halt (int dev){	ad1816_halt_input(dev);	ad1816_halt_output(dev);}static void ad1816_reset (int dev){	ad1816_halt (dev);}/* set playback speed */static int ad1816_set_speed (int dev, int arg){	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;		if (arg == 0) {		return devc->speed;	}	/* range checking */	if (arg < 4000) {		arg = 4000;	}	if (arg > 55000) {		arg = 55000;	}	devc->speed = arg;	return devc->speed;}static unsigned int ad1816_set_bits (int dev, unsigned int arg){	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;		static struct format_tbl {		int             format;		unsigned char   bits;	} format2bits[] = {		{ 0, 0 },		{ AFMT_MU_LAW, 1 },		{ AFMT_A_LAW, 3 },		{ AFMT_IMA_ADPCM, 0 },		{ AFMT_U8, 0 },		{ AFMT_S16_LE, 2 },		{ AFMT_S16_BE, 6 },		{ AFMT_S8, 0 },		{ AFMT_U16_LE, 0 },		{ AFMT_U16_BE, 0 }  	};	int  i, n = sizeof (format2bits) / sizeof (struct format_tbl);	/* return current format */	if (arg == 0)		return devc->audio_format;		devc->audio_format = arg;	/* search matching format bits */	for (i = 0; i < n; i++)		if (format2bits[i].format == arg) {			devc->format_bits = format2bits[i].bits;			devc->audio_format = arg;			return arg;		}	/* Still hanging here. Something must be terribly wrong */	devc->format_bits = 0;	return devc->audio_format = AFMT_U8;}static short ad1816_set_channels (int dev, short arg){	ad1816_info    *devc = (ad1816_info *) audio_devs[dev]->devc;	if (arg != 1 && arg != 2)		return devc->channels;	devc->channels = arg;	return arg;}/* open device */static int ad1816_open (int dev, int mode) {	ad1816_info    *devc = NULL;	unsigned long   flags;	/* is device number valid ? */	if (dev < 0 || dev >= num_audiodevs)		return -(ENXIO);	/* get device info of this dev */	devc = (ad1816_info *) audio_devs[dev]->devc; 	/* make check if device already open atomic */	save_flags (flags); 	cli ();	if (devc->opened) {		restore_flags (flags);		return -(EBUSY);	}

⌨️ 快捷键说明

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