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

📄 audio_fw.c

📁 Minix比较全的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Best viewed with tabsize 4 * * This file contains a standard driver for audio devices. * It supports double dma buffering and can be configured to use * extra buffer space beside the dma buffer. * This driver also support sub devices, which can be independently  * opened and closed.    * * The driver supports the following operations: * *    m_type      DEVICE    IO_ENDPT     COUNT    POSITION  ADRRESS * ----------------------------------------------------------------- * | DEV_OPEN    | device  | proc nr |         |         |         | * |-------------+---------+---------+---------+---------+---------| * | DEV_CLOSE   | device  | proc nr |         |         |         | * |-------------+---------+---------+---------+---------+---------| * | DEV_READ_S  | device  | proc nr |  bytes  |         | buf ptr | * |-------------+---------+---------+---------+---------+---------| * | DEV_WRITE_S | device  | proc nr |  bytes  |         | buf ptr | * |-------------+---------+---------+---------+---------+---------| * | DEV_IOCTL_S | device  | proc nr |func code|         | buf ptr | * |-------------+---------+---------+---------+---------+---------| * | DEV_STATUS  |         |         |         |         |         | * |-------------+---------+---------+---------+---------+---------| * | HARD_INT    |         |         |         |         |         |  * |-------------+---------+---------+---------+---------+---------| * | SIG_STOP    |         |         |         |         |         |  * -----------------------------------------------------------------  *  * The file contains one entry point: * *   main:	main entry when driver is brought up *	 *	October 2007	Updated audio framework to work with mplayer, added *					savecopies (Pieter Hijma) *  February 2006   Updated audio framework,  *		changed driver-framework relation (Peter Boonstoppel) *  November 2005   Created generic DMA driver framework (Laurens Bronwasser) *  August 24 2005  Ported audio driver to user space  *		(only audio playback) (Peter Boonstoppel) *  May 20 1995	    SB16 Driver: Michel R. Prevenier  */#include "audio_fw.h"FORWARD _PROTOTYPE( int msg_open, (int minor_dev_nr) );FORWARD _PROTOTYPE( int msg_close, (int minor_dev_nr) );FORWARD _PROTOTYPE( int msg_ioctl, (message *m_ptr) );FORWARD _PROTOTYPE( void msg_write, (message *m_ptr) );FORWARD _PROTOTYPE( void msg_read, (message *m_ptr) );FORWARD _PROTOTYPE( void msg_hardware, (void) );FORWARD _PROTOTYPE( void msg_sig_stop, (void) );FORWARD _PROTOTYPE( void msg_status, (message *m_ptr) );FORWARD _PROTOTYPE( int init_driver, (void) );FORWARD _PROTOTYPE( int open_sub_dev, (int sub_dev_nr, int operation) );FORWARD _PROTOTYPE( int close_sub_dev, (int sub_dev_nr) );FORWARD _PROTOTYPE( void handle_int_write,(int sub_dev_nr) );FORWARD _PROTOTYPE( void handle_int_read,(int sub_dev_nr) );FORWARD _PROTOTYPE( void data_to_user, (sub_dev_t *sub_dev_ptr) );FORWARD _PROTOTYPE( void data_from_user, (sub_dev_t *sub_dev_ptr) );FORWARD _PROTOTYPE( int init_buffers, (sub_dev_t *sub_dev_ptr) );FORWARD _PROTOTYPE( int get_started, (sub_dev_t *sub_dev_ptr) );FORWARD _PROTOTYPE( void reply,(int code, int replyee, int process,int status));FORWARD _PROTOTYPE( int io_ctl_length, (int io_request) );FORWARD _PROTOTYPE( special_file_t* get_special_file, (int minor_dev_nr) );PRIVATE char io_ctl_buf[_IOCPARM_MASK];PRIVATE int irq_hook_id = 0;	/* id of irq hook at the kernel */PRIVATE int irq_hook_set = FALSE;PRIVATE device_available = 0;/*todo*/PUBLIC void main(void) {		int r, caller, proc_nr, chan;	message mess;	drv_init();	/* Here is the main loop of the dma driver.  It waits for a message, 	   carries it out, and sends a reply. */	printf("%s up and running\n", drv.DriverName);	while(1) {		receive(ANY, &mess);		caller = mess.m_source;		proc_nr = mess.IO_ENDPT;		/* Now carry out the work. */		switch(mess.m_type) {			case DEV_OPEN:		/* open the special file ( = parameter) */				r = msg_open(mess.DEVICE);break;			case DEV_CLOSE:		/* close the special file ( = parameter) */				r = msg_close(mess.DEVICE); break;			case DEV_IOCTL_S:						r = msg_ioctl(&mess); break; 			case DEV_READ_S:						msg_read(&mess); continue; /* don't reply */			case DEV_WRITE_S:						msg_write(&mess); continue; /* don't reply */			case DEV_STATUS:					msg_status(&mess);continue; /* don't reply */			case HARD_INT:				msg_hardware();continue;  /* don't reply */			case SYS_SIG:		  				msg_sig_stop(); continue; /* don't reply */			default:          				r = EINVAL;					dprint("%s: %d uncaught msg!\n", drv.DriverName, mess.m_type);				break;		}		/* Finally, prepare and send the reply message. */		reply(TASK_REPLY, caller, proc_nr, r);	}}PRIVATE int init_driver(void) {	u32_t i; char irq;	static int executed = 0;	sub_dev_t* sub_dev_ptr;	/* init variables, get dma buffers */	for (i = 0; i < drv.NrOfSubDevices; i++) {		sub_dev_ptr = &sub_dev[i];		sub_dev_ptr->Opened = FALSE;		sub_dev_ptr->DmaBusy = FALSE;		sub_dev_ptr->DmaMode = NO_DMA;		sub_dev_ptr->DmaReadNext = 0;		sub_dev_ptr->DmaFillNext = 0;		sub_dev_ptr->DmaLength = 0;		sub_dev_ptr->BufReadNext = 0;		sub_dev_ptr->BufFillNext = 0;		sub_dev_ptr->RevivePending = FALSE;		sub_dev_ptr->OutOfData = FALSE;		sub_dev_ptr->Nr = i;	}	/* initialize hardware*/	if (drv_init_hw() != OK) {		error("%s: Could not initialize hardware\n", drv.DriverName, 0);		return EIO;	}	/* get irq from device driver...*/	if (drv_get_irq(&irq) != OK) {		error("%s: init driver couldn't get IRQ", drv.DriverName, i);		return EIO;	}	/* todo: execute the rest of this function only once 	   we don't want to set irq policy twice */	if (executed) return OK;	executed = TRUE;	/* ...and register interrupt vector */	if ((i=sys_irqsetpolicy(irq, 0, &irq_hook_id )) != OK){		error("%s: init driver couldn't set IRQ policy", drv.DriverName, i);		return EIO;	}	irq_hook_set = TRUE; /* now msg_sig_stop knows it must unregister policy*/	return OK;}PRIVATE int msg_open (int minor_dev_nr) {	int r, read_chan, write_chan, io_ctl;	special_file_t* special_file_ptr;	dprint("%s: msg_open() special file %d\n", drv.DriverName, minor_dev_nr);	special_file_ptr = get_special_file(minor_dev_nr);	if(special_file_ptr == NULL) {		return EIO;	}	read_chan = special_file_ptr->read_chan;	write_chan = special_file_ptr->write_chan;	io_ctl = special_file_ptr->io_ctl;	if (read_chan==NO_CHANNEL && write_chan==NO_CHANNEL && io_ctl==NO_CHANNEL) {		error("%s: No channel specified for minor device!\n", 				drv.DriverName, minor_dev_nr);		return EIO;	}	if (read_chan == write_chan && read_chan != NO_CHANNEL) {		error("%s: Read and write channels are equal!\n", 				drv.DriverName, minor_dev_nr);		return EIO;	}	/* init driver */	if (!device_available) {  		if (init_driver() != OK) {			error("%s: Couldn't init driver!\n", drv.DriverName, minor_dev_nr);			return EIO;		} else {			device_available = TRUE;		}	}  	/* open the sub devices specified in the interface header file */	if (write_chan != NO_CHANNEL) {		/* open sub device for writing */		if (open_sub_dev(write_chan, DEV_WRITE_S) != OK) return EIO;	}  	if (read_chan != NO_CHANNEL) {		if (open_sub_dev(read_chan, DEV_READ_S) != OK) return EIO;	}	if (read_chan == io_ctl || write_chan == io_ctl) {		/* io_ctl is already opened because it's the same as read or write */		return OK; /* we're done */	}	if (io_ctl != NO_CHANNEL) { /* Ioctl differs from read/write channels, */		r = open_sub_dev(io_ctl, NO_DMA); /* open it explicitly */		if (r != OK) return EIO;	} 	return OK;}PRIVATE int open_sub_dev(int sub_dev_nr, int dma_mode) {	sub_dev_t* sub_dev_ptr; int i;	sub_dev_ptr = &sub_dev[sub_dev_nr];	/* Only one open at a time per sub device */	if (sub_dev_ptr->Opened) { 		error("%s: Sub device %d is already opened\n", 				drv.DriverName, sub_dev_nr);		return EBUSY;	}	if (sub_dev_ptr->DmaBusy) { 		error("%s: Sub device %d is still busy\n", drv.DriverName, sub_dev_nr);		return EBUSY;	}	/* Setup variables */	sub_dev_ptr->Opened = TRUE;	sub_dev_ptr->DmaReadNext = 0;	sub_dev_ptr->DmaFillNext = 0;	sub_dev_ptr->DmaLength = 0;	sub_dev_ptr->DmaMode = dma_mode;	sub_dev_ptr->BufReadNext = 0;	sub_dev_ptr->BufFillNext = 0;	sub_dev_ptr->BufLength = 0;	sub_dev_ptr->RevivePending = FALSE;	sub_dev_ptr->OutOfData = TRUE;	/* arrange DMA */	if (dma_mode != NO_DMA) { /* sub device uses DMA */		/* allocate dma buffer and extra buffer space		   and configure sub device for dma */		if (init_buffers(sub_dev_ptr) != OK ) return EIO;	}	return OK;  }PRIVATE int msg_close(int minor_dev_nr) {	int r, read_chan, write_chan, io_ctl; 	special_file_t* special_file_ptr;	dprint("%s: msg_close() minor device %d\n", drv.DriverName, minor_dev_nr);	special_file_ptr = get_special_file(minor_dev_nr);	if(special_file_ptr == NULL) {		return EIO;	}	read_chan = special_file_ptr->read_chan;	write_chan = special_file_ptr->write_chan;	io_ctl = special_file_ptr->io_ctl;	/* close all sub devices */	if (write_chan != NO_CHANNEL) {		if (close_sub_dev(write_chan) != OK) r = EIO;	}  	if (read_chan != NO_CHANNEL) {		if (close_sub_dev(read_chan) != OK) r = EIO;	}	if (read_chan == io_ctl || write_chan == io_ctl) {		/* io_ctl is already closed because it's the same as read or write */		return r; /* we're done */	}	/* ioctl differs from read/write channels... */	if (io_ctl != NO_CHANNEL) { 		if (close_sub_dev(io_ctl) != OK) r = EIO; /* ...close it explicitly */	} 	return r;}PRIVATE int close_sub_dev(int sub_dev_nr) {	sub_dev_t *sub_dev_ptr;	sub_dev_ptr = &sub_dev[sub_dev_nr];	if (sub_dev_ptr->DmaMode == DEV_WRITE_S && !sub_dev_ptr->OutOfData) {		/* do nothing, still data in buffers that has to be transferred */		sub_dev_ptr->Opened = FALSE;  /* keep DMA busy */		return OK;	}	if (sub_dev_ptr->DmaMode == NO_DMA) {		/* do nothing, there is no dma going on */		sub_dev_ptr->Opened = FALSE;		return OK;	}	sub_dev_ptr->Opened = FALSE;	sub_dev_ptr->DmaBusy = FALSE;	/* stop the device */	drv_stop(sub_dev_ptr->Nr);	/* free the buffers */	free(sub_dev_ptr->DmaBuf);	free(sub_dev_ptr->ExtraBuf);}PRIVATE int msg_ioctl(message *m_ptr){	int status, len, chan;	phys_bytes user_phys;	sub_dev_t *sub_dev_ptr;	special_file_t* special_file_ptr;	dprint("%s: msg_ioctl() device %d\n", drv.DriverName, m_ptr->DEVICE);	special_file_ptr = get_special_file(m_ptr->DEVICE);	if(special_file_ptr == NULL) {		return EIO;	}	chan = special_file_ptr->io_ctl;	if (chan == NO_CHANNEL) {		error("%s: No io control channel specified!\n", drv.DriverName);		return EIO;	}	/* get pointer to sub device data */	sub_dev_ptr = &sub_dev[chan];	if(!sub_dev_ptr->Opened) {		error("%s: io control impossible - not opened!\n", drv.DriverName);		return EIO;	}	/* this is a hack...todo: may we intercept reset calls? */	/*	if(m_ptr->REQUEST == DSPIORESET) {		device_available = FALSE;	}	*/	if (m_ptr->REQUEST & _IOC_IN) { /* if there is data for us, copy it */		len = io_ctl_length(m_ptr->REQUEST);		if(sys_safecopyfrom(m_ptr->IO_ENDPT, 					(vir_bytes)m_ptr->ADDRESS, 0,					(vir_bytes)io_ctl_buf, len, D) != OK) {			printf("%s:%d: safecopyfrom failed\n", __FILE__, __LINE__);		}	}	/* all ioctl's are passed to the device specific part of the driver */	status = drv_io_ctl(m_ptr->REQUEST, (void *)io_ctl_buf, &len, chan); 	/* _IOC_OUT bit -> user expects data */	if (status == OK && m_ptr->REQUEST & _IOC_OUT) { 		/* copy result back to user */		if(sys_safecopyto(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, 0, 					(vir_bytes)io_ctl_buf, len, D) != OK) {			printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__);		}	}	return status;}PRIVATE void msg_write(message *m_ptr) {	int s, chan; sub_dev_t *sub_dev_ptr;	special_file_t* special_file_ptr;	dprint("%s: msg_write() device %d\n", drv.DriverName, m_ptr->DEVICE);	special_file_ptr = get_special_file(m_ptr->DEVICE); 	chan = special_file_ptr->write_chan;	if (chan == NO_CHANNEL) {		error("%s: No write channel specified!\n", drv.DriverName);		reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);		return;	}	/* get pointer to sub device data */	sub_dev_ptr = &sub_dev[chan];	if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first write */		if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){			error("%s; Failed to get fragment size!\n", drv.DriverName, 0);			return;			}	}	if(m_ptr->COUNT != sub_dev_ptr->FragSize) {		error("Fragment size does not match user's buffer length\n");		reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);				return;	}	/* if we are busy with something else than writing, return EBUSY */	if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE_S) {		error("Already busy with something else then writing\n");		reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);		return;	}	/* unblock the FileSystem, but keep user process blocked until REVIVE*/	reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND);	sub_dev_ptr->RevivePending = TRUE;	sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;	sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;	sub_dev_ptr->NotifyProcNr = m_ptr->m_source;	data_from_user(sub_dev_ptr);	if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */		dprint("starting audio device\n");		get_started(sub_dev_ptr);    		sub_dev_ptr->DmaMode = DEV_WRITE_S; /* Dma mode is writing */	} }PRIVATE void msg_read(message *m_ptr) {	int s, chan; sub_dev_t *sub_dev_ptr;	special_file_t* special_file_ptr;	dprint("%s: msg_read() device %d\n", drv.DriverName, m_ptr->DEVICE);	special_file_ptr = get_special_file(m_ptr->DEVICE); 

⌨️ 快捷键说明

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