📄 audio.c
字号:
/* $Id: audio.c,v 1.1.1.1 2004/02/04 12:56:49 laputa Exp $ * drivers/sbus/audio/audio.c * * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) * Copyright 1997,1998,1999 Derrick J. Brashear (shadow@dementia.org) * Copyright 1997 Brent Baccala (baccala@freesoft.org) * * Mixer code adapted from code contributed by and * Copyright 1998 Michael Mraka (michael@fi.muni.cz) * and with fixes from Michael Shuey (shuey@ecn.purdue.edu) * The mixer code cheats; Sparc hardware doesn't generally allow independent * line control, and this fakes it badly. * * SNDCTL_DSP_SETFMT based on code contributed by * Ion Badulescu (ionut@moisil.cs.columbia.edu) * * This is the audio midlayer that sits between the VFS character * devices and the low-level audio hardware device drivers. */#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/mm.h>#include <linux/tqueue.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/soundcard.h>#include <linux/devfs_fs_kernel.h>#include <linux/delay.h>#include <linux/poll.h>#include <asm/pgtable.h>#include <asm/uaccess.h>#include <asm/audioio.h>#undef __AUDIO_DEBUG#define __AUDIO_ERROR#undef __AUDIO_TRACE#undef __AUDIO_OSSDEBUG#ifdef __AUDIO_DEBUG#define dprintk(x) printk x#else#define dprintk(x)#endif#ifdef __AUDIO_OSSDEBUG#define oprintk(x) printk x#else#define oprintk(x)#endif#ifdef __AUDIO_ERROR#define eprintk(x) printk x#else#define eprintk(x)#endif#ifdef __AUDIO_TRACE#define tprintk(x) printk x#else#define tprintk(x)#endifstatic short lis_get_elist_ent( strevent_t *list, pid_t pid );static int lis_add_to_elist( strevent_t **list, pid_t pid, short events );static int lis_del_from_elist( strevent_t **list, pid_t pid, short events );static void lis_free_elist( strevent_t **list);static void kill_procs( struct strevent *elist, int sig, short e);static struct sparcaudio_driver *drivers[SPARCAUDIO_MAX_DEVICES];static devfs_handle_t devfs_handle; void sparcaudio_output_done(struct sparcaudio_driver * drv, int status){ /* If !status, just restart current output. * If status & 1, a buffer is finished; make it available again. * If status & 2, a buffer was claimed for DMA and is still in use. * * The playing_count for non-DMA hardware should never be non-zero. * Value of status for non-DMA hardware should always be 1. */ if (status & 1) { if (drv->playing_count) { drv->playing_count--; } else { drv->output_count--; drv->output_size -= drv->output_sizes[drv->output_front]; if (drv->output_notify[drv->output_front] == 1) { drv->output_eof++; drv->output_notify[drv->output_front] = 0; kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); } drv->output_front = (drv->output_front + 1) % drv->num_output_buffers; } } if (status & 2) { drv->output_count--; drv->playing_count++; drv->output_size -= drv->output_sizes[drv->output_front]; if (drv->output_notify[drv->output_front] == 1) { drv->output_eof++; drv->output_notify[drv->output_front] = 0; kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); } drv->output_front = (drv->output_front + 1) % drv->num_output_buffers; } /* If we've played everything go inactive. */ if ((drv->output_count < 1) && (drv->playing_count < 1)) drv->output_active = 0; /* If we got back a buffer, see if anyone wants to write to it */ if ((status & 1) || ((drv->output_count + drv->playing_count) < drv->num_output_buffers)) { wake_up_interruptible(&drv->output_write_wait); } /* If the output queue is empty, shut down the driver. */ if ((drv->output_count < 1) && (drv->playing_count < 1)) { kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); /* Stop the lowlevel driver from outputing. */ /* drv->ops->stop_output(drv); Should not be necessary -- DJB 5/25/98 */ drv->output_active = 0; /* Wake up any waiting writers or syncers and return. */ wake_up_interruptible(&drv->output_write_wait); wake_up_interruptible(&drv->output_drain_wait); return; } /* Start next block of output if we have it */ if (drv->output_count > 0) { drv->ops->start_output(drv, drv->output_buffers[drv->output_front], drv->output_sizes[drv->output_front]); drv->output_active = 1; } else { drv->output_active = 0; }}void sparcaudio_input_done(struct sparcaudio_driver * drv, int status){ /* Deal with the weird case here */ if (drv->duplex == 2) { if (drv->input_count < drv->num_input_buffers) drv->input_count++; drv->ops->start_input(drv, drv->input_buffers[drv->input_front], drv->input_buffer_size); wake_up_interruptible(&drv->input_read_wait); return; } /* If status % 2, they filled a buffer for us. * If status & 2, they took a buffer from us. */ if ((status % 2) == 1) { drv->input_count++; drv->recording_count--; drv->input_size+=drv->input_buffer_size; } if (status > 1) { drv->recording_count++; drv->input_front = (drv->input_front + 1) % drv->num_input_buffers; } dprintk(("f%d r%d c%d u%d\n", drv->input_front, drv->input_rear, drv->input_count, drv->recording_count)); /* If the input queue is full, shutdown the driver. */ if ((drv->input_count + drv->recording_count) == drv->num_input_buffers) { kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); /* Stop the lowlevel driver from inputing. */ drv->ops->stop_input(drv); drv->input_active = 0; } else { /* Otherwise, give the driver the next buffer. */ drv->ops->start_input(drv, drv->input_buffers[drv->input_front], drv->input_buffer_size); } /* Wake up any tasks that are waiting. */ wake_up_interruptible(&drv->input_read_wait);}/* * VFS layer interface */static unsigned int sparcaudio_poll(struct file *file, poll_table * wait){ unsigned int mask = 0; struct inode *inode = file->f_dentry->d_inode; struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> SPARCAUDIO_DEVICE_SHIFT)]; poll_wait(file, &drv->input_read_wait, wait); poll_wait(file, &drv->output_write_wait, wait); if (((!file->f_flags & O_NONBLOCK) && drv->input_count) || (drv->input_size > drv->buffer_size)) { mask |= POLLIN | POLLRDNORM; } if ((drv->output_count + drv->playing_count) < (drv->num_output_buffers)) { mask |= POLLOUT | POLLWRNORM; } return mask;}static ssize_t sparcaudio_read(struct file * file, char *buf, size_t count, loff_t *ppos){ struct inode *inode = file->f_dentry->d_inode; struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> SPARCAUDIO_DEVICE_SHIFT)]; int bytes_to_copy, bytes_read = 0, err; if (! (file->f_mode & FMODE_READ)) return -EINVAL; if ((file->f_flags & O_NONBLOCK) && (drv->input_size < count)) return -EAGAIN; while (count > 0) { if (drv->input_count == 0) { /* This *should* never happen. */ if (file->f_flags & O_NONBLOCK) { printk("Warning: audio input leak!\n"); return -EAGAIN; } interruptible_sleep_on(&drv->input_read_wait); if (signal_pending(current)) return -EINTR; } bytes_to_copy = drv->input_buffer_size - drv->input_offset; if (bytes_to_copy > count) bytes_to_copy = count; err = verify_area(VERIFY_WRITE, buf, bytes_to_copy); if (err) return err; copy_to_user(buf, drv->input_buffers[drv->input_rear]+drv->input_offset, bytes_to_copy); drv->input_offset += bytes_to_copy; drv->input_size -= bytes_to_copy; buf += bytes_to_copy; count -= bytes_to_copy; bytes_read += bytes_to_copy; if (drv->input_offset >= drv->input_buffer_size) { drv->input_rear = (drv->input_rear + 1) % drv->num_input_buffers; drv->input_count--; drv->input_offset = 0; } /* If we're in "loop audio" mode, try waking up the other side * in case they're waiting for us to eat a block. */ if (drv->duplex == 2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -