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

📄 audio.c

📁 自己根据lkd和情境分析
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $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 + -