📄 audio.c
字号:
/* * sound/audio.c * * Device file manager for /dev/audio * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#include "sound_config.h"#ifdef CONFIGURE_SOUNDCARD#ifndef EXCLUDE_AUDIO#include "ulaw.h"#define ON 1#define OFF 0static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a * incomplete output block */static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];static int audio_mode[MAX_DSP_DEV];#define AM_NONE 0#define AM_WRITE 1#define AM_READ 2static char *wr_dma_buf[MAX_DSP_DEV];intaudio_open (int dev, struct fileinfo *file){ int ret; int bits; int dev_type = dev & 0x0f; int mode = file->mode & O_ACCMODE; dev = dev >> 4; if (dev_type == SND_DEV_DSP16) bits = 16; else bits = 8; if ((ret = DMAbuf_open (dev, mode)) < 0) return ret; if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits) { audio_release (dev, file); return RET_ERROR (ENXIO); } wr_buff_no[dev] = -1; audio_mode[dev] = AM_NONE; return ret;}voidaudio_release (int dev, struct fileinfo *file){ int mode; dev = dev >> 4; mode = file->mode & O_ACCMODE; if (wr_buff_no[dev] >= 0) { DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); wr_buff_no[dev] = -1; } DMAbuf_release (dev, mode);}#ifdef NO_INLINE_ASMstatic voidtranslate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n){ unsigned long i; for (i = 0; i < n; ++i) buff[i] = table[buff[i]];}#elseextern inline voidtranslate_bytes (const void *table, void *buff, unsigned long n){ __asm__ ("cld\n" "1:\tlodsb\n\t" "xlatb\n\t" "stosb\n\t" "loop 1b\n\t": :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff) :"bx", "cx", "di", "si", "ax");}#endifintaudio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count){ int c, p, l; int err; int dev_type = dev & 0x0f; dev = dev >> 4; p = 0; c = count; if (audio_mode[dev] == AM_READ) /* Direction changed */ { wr_buff_no[dev] = -1; } audio_mode[dev] = AM_WRITE; if (!count) /* Flush output */ { if (wr_buff_no[dev] >= 0) { DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); wr_buff_no[dev] = -1; } return 0; } while (c) { /* Perform output blocking */ if (wr_buff_no[dev] < 0) /* There is no incomplete buffers */ { if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0) return wr_buff_no[dev]; wr_buff_ptr[dev] = 0; } l = c; if (l > (wr_buff_size[dev] - wr_buff_ptr[dev])) l = (wr_buff_size[dev] - wr_buff_ptr[dev]); if (!dsp_devs[dev]->copy_from_user) { /* No device specific copy routine */ COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l); } else dsp_devs[dev]->copy_from_user (dev, wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l); /* Insert local processing here */ if (dev_type == SND_DEV_AUDIO) {#ifdef linux /* This just allows interrupts while the conversion is running */ __asm__ ("sti");#endif translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l); } c -= l; p += l; wr_buff_ptr[dev] += l; if (wr_buff_ptr[dev] >= wr_buff_size[dev]) { if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0) return err; wr_buff_no[dev] = -1; } } return count;}intaudio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count){ int c, p, l; char *dmabuf; int buff_no; int dev_type = dev & 0x0f; dev = dev >> 4; p = 0; c = count; if (audio_mode[dev] == AM_WRITE) { if (wr_buff_no[dev] >= 0) { DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); wr_buff_no[dev] = -1; } } audio_mode[dev] = AM_READ; while (c) { if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0) return buff_no; if (l > c) l = c; /* Insert any local processing here. */ if (dev_type == SND_DEV_AUDIO) {#ifdef linux /* This just allows interrupts while the conversion is running */ __asm__ ("sti");#endif translate_bytes (dsp_ulaw, dmabuf, l); } COPY_TO_USER (buf, p, dmabuf, l); DMAbuf_rmchars (dev, buff_no, l); p += l; c -= l; } return count - c;}intaudio_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg){ int dev_type = dev & 0x0f; dev = dev >> 4; switch (cmd) { case SNDCTL_DSP_SYNC: if (wr_buff_no[dev] >= 0) { DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); wr_buff_no[dev] = -1; } return DMAbuf_ioctl (dev, cmd, arg, 0); break; case SNDCTL_DSP_POST: if (wr_buff_no[dev] >= 0) { DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); wr_buff_no[dev] = -1; } return 0; break; case SNDCTL_DSP_RESET: wr_buff_no[dev] = -1; return DMAbuf_ioctl (dev, cmd, arg, 0); break; default: if (dev_type == SND_DEV_AUDIO) return RET_ERROR (EIO); return DMAbuf_ioctl (dev, cmd, arg, 0); }}longaudio_init (long mem_start){ return mem_start;}#else/* Stub versions */intaudio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count){ return RET_ERROR (EIO);}intaudio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count){ return RET_ERROR (EIO);}intaudio_open (int dev, struct fileinfo *file) { return RET_ERROR (ENXIO); }voidaudio_release (int dev, struct fileinfo *file) { };intaudio_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg){ return RET_ERROR (EIO);}intaudio_lseek (int dev, struct fileinfo *file, off_t offset, int orig){ return RET_ERROR (EIO);}longaudio_init (long mem_start){ return mem_start;}#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -