?? audio.c
字號:
/* ********************************************************************** * audio.c -- /dev/dsp interface for emu10k1 driver * Copyright 1999, 2000 Creative Labs, Inc. * ********************************************************************** * * Date Author Summary of changes * ---- ------ ------------------ * October 20, 1999 Bertrand Lee base code release * November 2, 1999 Alan Cox cleaned up types/leaks * ********************************************************************** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, * USA. * ********************************************************************** */#define __NO_VERSION__#include <linux/module.h>#include <linux/poll.h>#include <linux/malloc.h>#include <linux/version.h>#include <linux/bitops.h>#include <asm/io.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/wrapper.h>#include "hwaccess.h"#include "cardwo.h"#include "cardwi.h"#include "recmgr.h"#include "irqmgr.h"#include "audio.h"static void calculate_ofrag(struct woinst *);static void calculate_ifrag(struct wiinst *);/* Audio file operations */static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos){ struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; struct wiinst *wiinst = wave_dev->wiinst; ssize_t ret = 0; unsigned long flags; DPD(3, "emu10k1_audio_read(), buffer=%p, count=%d\n", buffer, (u32) count); if (ppos != &file->f_pos) return -ESPIPE; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; spin_lock_irqsave(&wiinst->lock, flags); if (wiinst->mmapped) { spin_unlock_irqrestore(&wiinst->lock, flags); return -ENXIO; } if (wiinst->state == WAVE_STATE_CLOSED) { calculate_ifrag(wiinst); while (emu10k1_wavein_open(wave_dev) < 0) { spin_unlock_irqrestore(&wiinst->lock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(&wave_dev->card->open_wait); if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irqsave(&wiinst->lock, flags); } } spin_unlock_irqrestore(&wiinst->lock, flags); while (count > 0) { u32 bytestocopy; spin_lock_irqsave(&wiinst->lock, flags); if (!(wiinst->state & WAVE_STATE_STARTED) && (wave_dev->enablebits & PCM_ENABLE_INPUT)) emu10k1_wavein_start(wave_dev); emu10k1_wavein_update(wave_dev->card, wiinst); emu10k1_wavein_getxfersize(wiinst, &bytestocopy); spin_unlock_irqrestore(&wiinst->lock, flags); DPD(3, "bytestocopy --> %d\n", bytestocopy); if ((bytestocopy >= wiinst->buffer.fragment_size) || (bytestocopy >= count)) { bytestocopy = min(bytestocopy, count); emu10k1_wavein_xferdata(wiinst, (u8 *) buffer, &bytestocopy); count -= bytestocopy; buffer += bytestocopy; ret += bytestocopy; } if (count > 0) { if ((file->f_flags & O_NONBLOCK) || (!(wave_dev->enablebits & PCM_ENABLE_INPUT))) return (ret ? ret : -EAGAIN); interruptible_sleep_on(&wiinst->wait_queue); if (signal_pending(current)) return (ret ? ret : -ERESTARTSYS); } } DPD(3, "bytes copied -> %d\n", (u32) ret); return ret;}static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos){ struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; struct woinst *woinst = wave_dev->woinst; ssize_t ret; unsigned long flags; DPD(3, "emu10k1_audio_write(), buffer=%p, count=%d\n", buffer, (u32) count); if (ppos != &file->f_pos) return -ESPIPE; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; spin_lock_irqsave(&woinst->lock, flags); if (woinst->mmapped) { spin_unlock_irqrestore(&woinst->lock, flags); return -ENXIO; } if (woinst->state == WAVE_STATE_CLOSED) { calculate_ofrag(woinst); while (emu10k1_waveout_open(wave_dev) < 0) { spin_unlock_irqrestore(&woinst->lock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(&wave_dev->card->open_wait); if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irqsave(&woinst->lock, flags); } } spin_unlock_irqrestore(&woinst->lock, flags); ret = 0; while (count > 0) { u32 bytestocopy; spin_lock_irqsave(&woinst->lock, flags); emu10k1_waveout_update(woinst); emu10k1_waveout_getxfersize(woinst, &bytestocopy); spin_unlock_irqrestore(&woinst->lock, flags); DPD(3, "bytestocopy --> %d\n", bytestocopy); if ((bytestocopy >= woinst->buffer.fragment_size) || (bytestocopy >= count)) { bytestocopy = min(bytestocopy, count); emu10k1_waveout_xferdata(woinst, (u8 *) buffer, &bytestocopy); count -= bytestocopy; buffer += bytestocopy; ret += bytestocopy; spin_lock_irqsave(&woinst->lock, flags); woinst->total_copied += bytestocopy; if (!(woinst->state & WAVE_STATE_STARTED) && (wave_dev->enablebits & PCM_ENABLE_OUTPUT) && (woinst->total_copied >= woinst->buffer.fragment_size)) emu10k1_waveout_start(wave_dev); spin_unlock_irqrestore(&woinst->lock, flags); } if (count > 0) { if ((file->f_flags & O_NONBLOCK) || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT))) return (ret ? ret : -EAGAIN); interruptible_sleep_on(&woinst->wait_queue); if (signal_pending(current)) return (ret ? ret : -ERESTARTSYS); } } DPD(3, "bytes copied -> %d\n", (u32) ret); return ret;}static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; struct woinst *woinst = NULL; struct wiinst *wiinst = NULL; int val = 0; u32 bytestocopy; unsigned long flags; DPF(4, "emu10k1_audio_ioctl()\n"); if (file->f_mode & FMODE_WRITE) woinst = wave_dev->woinst; if (file->f_mode & FMODE_READ) wiinst = wave_dev->wiinst; switch (cmd) { case OSS_GETVERSION: DPF(2, "OSS_GETVERSION:\n"); return put_user(SOUND_VERSION, (int *) arg); case SNDCTL_DSP_RESET: DPF(2, "SNDCTL_DSP_RESET:\n"); wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; if (file->f_mode & FMODE_WRITE) { spin_lock_irqsave(&woinst->lock, flags); if (woinst->state & WAVE_STATE_OPEN) { if (woinst->mmapped) { int i; /* Undo marking the pages as reserved */ for (i = 0; i < woinst->buffer.pages; i++) mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); } emu10k1_waveout_close(wave_dev); } woinst->mmapped = 0; woinst->total_copied = 0; woinst->total_played = 0; woinst->blocks = 0; spin_unlock_irqrestore(&woinst->lock, flags); } if (file->f_mode & FMODE_READ) { spin_lock_irqsave(&wiinst->lock, flags); if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_close(wave_dev); wiinst->mmapped = 0; wiinst->total_recorded = 0; wiinst->blocks = 0; spin_unlock_irqrestore(&wiinst->lock, flags); } break; case SNDCTL_DSP_SYNC: DPF(2, "SNDCTL_DSP_SYNC:\n"); if (file->f_mode & FMODE_WRITE) { spin_lock_irqsave(&woinst->lock, flags); if (woinst->state & WAVE_STATE_OPEN) { if (woinst->state & WAVE_STATE_STARTED) while ((woinst->total_played < woinst->total_copied) && !signal_pending(current)) { spin_unlock_irqrestore(&woinst->lock, flags); interruptible_sleep_on(&woinst->wait_queue); spin_lock_irqsave(&woinst->lock, flags); } if (woinst->mmapped) { int i; /* Undo marking the pages as reserved */ for (i = 0; i < woinst->buffer.pages; i++) mem_map_reserve(virt_to_page(woinst->buffer.addr[i])); } emu10k1_waveout_close(wave_dev); } woinst->mmapped = 0; woinst->total_copied = 0; woinst->total_played = 0; woinst->blocks = 0; spin_unlock_irqrestore(&woinst->lock, flags); } if (file->f_mode & FMODE_READ) { spin_lock_irqsave(&wiinst->lock, flags); if (wiinst->state & WAVE_STATE_OPEN) emu10k1_wavein_close(wave_dev); wiinst->mmapped = 0; wiinst->total_recorded = 0; wiinst->blocks = 0; spin_unlock_irqrestore(&wiinst->lock, flags); } break; case SNDCTL_DSP_SETDUPLEX: DPF(2, "SNDCTL_DSP_SETDUPLEX:\n"); break; case SNDCTL_DSP_GETCAPS: DPF(2, "SNDCTL_DSP_GETCAPS:\n"); return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *) arg); case SNDCTL_DSP_SPEED: DPF(2, "SNDCTL_DSP_SPEED:\n"); if (get_user(val, (int *) arg)) return -EFAULT; DPD(2, "val is %d\n", val); if (val > 0) { if (file->f_mode & FMODE_READ) { struct wave_format format; spin_lock_irqsave(&wiinst->lock, flags); format = wiinst->format; format.samplingrate = val; if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; val = wiinst->format.samplingrate; spin_unlock_irqrestore(&wiinst->lock, flags); DPD(2, "set recording sampling rate -> %d\n", val); } if (file->f_mode & FMODE_WRITE) { struct wave_format format; spin_lock_irqsave(&woinst->lock, flags); format = woinst->format; format.samplingrate = val; if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; val = woinst->format.samplingrate; spin_unlock_irqrestore(&woinst->lock, flags); DPD(2, "set playback sampling rate -> %d\n", val); } return put_user(val, (int *) arg); } else { if (file->f_mode & FMODE_READ) val = wiinst->format.samplingrate; else if (file->f_mode & FMODE_WRITE) val = woinst->format.samplingrate; return put_user(val, (int *) arg); } break; case SNDCTL_DSP_STEREO: DPF(2, "SNDCTL_DSP_STEREO:\n"); if (get_user(val, (int *) arg)) return -EFAULT; DPD(2, " val is %d\n", val); if (file->f_mode & FMODE_READ) { struct wave_format format; spin_lock_irqsave(&wiinst->lock, flags); format = wiinst->format; format.channels = val ? 2 : 1; if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; val = wiinst->format.channels - 1; spin_unlock_irqrestore(&wiinst->lock, flags); DPD(2, "set recording stereo -> %d\n", val); } if (file->f_mode & FMODE_WRITE) { struct wave_format format; spin_lock_irqsave(&woinst->lock, flags); format = woinst->format; format.channels = val ? 2 : 1; if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; val = woinst->format.channels - 1; spin_unlock_irqrestore(&woinst->lock, flags); DPD(2, "set playback stereo -> %d\n", val); } return put_user(val, (int *) arg); break; case SNDCTL_DSP_CHANNELS: DPF(2, "SNDCTL_DSP_CHANNELS:\n"); if (get_user(val, (int *) arg)) return -EFAULT; DPD(2, " val is %d\n", val); if (val > 0) { if (file->f_mode & FMODE_READ) { struct wave_format format; spin_lock_irqsave(&wiinst->lock, flags); format = wiinst->format; format.channels = val; if (emu10k1_wavein_setformat(wave_dev, &format) < 0) return -EINVAL; val = wiinst->format.channels; spin_unlock_irqrestore(&wiinst->lock, flags); DPD(2, "set recording number of channels -> %d\n", val); } if (file->f_mode & FMODE_WRITE) { struct wave_format format; spin_lock_irqsave(&woinst->lock, flags); format = woinst->format; format.channels = val; if (emu10k1_waveout_setformat(wave_dev, &format) < 0) return -EINVAL; val = woinst->format.channels; spin_unlock_irqrestore(&woinst->lock, flags); DPD(2, "set playback number of channels -> %d\n", val);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -