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

📄 audio.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: audio.c,v 1.56 2000/10/19 00:50:02 davem 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/malloc.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/soundcard.h>#include <linux/version.h>#include <linux/devfs_fs_kernel.h>#include <asm/delay.h>#include <asm/pgtable.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; /* This crap to be pulled off into a local include file */#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100#define COPY_IN(arg, get) verify_area(VERIFY_READ, (void *)arg, sizeof(long)); memcpy_fromfs(&get, (long *)arg, sizeof(get));#define COPY_OUT(arg, ret) verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); memcpy_tofs((long *)arg, &ret, sizeof(ret));#define copy_to_user memcpy_tofs#define copy_from_user memcpy_fromfs#define signal_pending(x) (((x)->signal) & ~((x)->blocked))#else#include <asm/uaccess.h>#include <linux/poll.h>#define COPY_IN(arg, get) get_user(get, (int *)arg)#define COPY_OUT(arg, ret) put_user(ret, (int *)arg)#define sparcaudio_select sparcaudio_poll#endifvoid 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 */#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100static int sparcaudio_select(struct inode * inode, struct file * file,			    int sel_type, select_table * wait){        struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>                                                 SPARCAUDIO_DEVICE_SHIFT)];          switch (sel_type) {        case SEL_IN:                if (((!file->f_flags & O_NONBLOCK) && drv->input_count) ||                    (drv->input_size > drv->buffer_size)) {                        dprintk(("read ready: c%d o%d\n",                                 drv->input_count, drv->input_offset));                        return 1;                }                select_wait(&drv->input_read_wait, wait);                break;        case SEL_OUT:                dprintk(("sel out: c%d o%d p%d\n",                         drv->output_count, drv->output_offset, drv->playing_count));                if ((drv->output_count + drv->playing_count) < (drv->num_output_buffers))                        return 1;                select_wait(&drv->output_write_wait, wait);                break;        case SEL_EX:                break;        };        return 0;}#elsestatic 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;}#endif#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100static int sparcaudio_lseek(struct inode * inode, struct file * file,			    off_t offset, int origin)#elsestatic loff_t sparcaudio_lseek(struct file * file, loff_t offset, int origin)#endif{	return -ESPIPE;}#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100static int sparcaudio_read(struct inode * inode, struct file * file,

⌨️ 快捷键说明

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