📄 soundcard.c
字号:
/* * linux/kernel/chr_drv/sound/soundcard.c * * Soundcard driver for Linux *//* * Copyright (C) by Hannu Savolainen 1993-1996 * * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */#include <linux/config.h>#include "sound_config.h"#include <linux/major.h>int *sound_global_osp = NULL;static int chrdev_registered = 0;static int sound_major = SOUND_MAJOR;static int is_unloading = 0;/* * Table for permanently allocated memory (used when unloading the module) */caddr_t sound_mem_blocks[1024];int sound_nblocks = 0;static int soundcard_configured = 0;static struct fileinfo files[SND_NDEVS];static char dma_alloc_map[MAX_DMA_CHANNELS] ={0};#define DMA_MAP_UNAVAIL 0#define DMA_MAP_FREE 1#define DMA_MAP_BUSY 2intsnd_ioctl_return (int *addr, int value){ if (value < 0) return value; put_user (value, addr); return 0;}static intsound_read (inode_handle * inode, file_handle * file, char *buf, int count){ int dev; dev = MINOR (inode_get_rdev (inode)); files[dev].flags = file_get_flags (file); return sound_read_sw (dev, &files[dev], buf, count);}static intsound_write (inode_handle * inode, file_handle * file, const char *buf, int count){ int dev; dev = MINOR (inode_get_rdev (inode)); files[dev].flags = file_get_flags (file); return sound_write_sw (dev, &files[dev], buf, count);}static intsound_lseek (inode_handle * inode, file_handle * file, off_t offset, int orig){ return -(EPERM);}static intsound_open (inode_handle * inode, file_handle * file){ int dev, retval; struct fileinfo tmp_file; if (is_unloading) { printk ("Sound: Driver partially removed. Can't open device\n"); return -(EBUSY); } dev = MINOR (inode_get_rdev (inode)); if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) { printk ("Sound Card Error: The soundcard system has not been configured\n"); return -(ENXIO); } tmp_file.mode = 0; tmp_file.flags = file_get_flags (file); if ((tmp_file.flags & O_ACCMODE) == O_RDWR) tmp_file.mode = OPEN_READWRITE; if ((tmp_file.flags & O_ACCMODE) == O_RDONLY) tmp_file.mode = OPEN_READ; if ((tmp_file.flags & O_ACCMODE) == O_WRONLY) tmp_file.mode = OPEN_WRITE; if ((retval = sound_open_sw (dev, &tmp_file)) < 0) return retval;#ifdef MODULE MOD_INC_USE_COUNT;#endif memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file)); return retval;}static voidsound_release (inode_handle * inode, file_handle * file){ int dev; dev = MINOR (inode_get_rdev (inode)); files[dev].flags = file_get_flags (file); sound_release_sw (dev, &files[dev]);#ifdef MODULE MOD_DEC_USE_COUNT;#endif}static intsound_ioctl (inode_handle * inode, file_handle * file, unsigned int cmd, unsigned long arg){ int dev, err; dev = MINOR (inode_get_rdev (inode)); files[dev].flags = file_get_flags (file); if (_IOC_DIR (cmd) != _IOC_NONE) { /* * Have to validate the address given by the process. */ int len; len = _IOC_SIZE (cmd); if (_IOC_DIR (cmd) & _IOC_WRITE) { if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0) return err; } if (_IOC_DIR (cmd) & _IOC_READ) { if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0) return err; } } err = sound_ioctl_sw (dev, &files[dev], cmd, (caddr_t) arg); return err;}static intsound_select (inode_handle * inode, file_handle * file, int sel_type, select_table_handle * wait){ int dev; dev = MINOR (inode_get_rdev (inode)); files[dev].flags = file_get_flags (file); DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type)); switch (dev & 0x0f) {#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_select (dev, &files[dev], sel_type, wait); break;#endif#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_select (dev, &files[dev], sel_type, wait); break;#endif#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return audio_select (dev, &files[dev], sel_type, wait); break;#endif default: return 0; } return 0;}static intsound_mmap (inode_handle * inode, file_handle * file, vm_area_handle * vma){ int dev, dev_class; unsigned long size; struct dma_buffparms *dmap = NULL; dev = MINOR (inode_get_rdev (inode)); files[dev].flags = file_get_flags (file); dev_class = dev & 0x0f; dev >>= 4; if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) { printk ("Sound: mmap() not supported for other than audio devices\n"); return -EINVAL; } if ((vma_get_flags (vma) & (VM_READ | VM_WRITE)) == (VM_READ | VM_WRITE)) { printk ("Sound: Cannot do read/write mmap()\n"); return -EINVAL; } if (vma_get_flags (vma) & VM_READ) { dmap = audio_devs[dev]->dmap_in; } else if (vma_get_flags (vma) & VM_WRITE) { dmap = audio_devs[dev]->dmap_out; } else { printk ("Sound: Undefined mmap() access\n"); return -EINVAL; } if (dmap == NULL) { printk ("Sound: mmap() error. dmap == NULL\n"); return -EIO; } if (dmap->raw_buf == NULL) { printk ("Sound: mmap() called when raw_buf == NULL\n"); return -EIO; } if (dmap->mapping_flags) { printk ("Sound: mmap() called twice for the same DMA buffer\n"); return -EIO; } if (vma_get_offset (vma) != 0) { printk ("Sound: mmap() offset must be 0.\n"); return -EINVAL; } size = vma_get_end (vma) - vma_get_start (vma); if (size != dmap->bytes_in_use) { printk ("Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use); } if (remap_page_range (vma_get_start (vma), (unsigned long)dmap->raw_buf, vma_get_end (vma) - vma_get_start (vma), vma_get_page_prot (vma))) return -EAGAIN; vma_set_inode (vma, inode); inode_inc_count (inode); dmap->mapping_flags |= DMA_MAP_MAPPED; memset (dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use); return 0;}static struct file_operation_handle sound_fops ={ sound_lseek, sound_read, sound_write, NULL, /* sound_readdir */ sound_select, sound_ioctl, sound_mmap, sound_open, sound_release};voidsoundcard_init (void){#ifndef MODULE module_register_chrdev (sound_major, "sound", &sound_fops); chrdev_registered = 1;#endif soundcard_configured = 1; sndtable_init (); /* Initialize call tables and detect cards */#ifdef CONFIG_LOWLEVEL_SOUND { extern void sound_init_lowlevel_drivers (void); sound_init_lowlevel_drivers (); }#endif if (sndtable_get_cardcount () == 0) return; /* No cards detected */#ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { DMAbuf_init (); audio_init (); }#endif#ifdef CONFIG_MIDI if (num_midis) MIDIbuf_init ();#endif#ifdef CONFIG_SEQUENCER if (num_midis + num_synths) sequencer_init ();#endif}static unsigned int irqs = 0;#ifdef MODULEstatic voidfree_all_irqs (void){ int i; for (i = 0; i < 31; i++) if (irqs & (1ul << i)) { printk ("Sound warning: IRQ%d was left allocated - fixed.\n", i); snd_release_irq (i); } irqs = 0;}char kernel_version[] = UTS_RELEASE;#endifstatic int debugmem = 0; /* switched off by default */static int sound[20] ={0};intinit_module (void){ int err; int ints[21];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -