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

📄 opl3sa2.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * sound/opl3sa2.c * * A low level driver for Yamaha OPL3-SA2 and SA3 cards. * SAx cards should work, as they are just variants of the SA3. * * Copyright 1998, 1999 Scott Murray <scottm@interlog.com> * * Originally based on the CS4232 driver (in cs4232.c) by Hannu Savolainen * and others.  Now incorporates code/ideas from pss.c, also by Hannu * Savolainen.  Both of those files are distributed with the following * license: * * "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." * * As such, in accordance with the above license, this file, opl3sa2.c, is * distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2 (June 1991). * See the "COPYING" file distributed with this software for more information. * * Change History * -------------- * Scott Murray            Original driver (Jun 14, 1998) * Paul J.Y. Lahaie        Changed probing / attach code order * Scott Murray            Added mixer support (Dec 03, 1998) * Scott Murray            Changed detection code to be more forgiving, *                         added force option as last resort, *                         fixed ioctl return values. (Dec 30, 1998) * Scott Murray            Simpler detection code should work all the time now *                         (with thanks to Ben Hutchings for the heuristic), *                         removed now unnecessary force option. (Jan 5, 1999) * Christoph Hellwig	   Adapted to module_init/module_exit (Mar 4, 2000) * */#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include "sound_config.h"#include "ad1848.h"#include "mpu401.h"/* Useful control port indexes: */#define OPL3SA2_MASTER_LEFT  0x07#define OPL3SA2_MASTER_RIGHT 0x08#define OPL3SA2_MIC          0x09#define OPL3SA2_MISC         0x0A#define OPL3SA3_WIDE         0x14#define OPL3SA3_BASS         0x15#define OPL3SA3_TREBLE       0x16/* Useful constants: */#define DEFAULT_VOLUME 50#define DEFAULT_MIC    50#define DEFAULT_TIMBRE 0#define CHIPSET_UNKNOWN -1/* * These are used both as masks against what the card returns, * and as constants. */#define CHIPSET_OPL3SA2  1#define CHIPSET_OPL3SA3  2#define CHIPSET_OPL3SAX  4/* What's my version? */static int chipset = CHIPSET_UNKNOWN;/* Oh well, let's just cache the name */static char chipset_name[16];/* Where's my mixer */static int opl3sa2_mixer = -1;/* Bag o' mixer data */typedef struct opl3sa2_mixerdata {	unsigned short cfg_port;	unsigned short padding;	int            ad_mixer_dev;	unsigned int   volume_l;	unsigned int   volume_r;	unsigned int   mic;	unsigned int   bass;	unsigned int   treble;} opl3sa2_mixerdata;#ifdef CONFIG_OPL3SA2_CTRL_BASE/* Set control port if compiled into the kernel */static opl3sa2_mixerdata opl3sa2_data = { CONFIG_OPL3SA2_CTRL_BASE, };#elsestatic opl3sa2_mixerdata opl3sa2_data;#endifstatic opl3sa2_mixerdata *devc = &opl3sa2_data;/* Standard read and write functions */static void opl3sa2_write(unsigned short port,			  unsigned char  index,			  unsigned char  data){	outb_p(index, port);	outb(data, port + 1);}static void opl3sa2_read(unsigned short port,			 unsigned char  index,			 unsigned char* data){	outb_p(index, port);	*data = inb(port + 1);}/* All of the mixer functions... */static void opl3sa2_set_volume(opl3sa2_mixerdata *devc, int left, int right){	static unsigned char scale[101] = {		0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 		0x0e, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 		0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 		0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 		0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 		0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 		0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 		0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 		0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 		0x00	};	unsigned char vol;	vol = scale[left];	/* If level is zero, turn on mute */	if(!left)		vol |= 0x80;	opl3sa2_write(devc->cfg_port, OPL3SA2_MASTER_LEFT, vol);	vol = scale[right];	/* If level is zero, turn on mute */	if(!right)		vol |= 0x80;	opl3sa2_write(devc->cfg_port, OPL3SA2_MASTER_RIGHT, vol);}static void opl3sa2_set_mic(opl3sa2_mixerdata *devc, int level){	unsigned char vol = 0x1F;	if((level >= 0) && (level <= 100))		vol = 0x1F - (unsigned char) (0x1F * level / 100L);	/* If level is zero, turn on mute */	if(!level)		vol |= 0x80;	opl3sa2_write(devc->cfg_port, OPL3SA2_MIC, vol);}static void opl3sa3_set_bass(opl3sa2_mixerdata *devc, int level){	unsigned char bass;	bass = level ? ((unsigned char) (0x07 * level / 100L)) : 0; 	bass |= (bass << 4);	opl3sa2_write(devc->cfg_port, OPL3SA3_BASS, bass);}static void opl3sa3_set_treble(opl3sa2_mixerdata *devc, int level){		unsigned char treble;	treble = level ? ((unsigned char) (0x07 * level / 100L)) : 0; 	treble |= (treble << 4);	opl3sa2_write(devc->cfg_port, OPL3SA3_TREBLE, treble);}static void opl3sa2_mixer_reset(opl3sa2_mixerdata *devc){	if(devc)	{		opl3sa2_set_volume(devc, DEFAULT_VOLUME, DEFAULT_VOLUME);		devc->volume_l = devc->volume_r = DEFAULT_VOLUME;		opl3sa2_set_mic(devc, DEFAULT_MIC);		devc->mic = DEFAULT_MIC;		opl3sa3_set_bass(devc, DEFAULT_TIMBRE);		opl3sa3_set_treble(devc, DEFAULT_TIMBRE);		devc->bass = devc->treble = DEFAULT_TIMBRE;	}}static void arg_to_volume_mono(unsigned int volume, int *aleft){	int left;		left = volume & 0x00ff;	if (left > 100)		left = 100;	*aleft = left;}static void arg_to_volume_stereo(unsigned int volume, int *aleft, int *aright){	arg_to_volume_mono(volume, aleft);	arg_to_volume_mono(volume >> 8, aright);}static int ret_vol_mono(int left){	return ((left << 8) | left);}static int ret_vol_stereo(int left, int right){	return ((right << 8) | left);}static int call_ad_mixer(opl3sa2_mixerdata *devc, unsigned int cmd, caddr_t arg){	if(devc->ad_mixer_dev != -1) 		return mixer_devs[devc->ad_mixer_dev]->ioctl(devc->ad_mixer_dev,							     cmd,							     arg);	else 		return -EINVAL;}static int opl3sa2_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg){	int cmdf = cmd & 0xff;	opl3sa2_mixerdata* devc = (opl3sa2_mixerdata*) mixer_devs[dev]->devc;		switch(cmdf)	{		case SOUND_MIXER_VOLUME:		case SOUND_MIXER_MIC:		case SOUND_MIXER_BASS:		case SOUND_MIXER_TREBLE:		case SOUND_MIXER_DEVMASK:		case SOUND_MIXER_STEREODEVS: 		case SOUND_MIXER_RECMASK:		case SOUND_MIXER_CAPS: 		case SOUND_MIXER_RECSRC:			break;		default:			return call_ad_mixer(devc, cmd, arg);	}		if(((cmd >> 8) & 0xff) != 'M')		return -EINVAL;			if(_SIOC_DIR (cmd) & _SIOC_WRITE)	{		switch (cmdf)			{			case SOUND_MIXER_RECSRC:				if(devc->ad_mixer_dev != -1)					return call_ad_mixer(devc, cmd, arg);				else				{					if(*(int*)arg != 0)						return -EINVAL;					return 0;				}			case SOUND_MIXER_VOLUME:				arg_to_volume_stereo(*(unsigned int*)arg,						     &devc->volume_l,						     &devc->volume_r); 				opl3sa2_set_volume(devc, devc->volume_l,						   devc->volume_r);				*(int*)arg = ret_vol_stereo(devc->volume_l,							     devc->volume_r);				return 0;		  			case SOUND_MIXER_MIC:				arg_to_volume_mono(*(unsigned int*)arg,						   &devc->mic);				opl3sa2_set_mic(devc, devc->mic);				*(int*)arg = ret_vol_mono(devc->mic);				return 0;		  			case SOUND_MIXER_BASS:				if(chipset != CHIPSET_OPL3SA2)				{					arg_to_volume_mono(*(unsigned int*)arg,							   &devc->bass);					opl3sa3_set_bass(devc, devc->bass);					*(int*)arg = ret_vol_mono(devc->bass);					return 0;				}				return -EINVAL;		  			case SOUND_MIXER_TREBLE:				if(chipset != CHIPSET_OPL3SA2)				{					arg_to_volume_mono(*(unsigned int *)arg,							   &devc->treble);					opl3sa3_set_treble(devc, devc->treble);					*(int*)arg = ret_vol_mono(devc->treble);					return 0;				}				return -EINVAL;		  			default:				return -EINVAL;		}	}	else				{		/*		 * Return parameters		 */		switch (cmdf)		{			case SOUND_MIXER_DEVMASK:				if(call_ad_mixer(devc, cmd, arg) == -EINVAL)					*(int*)arg = 0; /* no mixer devices */				*(int*)arg |= (SOUND_MASK_VOLUME | SOUND_MASK_MIC);				/* OPL3-SA2 has no bass and treble mixers */				if(chipset != CHIPSET_OPL3SA2)					*(int*)arg |= (SOUND_MASK_BASS |						       SOUND_MASK_TREBLE);				return 0;		  			case SOUND_MIXER_STEREODEVS:				if(call_ad_mixer(devc, cmd, arg) == -EINVAL)					*(int*)arg = 0; /* no stereo devices */				*(int*)arg |= SOUND_MASK_VOLUME;				return 0;		  			case SOUND_MIXER_RECMASK:				if(devc->ad_mixer_dev != -1)				{					return call_ad_mixer(devc, cmd, arg);				}				else

⌨️ 快捷键说明

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