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

📄 dmasound_core.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 3 页
字号:
static ssize_t sound_copy_translate(TRANS *trans, const u_char *userPtr,				    size_t userCount, u_char frame[],				    ssize_t *frameUsed, ssize_t frameLeft){	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);	switch (dmasound.soft.format) {	    case AFMT_MU_LAW:		ct_func = trans->ct_ulaw;		break;	    case AFMT_A_LAW:		ct_func = trans->ct_alaw;		break;	    case AFMT_S8:		ct_func = trans->ct_s8;		break;	    case AFMT_U8:		ct_func = trans->ct_u8;		break;	    case AFMT_S16_BE:		ct_func = trans->ct_s16be;		break;	    case AFMT_U16_BE:		ct_func = trans->ct_u16be;		break;	    case AFMT_S16_LE:		ct_func = trans->ct_s16le;		break;	    case AFMT_U16_LE:		ct_func = trans->ct_u16le;		break;	    default:		return 0;	}	return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);}    /*     *  /dev/mixer abstraction     */static struct {    int busy;    int modify_counter;} mixer;static int mixer_open(struct inode *inode, struct file *file){	dmasound.mach.open();	mixer.busy = 1;	return 0;}static int mixer_release(struct inode *inode, struct file *file){	lock_kernel();	mixer.busy = 0;	dmasound.mach.release();	unlock_kernel();	return 0;}static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,		       u_long arg){	if (_SIOC_DIR(cmd) & _SIOC_WRITE)	    mixer.modify_counter++;	switch (cmd) {	    case OSS_GETVERSION:		return IOCTL_OUT(arg, SOUND_VERSION);	    case SOUND_MIXER_INFO:		{		    mixer_info info;		    strncpy(info.id, dmasound.mach.name2, sizeof(info.id));		    strncpy(info.name, dmasound.mach.name2, sizeof(info.name));		    info.name[sizeof(info.name)-1] = 0;		    info.modify_counter = mixer.modify_counter;		    if (copy_to_user((int *)arg, &info, sizeof(info)))			    return -EFAULT;		    return 0;		}	}	if (dmasound.mach.mixer_ioctl)	    return dmasound.mach.mixer_ioctl(cmd, arg);	return -EINVAL;}static struct file_operations mixer_fops ={	owner:		THIS_MODULE,	llseek:		no_llseek,	ioctl:		mixer_ioctl,	open:		mixer_open,	release:	mixer_release,};static void __init mixer_init(void){#ifndef MODULE	int mixer_unit;#endif	mixer_unit = register_sound_mixer(&mixer_fops, -1);	if (mixer_unit < 0)		return;	mixer.busy = 0;	dmasound.treble = 0;	dmasound.bass = 0;	if (dmasound.mach.mixer_init)	    dmasound.mach.mixer_init();}    /*     *  Sound queue stuff, the heart of the driver     */struct sound_queue dmasound_write_sq;#ifdef HAS_RECORDstruct sound_queue dmasound_read_sq;#endifstatic int sq_allocate_buffers(struct sound_queue *sq, int num, int size){	int i;	if (sq->buffers)		return 0;	sq->numBufs = num;	sq->bufSize = size;	sq->buffers = kmalloc (num * sizeof(char *), GFP_KERNEL);	if (!sq->buffers)		return -ENOMEM;	for (i = 0; i < num; i++) {		sq->buffers[i] = dmasound.mach.dma_alloc(size, GFP_KERNEL);		if (!sq->buffers[i]) {			while (i--)				dmasound.mach.dma_free(sq->buffers[i], size);			kfree(sq->buffers);			sq->buffers = 0;			return -ENOMEM;		}	}	return 0;}static void sq_release_buffers(struct sound_queue *sq){	int i;	if (sq->buffers) {		if (sq != &write_sq && dmasound.mach.abort_read)			dmasound.mach.abort_read();		for (i = 0; i < sq->numBufs; i++)			dmasound.mach.dma_free(sq->buffers[i], sq->bufSize);		kfree(sq->buffers);		sq->buffers = NULL;	}}static void sq_setup(struct sound_queue *sq, int max_count, int max_active,		     int block_size){	void (*setup_func)(void);	sq->max_count = max_count;	sq->max_active = max_active;	sq->block_size = block_size;	sq->front = sq->count = sq->rear_size = 0;	sq->syncing = 0;	sq->active = 0;	if (sq == &write_sq) {	    sq->rear = -1;	    setup_func = dmasound.mach.write_sq_setup;	} else {	    sq->rear = 0;	    setup_func = dmasound.mach.read_sq_setup;	}	if (setup_func)	    setup_func();}static inline void sq_play(void){	dmasound.mach.play();}static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,			loff_t *ppos){	ssize_t uWritten = 0;	u_char *dest;	ssize_t uUsed, bUsed, bLeft;	/* ++TeSche: Is something like this necessary?	 * Hey, that's an honest question! Or does any other part of the	 * filesystem already checks this situation? I really don't know.	 */	if (uLeft == 0)		return 0;	/* The interrupt doesn't start to play the last, incomplete frame.	 * Thus we can append to it without disabling the interrupts! (Note	 * also that write_sq.rear isn't affected by the interrupt.)	 */	if (write_sq.count > 0 &&	    (bLeft = write_sq.block_size-write_sq.rear_size) > 0) {		dest = write_sq.buffers[write_sq.rear];		bUsed = write_sq.rear_size;		uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,					     dest, &bUsed, bLeft);		if (uUsed <= 0)			return uUsed;		src += uUsed;		uWritten += uUsed;		uLeft -= uUsed;		write_sq.rear_size = bUsed;	}	do {		while (write_sq.count == write_sq.max_active) {			sq_play();			if (write_sq.open_mode & O_NONBLOCK)				return uWritten > 0 ? uWritten : -EAGAIN;			SLEEP(write_sq.action_queue);			if (signal_pending(current))				return uWritten > 0 ? uWritten : -EINTR;		}		/* Here, we can avoid disabling the interrupt by first		 * copying and translating the data, and then updating		 * the write_sq variables. Until this is done, the interrupt		 * won't see the new frame and we can work on it		 * undisturbed.		 */		dest = write_sq.buffers[(write_sq.rear+1) % write_sq.max_count];		bUsed = 0;		bLeft = write_sq.block_size;		uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,					     dest, &bUsed, bLeft);		if (uUsed <= 0)			break;		src += uUsed;		uWritten += uUsed;		uLeft -= uUsed;		if (bUsed) {			write_sq.rear = (write_sq.rear+1) % write_sq.max_count;			write_sq.rear_size = bUsed;			write_sq.count++;		}	} while (bUsed);   /* uUsed may have been 0 */	sq_play();	return uUsed < 0? uUsed: uWritten;}#ifdef HAS_RECORD    /*     *  Here is how the values are used for reading.     *  The value 'active' simply indicates the DMA is running.  This is done     *  so the driver semantics are DMA starts when the first read is posted.     *  The value 'front' indicates the buffer we should next send to the user.     *  The value 'rear' indicates the buffer the DMA is currently filling.     *  When 'front' == 'rear' the buffer "ring" is empty (we always have an     *  empty available).  The 'rear_size' is used to track partial offsets     *  into the current buffer.  Right now, I just keep the DMA running.  If     *  the reader can't keep up, the interrupt tosses the oldest buffer.  We     *  could also shut down the DMA in this case.     */static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,		       loff_t *ppos){	ssize_t	uRead, bLeft, bUsed, uUsed;	if (uLeft == 0)		return 0;	if (!read_sq.active && dmasound.mach.record)		dmasound.mach.record();	/* Kick off the record process. */	uRead = 0;	/* Move what the user requests, depending upon other options.	*/	while (uLeft > 0) {		/* When front == rear, the DMA is not done yet.		*/		while (read_sq.front == read_sq.rear) {			if (read_sq.open_mode & O_NONBLOCK) {			       return uRead > 0 ? uRead : -EAGAIN;			}			SLEEP(read_sq.action_queue);			if (signal_pending(current))				return uRead > 0 ? uRead : -EINTR;		}		/* The amount we move is either what is left in the		 * current buffer or what the user wants.		 */		bLeft = read_sq.block_size - read_sq.rear_size;		bUsed = read_sq.rear_size;		uUsed = sound_copy_translate(dmasound.trans_read, dst, uLeft,					     read_sq.buffers[read_sq.front],					     &bUsed, bLeft);		if (uUsed <= 0)			return uUsed;		dst += uUsed;		uRead += uUsed;		uLeft -= uUsed;		read_sq.rear_size += bUsed;		if (read_sq.rear_size >= read_sq.block_size) {			read_sq.rear_size = 0;			read_sq.front++;			if (read_sq.front >= read_sq.max_active)				read_sq.front = 0;		}	}	return uRead;}#endif /* HAS_RECORD */static inline void sq_init_waitqueue(struct sound_queue *sq){	init_waitqueue_head(&sq->action_queue);	init_waitqueue_head(&sq->open_queue);	init_waitqueue_head(&sq->sync_queue);	sq->busy = 0;}static inline void sq_wake_up(struct sound_queue *sq, struct file *file,			      mode_t mode){	if (file->f_mode & mode) {		sq->busy = 0;		WAKE_UP(sq->open_queue);	}}static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,		    int numbufs, int bufsize){	int rc = 0;	if (file->f_mode & mode) {		if (sq->busy) {			rc = -EBUSY;			if (file->f_flags & O_NONBLOCK)				return rc;			rc = -EINTR;			while (sq->busy) {				SLEEP(sq->open_queue);				if (signal_pending(current))					return rc;			}			rc = 0;		}		sq->busy = 1; /* Let's play spot-the-race-condition */		if (sq_allocate_buffers(sq, numbufs, bufsize)) {			sq_wake_up(sq, file, mode);			return rc;		}		sq_setup(sq, numbufs, numbufs, bufsize);		sq->open_mode = file->f_mode;	}	return rc;}#define write_sq_init_waitqueue()	sq_init_waitqueue(&write_sq)#define write_sq_wake_up(file)		sq_wake_up(&write_sq, file, FMODE_WRITE)#define write_sq_release_buffers()	sq_release_buffers(&write_sq)#define write_sq_open(file)	\	sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize << 10)#ifdef HAS_RECORD#define read_sq_init_waitqueue()	sq_init_waitqueue(&read_sq)#define read_sq_wake_up(file)		sq_wake_up(&read_sq, file, FMODE_READ)#define read_sq_release_buffers()	sq_release_buffers(&read_sq)#define read_sq_open(file)	\	sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize << 10)#else /* !HAS_RECORD */#define read_sq_init_waitqueue()	do {} while (0)#define read_sq_wake_up(file)		do {} while (0)#define read_sq_release_buffers()	do {} while (0)#define read_sq_open(file)		(0)#endif /* !HAS_RECORD */static int sq_open(struct inode *inode, struct file *file){	int rc;	dmasound.mach.open();	if ((rc = write_sq_open(file)) || (rc = read_sq_open(file))) {		dmasound.mach.release();		return rc;	}	if (dmasound.mach.sq_open)	    dmasound.mach.sq_open();	dmasound.minDev = MINOR(inode->i_rdev) & 0x0f;	dmasound.soft = dmasound.dsp;	dmasound.hard = dmasound.dsp;	sound_init();	if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {		sound_set_speed(8000);		sound_set_stereo(0);		sound_set_format(AFMT_MU_LAW);	}#if 0	if (file->f_mode == FMODE_READ && dmasound.mach.record) {		/* Start dma'ing straight away */		dmasound.mach.record();	}#endif	return 0;}static void sq_reset(void){	sound_silence();	write_sq.active = 0;	write_sq.count = 0;	write_sq.front = (write_sq.rear+1) % write_sq.max_count;}static int sq_fsync(struct file *filp, struct dentry *dentry)

⌨️ 快捷键说明

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