/*
* sound/oss/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/slab.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_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 */
};
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;
};
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 =