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

📄 soundcard.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/drivers/sound/soundcard.c * * Sound card driver for Linux *//* * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free 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. *//* * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed) *                   integrated sound_switch.c * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, *                   which should disappear in the near future) * * Rob Riggs		Added persistent DMA buffers support (1998/10/17) */#include <linux/config.h>#include "sound_config.h"#include <linux/types.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/fcntl.h>#include <linux/ctype.h>#include <linux/stddef.h>#include <linux/kmod.h>#ifdef __KERNEL__#include <asm/dma.h>#include <asm/io.h>#include <asm/segment.h>#include <linux/wait.h>#include <linux/malloc.h>#include <linux/ioport.h>#endif				/* __KERNEL__ */#include <linux/delay.h>#include <linux/proc_fs.h>#include "soundmodule.h"struct notifier_block *sound_locker=(struct notifier_block *)0;static int lock_depth = 0;#ifdef MODULE#define modular 1#else#define modular 0#endif/* * This ought to be moved into include/asm/dma.h */#ifndef valid_dma#define valid_dma(n) ((n) >= 0 && (n) < MAX_DMA_CHANNELS && (n) != 4)#endifstatic int      chrdev_registered = 0;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;/* Persistent DMA buffers */#ifdef CONFIG_SOUND_DMAPint		sound_dmap_flag = 1;#elseint		sound_dmap_flag = 0;#endifstatic int      soundcard_configured = 0;static char     dma_alloc_map[MAX_DMA_CHANNELS] ={0};#define DMA_MAP_UNAVAIL		0#define DMA_MAP_FREE		1#define DMA_MAP_BUSY		2static int in_use = 0;	        /* Total # of open devices */unsigned long seq_time = 0;	/* Time for /dev/sequencer *//* * Table for configurable mixer volume handling */static mixer_vol_table mixer_vols[MAX_MIXER_DEV];static int num_mixer_volumes = 0;int *load_mixer_volumes(char *name, int *levels, int present){	int             i, n;	for (i = 0; i < num_mixer_volumes; i++)	{		if (strcmp(name, mixer_vols[i].name) == 0)		{			if (present)				mixer_vols[i].num = i;			return mixer_vols[i].levels;		}	}	if (num_mixer_volumes >= MAX_MIXER_DEV)	{		printk(KERN_ERR "Sound: Too many mixers (%s)\n", name);		return levels;	}	n = num_mixer_volumes++;	strcpy(mixer_vols[n].name, name);	if (present)		mixer_vols[n].num = n;	else		mixer_vols[n].num = -1;	for (i = 0; i < 32; i++)		mixer_vols[n].levels[i] = levels[i];	return mixer_vols[n].levels;}static int set_mixer_levels(caddr_t arg){        /* mixer_vol_table is 174 bytes, so IMHO no reason to not allocate it on the stack */	mixer_vol_table buf;   	if (__copy_from_user(&buf, arg, sizeof(buf)))		return -EFAULT;	load_mixer_volumes(buf.name, buf.levels, 0);	if (__copy_to_user(arg, &buf, sizeof(buf)))		return -EFAULT;	return 0;}static int get_mixer_levels(caddr_t arg){	int n;	if (__get_user(n, (int *)(&(((mixer_vol_table *)arg)->num))))		return -EFAULT;	if (n < 0 || n >= num_mixer_volumes)		return -EINVAL;	if (__copy_to_user(arg, &mixer_vols[n], sizeof(mixer_vol_table)))		return -EFAULT;	return 0;}static int sound_proc_get_info(char *buffer, char **start, off_t offset, int length, int inout){	int len, i, drv;        off_t pos = 0;        off_t begin = 0;#ifdef MODULE#define MODULEPROCSTRING "Driver loaded as a module"#else#define MODULEPROCSTRING "Driver compiled into kernel"#endif#ifdef OSKIT	len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"		      "Load type: " MODULEPROCSTRING "\n"		      "Config options: %x\n\nInstalled drivers: \n", 		      SELECTED_SOUND_OPTIONS);#else	down(&uts_sem);		len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"		      "Load type: " MODULEPROCSTRING "\n"		      "Kernel: %s %s %s %s %s\n"		      "Config options: %x\n\nInstalled drivers: \n", 		      system_utsname.sysname, system_utsname.nodename, system_utsname.release, 		      system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);	up(&uts_sem);#endif		for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) {		if (!sound_drivers[i].card_type)			continue;		len += sprintf(buffer + len, "Type %d: %s\n", 			       sound_drivers[i].card_type, sound_drivers[i].name);		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}	}	len += sprintf(buffer + len, "\nCard config: \n");	for (i = 0; (i < num_sound_cards) && (pos <= offset + length); i++) 	{		if (!snd_installed_cards[i].card_type)			continue;		if (!snd_installed_cards[i].enabled)			len += sprintf(buffer + len, "(");		if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1)			len += sprintf(buffer + len, "%s", sound_drivers[drv].name);		if (snd_installed_cards[i].config.io_base)			len += sprintf(buffer + len, " at 0x%x", snd_installed_cards[i].config.io_base);		if (snd_installed_cards[i].config.irq != 0)			len += sprintf(buffer + len, " irq %d", abs(snd_installed_cards[i].config.irq));		if (snd_installed_cards[i].config.dma != -1) {			len += sprintf(buffer + len, " drq %d", snd_installed_cards[i].config.dma);			if (snd_installed_cards[i].config.dma2 != -1)				len += sprintf(buffer + len, ",%d", snd_installed_cards[i].config.dma2);		}		if (!snd_installed_cards[i].enabled)			len += sprintf(buffer + len, ")");		len += sprintf(buffer + len, "\n");		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}	}	if (!sound_started)		len += sprintf(buffer + len, "\n\n***** Sound driver not started *****\n\n");#ifndef CONFIG_AUDIO	len += sprintf(buffer + len, "\nAudio devices: NOT ENABLED IN CONFIG\n");#else	len += sprintf(buffer + len, "\nAudio devices:\n");	for (i = 0; (i < num_audiodevs) && (pos <= offset + length); i++) {		if (audio_devs[i] == NULL)			continue;		len += sprintf(buffer + len, "%d: %s%s\n", i, audio_devs[i]->name, 			       audio_devs[i]->flags & DMA_DUPLEX ? " (DUPLEX)" : "");		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}	}#endif#ifndef CONFIG_SEQUENCER	len += sprintf(buffer + len, "\nSynth devices: NOT ENABLED IN CONFIG\n");#else	len += sprintf(buffer + len, "\nSynth devices:\n");	for (i = 0; (i < num_synths) && (pos <= offset + length); i++) {		if (synth_devs[i] == NULL)			continue;		len += sprintf(buffer + len, "%d: %s\n", i, synth_devs[i]->info->name);		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}	}#endif#ifndef CONFIG_MIDI	len += sprintf(buffer + len, "\nMidi devices: NOT ENABLED IN CONFIG\n");#else	len += sprintf(buffer + len, "\nMidi devices:\n");	for (i = 0; (i < num_midis) && (pos <= offset + length); i++) {		if (midi_devs[i] == NULL)			continue;		len += sprintf(buffer + len, "%d: %s\n", i, midi_devs[i]->info.name);		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}	}#endif#ifdef CONFIG_SEQUENCER	len += sprintf(buffer + len, "\nTimers:\n");	for (i = 0; (i < num_sound_timers) && (pos <= offset + length); i++) {		if (sound_timer_devs[i] == NULL)			continue;		len += sprintf(buffer + len, "%d: %s\n", i, sound_timer_devs[i]->info.name);		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}	}#endif	len += sprintf(buffer + len, "\nMixers:\n");	for (i = 0; (i < num_mixers) && (pos <= offset + length); i++) {		if (mixer_devs[i] == NULL)			continue;		len += sprintf(buffer + len, "%d: %s\n", i, mixer_devs[i]->name);		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}	}	*start = buffer + (offset - begin);	len -= (offset - begin);        if (len > length) 		len = length;        return len;}#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry proc_root_sound = {        PROC_SOUND, 5, "sound",        S_IFREG | S_IRUGO, 1, 0, 0,        0, NULL, sound_proc_get_info};#endif#ifndef MIN#define MIN(a,b) (((a) < (b)) ? (a) : (b))#endif/* 4K page size but our output routines use some slack for overruns */#define PROC_BLOCK_SIZE (3*1024)/* * basically copied from fs/proc/generic.c:proc_file_read  * should be removed sometime in the future together with /dev/sndstat * (a symlink /dev/sndstat -> /proc/sound will do as well) */static ssize_t sndstat_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos){        char    *page;        ssize_t retval=0;        int     eof=0;        ssize_t n, count;        char    *start;        if (!(page = (char*) __get_free_page(GFP_KERNEL)))                return -ENOMEM;        while ((nbytes > 0) && !eof)        {                count = MIN(PROC_BLOCK_SIZE, nbytes);                start = NULL;		n = sound_proc_get_info(page, &start, *ppos, count, 0);		if (n < count)			eof = 1;                                        if (!start) {                        /*                         * For proc files that are less than 4k                         */                        start = page + *ppos;                        n -= *ppos;                        if (n <= 0)                                break;                        if (n > count)                                n = count;                }                if (n == 0)                        break;  /* End of file */                if (n < 0) {                        if (retval == 0)                                retval = n;                        break;                }                                n -= copy_to_user(buf, start, n);       /* BUG ??? */                if (n == 0) {                        if (retval == 0)                                retval = -EFAULT;                        break;                }                                *ppos += n;     /* Move down the file */                nbytes -= n;                buf += n;                retval += n;        }        free_page((unsigned long) page);        return retval;}static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos){	int dev = MINOR(file->f_dentry->d_inode->i_rdev);	DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));	switch (dev & 0x0f) {	case SND_DEV_STATUS:		return sndstat_file_read(file, buf, count, ppos);#ifdef CONFIG_AUDIO	case SND_DEV_DSP:	case SND_DEV_DSP16:	case SND_DEV_AUDIO:		return audio_read(dev, file, buf, count);#endif#ifdef CONFIG_SEQUENCER	case SND_DEV_SEQ:	case SND_DEV_SEQ2:		return sequencer_read(dev, file, buf, count);#endif#ifdef CONFIG_MIDI	case SND_DEV_MIDIN:		return MIDIbuf_read(dev, file, buf, count);#endif	default:;	}	return -EINVAL;}static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos){	int dev = MINOR(file->f_dentry->d_inode->i_rdev);	DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));	switch (dev & 0x0f) {#ifdef CONFIG_SEQUENCER	case SND_DEV_SEQ:	case SND_DEV_SEQ2:		return sequencer_write(dev, file, buf, count);#endif#ifdef CONFIG_AUDIO	case SND_DEV_DSP:	case SND_DEV_DSP16:	case SND_DEV_AUDIO:		return audio_write(dev, file, buf, count);#endif#ifdef CONFIG_MIDI	case SND_DEV_MIDIN:		return MIDIbuf_write(dev, file, buf, count);#endif	}	return -EINVAL;}static long long sound_lseek(struct file *file, long long offset, int orig){	return -ESPIPE;}static int sound_open(struct inode *inode, struct file *file){	int dev, retval;	if (is_unloading) {		/* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/		return -EBUSY;	}	dev = MINOR(inode->i_rdev);	if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) {		/* printk("SoundCard Error: The sound system has not been configured\n");*/		return -ENXIO;	}	DEB(printk("sound_open(dev=%d)\n", dev));	if ((dev >= SND_NDEVS) || (dev < 0)) {		/* printk(KERN_ERR "Invalid minor device %d\n", dev);*/		return -ENXIO;	}	switch (dev & 0x0f) {	case SND_DEV_STATUS:		break;	case SND_DEV_CTL:		dev >>= 4;		if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {			char modname[20];			sprintf(modname, "mixer%d", dev);			request_module(modname);		}		if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL))			return -ENXIO;		break;#ifdef CONFIG_SEQUENCER	case SND_DEV_SEQ:	case SND_DEV_SEQ2:		if ((retval = sequencer_open(dev, file)) < 0)			return retval;		break;#endif#ifdef CONFIG_MIDI	case SND_DEV_MIDIN:		if ((retval = MIDIbuf_open(dev, file)) < 0)			return retval;		break;#endif#ifdef CONFIG_AUDIO	case SND_DEV_DSP:	case SND_DEV_DSP16:	case SND_DEV_AUDIO:		if ((retval = audio_open(dev, file)) < 0)			return retval;		break;#endif	default:		printk(KERN_ERR "Invalid minor device %d\n", dev);		return -ENXIO;	}	in_use++;#ifdef CONFIG_MODULES	notifier_call_chain(&sound_locker, 1, 0);	lock_depth++;#endif	return 0;}static int sound_release(struct inode *inode, struct file *file){	int dev = MINOR(inode->i_rdev);	DEB(printk("sound_release(dev=%d)\n", dev));	switch (dev & 0x0f) {	case SND_DEV_STATUS:	case SND_DEV_CTL:		break;		#ifdef CONFIG_SEQUENCER	case SND_DEV_SEQ:	case SND_DEV_SEQ2:		sequencer_release(dev, file);		break;#endif#ifdef CONFIG_MIDI	case SND_DEV_MIDIN:		MIDIbuf_release(dev, file);		break;#endif#ifdef CONFIG_AUDIO	case SND_DEV_DSP:	case SND_DEV_DSP16:	case SND_DEV_AUDIO:		audio_release(dev, file);		break;#endif	default:		printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);	}	in_use--;#ifdef CONFIG_MODULES	notifier_call_chain(&sound_locker, 0, 0);	lock_depth--;#endif	return 0;}static int get_mixer_info(int dev, caddr_t arg){	mixer_info info;	strncpy(info.id, mixer_devs[dev]->id, sizeof(info.id));

⌨️ 快捷键说明

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