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

📄 opl3.c

📁 opl3的驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
     static void bend_pitch(int dev, int voice, int value)
     {
     	unsigned char data;
     	int block, fnum, freq;
     	struct physical_voice_info *map;
     
     	map = &pv_map[devc->lv_map[voice]];
     
     	if (map->voice_mode == 0)
     		return;
     
     	devc->voc[voice].bender = value;
     	if (!value)
     		return;
     	if (!(devc->voc[voice].keyon_byte & 0x20))
     		return;	/*
     			 * Not keyed on
     			 */
     
     	freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range, 0);
     	devc->voc[voice].current_freq = freq;
     
     	freq_to_fnum(freq, &block, &fnum);
     
     	data = fnum & 0xff;	/*
     				 * Least significant bits of fnumber
     				 */
     	opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data);
     
     	data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
     	devc->voc[voice].keyon_byte = data;
     	opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data);
     }
     
     static void opl3_controller (int dev, int voice, int ctrl_num, int value)
     {
     	if (voice < 0 || voice >= devc->nr_voice)
     		return;
     
     	switch (ctrl_num)
     	{
     		case CTRL_PITCH_BENDER:
     			bend_pitch(dev, voice, value);
     			break;
     
     		case CTRL_PITCH_BENDER_RANGE:
     			devc->voc[voice].bender_range = value;
     			break;
     
     		case CTL_MAIN_VOLUME:
     			devc->voc[voice].volume = value / 128;
     			break;
     
     		case CTL_PAN:
     			devc->voc[voice].panning = (value * 2) - 128;
     			break;
     	}
     }
     
     static void opl3_bender(int dev, int voice, int value)
     {
     	if (voice < 0 || voice >= devc->nr_voice)
     		return;
     
     	bend_pitch(dev, voice, value - 8192);
     }
     
     static int opl3_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc)
     {
     	int i, p, best, first, avail, best_time = 0x7fffffff;
     	struct sbi_instrument *instr;
     	int is4op;
     	int instr_no;
     
     	if (chn < 0 || chn > 15)
     		instr_no = 0;
     	else
     		instr_no = devc->chn_info[chn].pgm_num;
     
     	instr = &devc->i_map[instr_no];
     	if (instr->channel < 0 ||	/* Instrument not loaded */
     		devc->nr_voice != 12)	/* Not in 4 OP mode */
     		is4op = 0;
     	else if (devc->nr_voice == 12)	/* 4 OP mode */
     		is4op = (instr->key == OPL3_PATCH);
     	else
     		is4op = 0;
     
     	if (is4op)
     	{
     		first = p = 0;
     		avail = 6;
     	}
     	else
     	{
     		if (devc->nr_voice == 12)	/* 4 OP mode. Use the '2 OP only' operators first */
     			first = p = 6;
     		else
     			first = p = 0;
     		avail = devc->nr_voice;
     	}
     
     	/*
     	 *    Now try to find a free voice
     	 */
     	best = first;
     
     	for (i = 0; i < avail; i++)
     	{
     		if (alloc->map[p] == 0)
     		{
     			return p;
     		}
     		if (alloc->alloc_times[p] < best_time)		/* Find oldest playing note */
     		{
     			best_time = alloc->alloc_times[p];
     			best = p;
     		}
     		p = (p + 1) % avail;
     	}
     
     	/*
     	 *    Insert some kind of priority mechanism here.
     	 */
     
     	if (best < 0)
     		best = 0;
     	if (best > devc->nr_voice)
     		best -= devc->nr_voice;
     
     	return best;	/* All devc->voc in use. Select the first one. */
     }
     
     static void opl3_setup_voice(int dev, int voice, int chn)
     {
     	struct channel_info *info =
     	&synth_devs[dev]->chn_info[chn];
     
     	opl3_set_instr(dev, voice, info->pgm_num);
     
     	devc->voc[voice].bender = 0;
     	devc->voc[voice].bender_range = info->bender_range;
     	devc->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME];
     	devc->voc[voice].panning = (info->controllers[CTL_PAN] * 2) - 128;
     }
     
     static struct synth_operations opl3_operations =
     {
     	owner:		THIS_MODULE,
     	id:		"OPL",
     	info:		NULL,
     	midi_dev:	0,
     	synth_type:	SYNTH_TYPE_FM,
     	synth_subtype:	FM_TYPE_ADLIB,
     	open:		opl3_open,
     	close:		opl3_close,
     	ioctl:		opl3_ioctl,
     	kill_note:	opl3_kill_note,
     	start_note:	opl3_start_note,
     	set_instr:	opl3_set_instr,
     	reset:		opl3_reset,
     	hw_control:	opl3_hw_control,
     	load_patch:	opl3_load_patch,
     	aftertouch:	opl3_aftertouch,
     	controller:	opl3_controller,
     	panning:	opl3_panning,
     	volume_method:	opl3_volume_method,
     	bender:		opl3_bender,
     	alloc_voice:	opl3_alloc_voice,
     	setup_voice:	opl3_setup_voice
     };
     
     int opl3_init(int ioaddr, int *osp, struct module *owner)
     {
     	int i;
     	int me;
     
     	if (devc == NULL)
     	{
     		printk(KERN_ERR "opl3: Device control structure not initialized.\n");
     		return -1;
     	}
     
     	if ((me = sound_alloc_synthdev()) == -1)
     	{
     		printk(KERN_WARNING "opl3: Too many synthesizers\n");
     		return -1;
     	}
     
     	devc->nr_voice = 9;
     
     	devc->fm_info.device = 0;
     	devc->fm_info.synth_type = SYNTH_TYPE_FM;
     	devc->fm_info.synth_subtype = FM_TYPE_ADLIB;
     	devc->fm_info.perc_mode = 0;
     	devc->fm_info.nr_voices = 9;
     	devc->fm_info.nr_drums = 0;
     	devc->fm_info.instr_bank_size = SBFM_MAXINSTR;
     	devc->fm_info.capabilities = 0;
     	devc->left_io = ioaddr;
     	devc->right_io = ioaddr + 2;
     
     	if (detected_model <= 2)
     		devc->model = 1;
     	else
     	{
     		devc->model = 2;
     		if (detected_model == 4)
     			devc->is_opl4 = 1;
     	}
     
     	opl3_operations.info = &devc->fm_info;
     
     	synth_devs[me] = &opl3_operations;
     
     	if (owner)
     		synth_devs[me]->owner = owner;
     	
     	sequencer_init();
     	devc->v_alloc = &opl3_operations.alloc;
     	devc->chn_info = &opl3_operations.chn_info[0];
     
     	if (devc->model == 2)
     	{
     		if (devc->is_opl4) 
     			strcpy(devc->fm_info.name, "Yamaha OPL4/OPL3 FM");
     		else 
     			strcpy(devc->fm_info.name, "Yamaha OPL3");
     
     		devc->v_alloc->max_voice = devc->nr_voice = 18;
     		devc->fm_info.nr_drums = 0;
     		devc->fm_info.synth_subtype = FM_TYPE_OPL3;
     		devc->fm_info.capabilities |= SYNTH_CAP_OPL3;
     
     		for (i = 0; i < 18; i++)
     		{
     			if (pv_map[i].ioaddr == USE_LEFT)
     				pv_map[i].ioaddr = devc->left_io;
     			else
     				pv_map[i].ioaddr = devc->right_io;
     		}
     		opl3_command(devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE);
     		opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x00);
     	}
     	else
     	{
     		strcpy(devc->fm_info.name, "Yamaha OPL2");
     		devc->v_alloc->max_voice = devc->nr_voice = 9;
     		devc->fm_info.nr_drums = 0;
     
     		for (i = 0; i < 18; i++)
     			pv_map[i].ioaddr = devc->left_io;
     	};
     	conf_printf2(devc->fm_info.name, ioaddr, 0, -1, -1);
     
     	for (i = 0; i < SBFM_MAXINSTR; i++)
     		devc->i_map[i].channel = -1;
     
     	return me;
     }
     
     EXPORT_SYMBOL(opl3_init);
     EXPORT_SYMBOL(opl3_detect);
     
     static int me;
     
     static int io = -1;
     
     MODULE_PARM(io, "i");
     
     static int __init init_opl3 (void)
     {
     	printk(KERN_INFO "YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n");
     
     	if (io != -1)	/* User loading pure OPL3 module */
     	{
     		if (!opl3_detect(io, NULL))
     		{
     			return -ENODEV;
     		}
     
     		me = opl3_init(io, NULL, THIS_MODULE);
     	}
     
     	return 0;
     }
     
     static void __exit cleanup_opl3(void)
     {
     	if (devc && io != -1)
     	{
     		if (devc->base) {
     			release_region(devc->base,4);
     			if (devc->is_opl4)
     				release_region(devc->base - 8, 2);
     		}
     		kfree(devc);
     		devc = NULL;
     		sound_unload_synthdev(me);
     	}
     }
     
     module_init(init_opl3);
     module_exit(cleanup_opl3);
     
     #ifndef MODULE
     static int __init setup_opl3(char *str)
     {
             /* io  */
     	int ints[2];
     	
     	str = get_options(str, ARRAY_SIZE(ints), ints);
     	
     	io = ints[1];
     
     	return 1;
     }
     
     __setup("opl3=", setup_opl3);
     #endif
     
File: /usr/src/linux/drivers/sound/opl3.c
   /*
    * sound/opl3.c
    *
    * A low level driver for Yamaha YM3812 and OPL-3 -chips
    *
    *
    * 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.
     *
     *
     * Changes
     *	Thomas Sailer   	ioctl code reworked (vmalloc/vfree removed)
     *	Alan Cox		modularisation, fixed sound_mem allocs.
     *	Christoph Hellwig	Adapted to module_init/module_exit
     *	Arnaldo C. de Melo	get rid of check_region, use request_region for
     *				OPL4, release it on exit, some cleanups.
     *
     * Status
     *	Believed to work. Badly needs rewriting a bit to support multiple
     *	OPL3 devices.
     */
    
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/delay.h>
    
    /*
     * Major improvements to the FM handling 30AUG92 by Rob Hooft,
     * hooft@chem.ruu.nl
     */
    
    #include "sound_config.h"
    
    #include "opl3.h"
    #include "opl3_hw.h"
    
    #define MAX_VOICE	18
    #define OFFS_4OP	11
    
    struct voice_info
    {
    	unsigned char   keyon_byte;
    	long            bender;
    	long            bender_range;
    	unsigned long   orig_freq;
    	unsigned long   current_freq;
    	int             volume;
    	int             mode;
    	int             panning;	/* 0xffff means not set */
    };
    
    typedef struct opl_devinfo
    {
    	int             base;
    	int             left_io, right_io;
    	int             nr_voice;
    	int             lv_map[MAX_VOICE];
    
    	struct voice_info voc[MAX_VOICE];
    	struct voice_alloc_info *v_alloc;
    	struct channel_info *chn_info;
    
    	struct sbi_instrument i_map[SBFM_MAXINSTR];
    	struct sbi_instrument *act_i[MAX_VOICE];
    
    	struct synth_info fm_info;
    
    	int             busy;
    	int             model;
    	unsigned char   cmask;
    
    	int             is_opl4;
    	int            *osp;
    } opl_devinfo;
    
    static struct opl_devinfo *devc = NULL;
    
    static int      detected_model;
    
    static int      store_instr(int instr_no, struct sbi_instrument *instr);
    static void     freq_to_fnum(int freq, int *block, int *fnum);
    static void     opl3_command(int io_addr, unsigned int addr, unsigned int val);
    static int      opl3_kill_note(int dev, int voice, int note, int velocity);
    
    static void enter_4op_mode(void)
    {
    	int i;
    	static int v4op[MAX_VOICE] = {
    		0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17
    	};
    
    	devc->cmask = 0x3f;	/* Connect all possible 4 OP voice operators */
    	opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f);
    
    	for (i = 0; i < 3; i++)
    		pv_map[i].voice_mode = 4;
     	for (i = 3; i < 6; i++)
     		pv_map[i].voice_mode = 0;
     
     	for (i = 9; i < 12; i++)
     		pv_map[i].voice_mode = 4;
     	for (i = 12; i < 15; i++)
     		pv_map[i].voice_mode = 0;
     
     	for (i = 0; i < 12; i++)
     		devc->lv_map[i] = v4op[i];
     	devc->v_alloc->max_voice = devc->nr_voice = 12;
     }
     
     static int opl3_ioctl(int dev, unsigned int cmd, caddr_t arg)
     {
     	struct sbi_instrument ins;
     	
     	switch (cmd) {
     		case SNDCTL_FM_LOAD_INSTR:
     			printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
     			if (copy_from_user(&ins, arg, sizeof(ins)))
     				return -EFAULT;
     			if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) {
     				printk(KERN_WARNING "FM Error: Invalid instrument number %d\n", ins.channel);
     				return -EINVAL;
     			}
     			return store_instr(ins.channel, &ins);
     
     		case SNDCTL_SYNTH_INFO:
     			devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
     			if (copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info)))
     				return -EFAULT;
     			return 0;
     
     		case SNDCTL_SYNTH_MEMAVL:
     			return 0x7fffffff;
     
     		case SNDCTL_FM_4OP_ENABLE:
     			if (devc->model == 2)
     				enter_4op_mode();
     			return 0;
     
     		default:
     			return -EINVAL;
     	}

⌨️ 快捷键说明

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