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

📄 sb16.c

📁 Minix比较全的源码
💻 C
字号:
/*  Driver for SB16 ISA card *  Implementing audio/audio_fw.h *	 *  February 2006   Integrated standalone driver with audio framework (Peter Boonstoppel) *  August 24 2005  Ported audio driver to user space (only audio playback) (Peter Boonstoppel) *  May 20 1995	    SB16 Driver: Michel R. Prevenier  */#include "sb16.h"#include "mixer.h"FORWARD _PROTOTYPE( void dsp_dma_setup, (phys_bytes address, int count, int sub_dev) );FORWARD _PROTOTYPE( int dsp_ioctl, (int request, void *val, int *len));FORWARD _PROTOTYPE( int dsp_set_size, (unsigned int size) );FORWARD _PROTOTYPE( int dsp_set_speed, (unsigned int speed) );FORWARD _PROTOTYPE( int dsp_set_stereo, (unsigned int stereo) );FORWARD _PROTOTYPE( int dsp_set_bits, (unsigned int bits) );FORWARD _PROTOTYPE( int dsp_set_sign, (unsigned int sign) );FORWARD _PROTOTYPE( int dsp_get_max_frag_size, (u32_t *val, int *len) );PRIVATE unsigned int DspStereo = DEFAULT_STEREO;PRIVATE unsigned int DspSpeed = DEFAULT_SPEED; PRIVATE unsigned int DspBits = DEFAULT_BITS;PRIVATE unsigned int DspSign = DEFAULT_SIGN;PRIVATE unsigned int DspFragmentSize;PRIVATE phys_bytes DmaPhys;PRIVATE int running = FALSE;PUBLIC sub_dev_t sub_dev[2];PUBLIC special_file_t special_file[3];PUBLIC drv_t drv;PUBLIC int drv_init(void) {	drv.DriverName = "SB16";	drv.NrOfSubDevices = 2;	drv.NrOfSpecialFiles = 3;		sub_dev[AUDIO].readable = 1;	sub_dev[AUDIO].writable = 1;	sub_dev[AUDIO].DmaSize = 64 * 1024;	sub_dev[AUDIO].NrOfDmaFragments = 2;	sub_dev[AUDIO].MinFragmentSize = 1024;	sub_dev[AUDIO].NrOfExtraBuffers = 4;	sub_dev[MIXER].writable = 0;	sub_dev[MIXER].readable = 0;		special_file[0].minor_dev_nr = 0;	special_file[0].write_chan = AUDIO;	special_file[0].read_chan = NO_CHANNEL;	special_file[0].io_ctl = AUDIO;	special_file[1].minor_dev_nr = 1;	special_file[1].write_chan = NO_CHANNEL;	special_file[1].read_chan = AUDIO;	special_file[1].io_ctl = AUDIO;	special_file[2].minor_dev_nr = 2;	special_file[2].write_chan = NO_CHANNEL;	special_file[2].read_chan = NO_CHANNEL;	special_file[2].io_ctl = MIXER;}PUBLIC int drv_init_hw(void) {	int i, s;	int DspVersion[2];	dprint("drv_init_hw():\n");	if(drv_reset () != OK) { 		dprint("sb16: No SoundBlaster card detected\n");		return -1;	}	DspVersion[0] = DspVersion[1] = 0;	dsp_command(DSP_GET_VERSION);	/* Get DSP version bytes */	for(i = 1000; i; i--) {		if(sb16_inb(DSP_DATA_AVL) & 0x80) {					if(DspVersion[0] == 0) {				DspVersion[0] = sb16_inb(DSP_READ);			} else {				DspVersion[1] = sb16_inb(DSP_READ);				break;			}		}	}	if(DspVersion[0] < 4) {		dprint("sb16: No SoundBlaster 16 compatible card detected\n");		return -1;	} 		dprint("sb16: SoundBlaster DSP version %d.%d detected!\n", DspVersion[0], DspVersion[1]);	/* set SB to use our IRQ and DMA channels */	mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1)));	mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16));	DspFragmentSize = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments;	return OK;}PUBLIC int drv_reset(void) {	int i;	dprint("drv_reset():\n");	sb16_outb(DSP_RESET, 1);	for(i = 0; i < 1000; i++); /* wait a while */	sb16_outb(DSP_RESET, 0);	for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++); 			if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */	return OK;}PUBLIC int drv_start(int channel, int DmaMode) {	dprint("drv_start():\n");	drv_reset();	dsp_dma_setup(DmaPhys, DspFragmentSize * sub_dev[channel].NrOfDmaFragments, DmaMode);	dsp_set_speed(DspSpeed);	/* Put the speaker on */	if(DmaMode == DEV_WRITE) {		dsp_command (DSP_CMD_SPKON); /* put speaker on */		/* Program DSP with dma mode */		dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_OUT : DSP_CMD_16BITAUTO_OUT));     	} else {		dsp_command (DSP_CMD_SPKOFF); /* put speaker off */		/* Program DSP with dma mode */		dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_IN : DSP_CMD_16BITAUTO_IN));     	}	/* Program DSP with transfer mode */	if (!DspSign) {		dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_US : DSP_MODE_MONO_US));	} else {		dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_S : DSP_MODE_MONO_S));	}	/* Give length of fragment to DSP */	if (DspBits == 8) { /* 8 bit transfer */		/* #bytes - 1 */		dsp_command((DspFragmentSize - 1) >> 0); 		dsp_command((DspFragmentSize - 1) >> 8);	} else {             /* 16 bit transfer */		/* #words - 1 */		dsp_command((DspFragmentSize - 1) >> 1);		dsp_command((DspFragmentSize - 1) >> 9);	}	running = TRUE;	return OK;}PUBLIC int drv_stop(int sub_dev) {	if(running) {		dprint("drv_stop():\n");		dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));		running = FALSE;		drv_reenable_int(sub_dev);	}	return OK;}PUBLIC int drv_set_dma(u32_t dma, u32_t length, int chan) {	dprint("drv_set_dma():\n");	DmaPhys = dma;	return OK;}PUBLIC int drv_reenable_int(int chan) {	dprint("drv_reenable_int()\n");	sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));	return OK;}PUBLIC int drv_int_sum(void) {	return mixer_get(MIXER_IRQ_STATUS) & 0x0F;}PUBLIC int drv_int(int sub_dev) {	return sub_dev == AUDIO && mixer_get(MIXER_IRQ_STATUS) & 0x03;}PUBLIC int drv_pause(int chan) {	drv_stop(chan);	return OK;}PUBLIC int drv_resume(int chan) {	dsp_command((DspBits == 8 ? DSP_CMD_DMA8CONT : DSP_CMD_DMA16CONT));	return OK;}PUBLIC int drv_io_ctl(int request, void *val, int *len, int sub_dev) {	dprint("dsp_ioctl: got ioctl %d, argument: %d sub_dev: %d\n", request, val, sub_dev);	if(sub_dev == AUDIO) {		return dsp_ioctl(request, val, len);	} else if(sub_dev == MIXER) {		return mixer_ioctl(request, val, len);	} 	return EIO;}PUBLIC int drv_get_irq(char *irq) {	dprint("drv_get_irq():\n");	*irq = SB_IRQ;	return OK;}PUBLIC int drv_get_frag_size(u32_t *frag_size, int sub_dev) {	dprint("drv_get_frag_size():\n");	*frag_size = DspFragmentSize;	return OK;}PRIVATE int dsp_ioctl(int request, void *val, int *len) {	int status;		switch(request) {		case DSPIORATE:		status = dsp_set_speed(*((u32_t*) val)); break;		case DSPIOSTEREO:	status = dsp_set_stereo(*((u32_t*) val)); break;		case DSPIOBITS:		status = dsp_set_bits(*((u32_t*) val)); break;		case DSPIOSIZE:		status = dsp_set_size(*((u32_t*) val)); break;		case DSPIOSIGN:		status = dsp_set_sign(*((u32_t*) val)); break;		case DSPIOMAX:		status = dsp_get_max_frag_size(val, len); break;		case DSPIORESET:    status = drv_reset(); break;		default:            status = ENOTTY; break;	}	return status;}PRIVATE void dsp_dma_setup(phys_bytes address, int count, int DmaMode) {	pvb_pair_t pvb[9];	dprint("Setting up %d bit DMA\n", DspBits);	if(DspBits == 8) {   /* 8 bit sound */		count--;     		pv_set(pvb[0], DMA8_MASK, SB_DMA_8 | 0x04);      /* Disable DMA channel */		pv_set(pvb[1], DMA8_CLEAR, 0x00);		       /* Clear flip flop */		/* set DMA mode */		pv_set(pvb[2], DMA8_MODE, (DmaMode == DEV_WRITE ? DMA8_AUTO_PLAY : DMA8_AUTO_REC)); 		pv_set(pvb[3], DMA8_ADDR, address >>  0);        /* Low_byte of address */		pv_set(pvb[4], DMA8_ADDR, address >>  8);        /* High byte of address */		pv_set(pvb[5], DMA8_PAGE, address >> 16);        /* 64K page number */		pv_set(pvb[6], DMA8_COUNT, count >> 0);          /* Low byte of count */		pv_set(pvb[7], DMA8_COUNT, count >> 8);          /* High byte of count */		pv_set(pvb[8], DMA8_MASK, SB_DMA_8);	       /* Enable DMA channel */		sys_voutb(pvb, 9);	} else {  /* 16 bit sound */		count -= 2;		pv_set(pvb[0], DMA16_MASK, (SB_DMA_16 & 3) | 0x04);	/* Disable DMA channel */				pv_set(pvb[1], DMA16_CLEAR, 0x00);                  /* Clear flip flop */		/* Set dma mode */		pv_set(pvb[2], DMA16_MODE, (DmaMode == DEV_WRITE ? DMA16_AUTO_PLAY : DMA16_AUTO_REC));        		pv_set(pvb[3], DMA16_ADDR, (address >> 1) & 0xFF);  /* Low_byte of address */		pv_set(pvb[4], DMA16_ADDR, (address >> 9) & 0xFF);  /* High byte of address */		pv_set(pvb[5], DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */		pv_set(pvb[6], DMA16_COUNT, count >> 1);            /* Low byte of count */		pv_set(pvb[7], DMA16_COUNT, count >> 9);            /* High byte of count */		pv_set(pvb[8], DMA16_MASK, SB_DMA_16 & 3);          /* Enable DMA channel */		sys_voutb(pvb, 9);	}}PRIVATE int dsp_set_size(unsigned int size) {	dprint("dsp_set_size(): set fragment size to %u\n", size);	/* Sanity checks */	if(size < sub_dev[AUDIO].MinFragmentSize || size > sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments || size % 2 != 0) {		return EINVAL;	}	DspFragmentSize = size; 	return OK;}PRIVATE int dsp_set_speed(unsigned int speed) {	dprint("sb16: setting speed to %u, stereo = %d\n", speed, DspStereo);	if(speed < DSP_MIN_SPEED || speed > DSP_MAX_SPEED) {		return EPERM;	}	/* Soundblaster 16 can be programmed with real sample rates	* instead of time constants	*	* Since you cannot sample and play at the same time	* we set in- and output rate to the same value 	*/	dsp_command(DSP_INPUT_RATE);		/* set input rate */	dsp_command(speed >> 8);			/* high byte of speed */	dsp_command(speed);			 		/* low byte of speed */	dsp_command(DSP_OUTPUT_RATE);		/* same for output rate */	dsp_command(speed >> 8);		dsp_command(speed); 	DspSpeed = speed;	return OK;}PRIVATE int dsp_set_stereo(unsigned int stereo) {	if(stereo) { 		DspStereo = 1;	} else { 		DspStereo = 0;	}	return OK;}PRIVATE int dsp_set_bits(unsigned int bits) {	/* Sanity checks */	if(bits != 8 && bits != 16) {		return EINVAL;	}	DspBits = bits; 	return OK;}PRIVATE int dsp_set_sign(unsigned int sign) {	dprint("sb16: set sign to %u\n", sign);	DspSign = (sign > 0 ? 1 : 0); 	return OK;}PRIVATE int dsp_get_max_frag_size(u32_t *val, int *len) {	*len = sizeof(*val);	*val = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments;	return OK;}PUBLIC int dsp_command(int value) {	int i, status;	for (i = 0; i < SB_TIMEOUT; i++) {		if((sb16_inb(DSP_STATUS) & 0x80) == 0) {			sb16_outb(DSP_COMMAND, value);			return OK;		}	}	dprint("sb16: SoundBlaster: DSP Command(%x) timeout\n", value);	return -1;}PUBLIC int sb16_inb(int port) {		int s, value = -1;	if ((s=sys_inb(port, &value)) != OK)		panic("SB16DSP","sys_inb() failed", s);		return value;}PUBLIC void sb16_outb(int port, int value) {	int s;		if ((s=sys_outb(port, value)) != OK)		panic("SB16DSP","sys_outb() failed", s);}

⌨️ 快捷键说明

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