Index: head/sys/i386/isa/sound/opl3.c =================================================================== --- head/sys/i386/isa/sound/opl3.c (revision 55120) +++ head/sys/i386/isa/sound/opl3.c (revision 55121) @@ -1,1132 +1,1137 @@ /* * sound/opl3.c * * A low level driver for Yamaha YM3812 and OPL-3 -chips * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD$ + * */ /* * Major improvements to the FM handling 30AUG92 by Rob Hooft, */ /* * hooft@chem.ruu.nl */ #include #if defined(CONFIG_YM3812) #include #include #define MAX_VOICE 18 #define OFFS_4OP 11 struct voice_info { u_char keyon_byte; long bender; long bender_range; u_long orig_freq; u_long current_freq; int volume; int mode; }; typedef struct opl_devinfo { 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; u_char cmask; int is_opl4; sound_os_info *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, u_int addr, u_int val); static int opl3_kill_note(int dev, int voice, int note, int velocity); void enable_opl3_mode(int left, int right, int both) { /* NOP */ } 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, u_int cmd, ioctl_arg arg) { switch (cmd) { case SNDCTL_FM_LOAD_INSTR: { struct sbi_instrument ins; bcopy(&(((char *) arg)[0]), (char *) &ins, sizeof(ins)); if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { printf("FM Error: Invalid instrument number %d\n", ins.channel); return -(EINVAL); } pmgr_inform(dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0); return store_instr(ins.channel, &ins); } break; case SNDCTL_SYNTH_INFO: devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; bcopy(&devc->fm_info, &(((char *) arg)[0]), sizeof(devc->fm_info)); return 0; break; case SNDCTL_SYNTH_MEMAVL: return 0x7fffffff; break; case SNDCTL_FM_4OP_ENABLE: if (devc->model == 2) enter_4op_mode(); return 0; break; default: return -(EINVAL); } } int opl3_detect(int ioaddr, sound_os_info * osp) { /* * This function returns 1 if the FM chip is present at the given * I/O port The detection algorithm plays with the timer built in the * FM chip and looks for a change in the status register. * * Note! The timers of the FM chip are not connected to AdLib (and * compatible) boards. * * Note2! The chip is initialized if detected. */ u_char stat1, stat2, signature; int i; if (devc != NULL) return 0; devc = (struct opl_devinfo *) malloc(sizeof(*devc), M_DEVBUF, M_NOWAIT); if (!devc) panic("SOUND: Cannot allocate memory\n"); if (devc == NULL) { printf("OPL3: Can't allocate memory for device control structure\n"); return 0; } devc->osp = osp; /* Reset timers 1 and 2 */ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset the IRQ of the FM chip */ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); signature = stat1 = inb(ioaddr); /* Status register */ if ((stat1 & 0xE0) != 0x00) { return 0; /* Should be 0x00 */ } opl3_command(ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER2_MASK | TIMER1_START); /* Unmask and start timer 1 */ DELAY(150); /* Now we have to delay at least 80 usec */ stat2 = inb(ioaddr); /* Read status after timers have expired */ /* * Stop the timers */ /* Reset timers 1 and 2 */ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset the IRQ of the FM chip */ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); if ((stat2 & 0xE0) != 0xc0) { return 0; /* There is no YM3812 */ } /* * There is a FM chicp in this address. Detect the type (OPL2 to * OPL4) */ if (signature == 0x06) {/* OPL2 */ detected_model = 2; } else if (signature == 0x00) { /* OPL3 or OPL4 */ u_char tmp; detected_model = 3; /* * Detect availability of OPL4 (_experimental_). Works * propably only after a cold boot. In addition the OPL4 port * of the chip may not be connected to the PC bus at all. */ opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0x00); opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); if ((tmp = inb(ioaddr)) == 0x02) { /* Have a OPL4 */ detected_model = 4; } if (!0) { /* OPL4 port is free */ /* XXX check here lr970711 */ int tmp; outb(ioaddr - 8, 0x02); /* Select OPL4 ID register */ DELAY(10); tmp = inb(ioaddr - 7); /* Read it */ DELAY(10); if (tmp == 0x20) { /* OPL4 should return 0x20 here */ detected_model = 4; outb(ioaddr - 8, 0xF8); /* Select OPL4 FM mixer control */ DELAY(10); outb(ioaddr - 7, 0x1B); /* Write value */ DELAY(10); } else detected_model = 3; } opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0); } for (i = 0; i < 9; i++) opl3_command(ioaddr, KEYON_BLOCK + i, 0); /* Note off */ opl3_command(ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); opl3_command(ioaddr, PERCUSSION_REGISTER, 0x00); /* Melodic mode. */ return 1; } static int opl3_kill_note(int dev, int voice, int note, int velocity) { struct physical_voice_info *map; if (voice < 0 || voice >= devc->nr_voice) return 0; devc->v_alloc->map[voice] = 0; map = &pv_map[devc->lv_map[voice]]; DEB(printf("Kill note %d\n", voice)); if (map->voice_mode == 0) return 0; opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, devc->voc[voice].keyon_byte & ~0x20); devc->voc[voice].keyon_byte = 0; devc->voc[voice].bender = 0; devc->voc[voice].volume = 64; devc->voc[voice].bender_range = 200; /* 200 cents = 2 semitones */ devc->voc[voice].orig_freq = 0; devc->voc[voice].current_freq = 0; devc->voc[voice].mode = 0; return 0; } #define HIHAT 0 #define CYMBAL 1 #define TOMTOM 2 #define SNARE 3 #define BDRUM 4 #define UNDEFINED TOMTOM #define DEFAULT TOMTOM static int store_instr(int instr_no, struct sbi_instrument * instr) { if (instr->key !=FM_PATCH && (instr->key !=OPL3_PATCH || devc->model != 2)) printf("FM warning: Invalid patch format field (key) 0x%x\n", instr->key); bcopy((char *) instr, (char *) &(devc->i_map[instr_no]), sizeof(*instr)); return 0; } static int opl3_set_instr(int dev, int voice, int instr_no) { if (voice < 0 || voice >= devc->nr_voice) return 0; if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) return 0; devc->act_i[voice] = &devc->i_map[instr_no]; return 0; } /* * The next table looks magical, but it certainly is not. Its values have * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception * for i=0. This log-table converts a linear volume-scaling (0..127) to a * logarithmic scaling as present in the FM-synthesizer chips. so : Volume * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative * volume -8 it was implemented as a table because it is only 128 bytes and * it saves a lot of log() calculations. (RH) */ static char fm_volume_table[128] = { -64, -48, -40, -35, -32, -29, -27, -26, -24, -23, -21, -20, -19, -18, -18, -17, -16, -15, -15, -14, -13, -13, -12, -12, -11, -11, -10, -10, -10, -9, -9, -8, -8, -8, -7, -7, -7, -6, -6, -6, -5, -5, -5, -5, -4, -4, -4, -4, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8}; static void calc_vol(u_char *regbyte, int volume, int main_vol) { int level = (~*regbyte & 0x3f); if (main_vol > 127) main_vol = 127; volume = (volume * main_vol) / 127; if (level) level += fm_volume_table[volume]; RANGE (level, 0, 0x3f ); *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); } static void set_voice_volume(int voice, int volume, int main_vol) { u_char vol1, vol2, vol3, vol4; struct sbi_instrument *instr; struct physical_voice_info *map; if (voice < 0 || voice >= devc->nr_voice) return; map = &pv_map[devc->lv_map[voice]]; instr = devc->act_i[voice]; if (!instr) instr = &devc->i_map[0]; if (instr->channel < 0) return; if (devc->voc[voice].mode == 0) return; if (devc->voc[voice].mode == 2) { vol1 = instr->operators[2]; vol2 = instr->operators[3]; if ((instr->operators[10] & 0x01)) { calc_vol(&vol1, volume, main_vol); } calc_vol(&vol2, volume, main_vol); opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); } else { /* 4 OP voice */ int connection; vol1 = instr->operators[2]; vol2 = instr->operators[3]; vol3 = instr->operators[OFFS_4OP + 2]; vol4 = instr->operators[OFFS_4OP + 3]; /* * The connection method for 4 OP devc->voc is defined by the * rightmost bits at the offsets 10 and 10+OFFS_4OP */ connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); switch (connection) { case 0: calc_vol(&vol4, volume, main_vol); break; case 1: calc_vol(&vol2, volume, main_vol); calc_vol(&vol4, volume, main_vol); break; case 2: calc_vol(&vol1, volume, main_vol); calc_vol(&vol4, volume, main_vol); break; case 3: calc_vol(&vol1, volume, main_vol); calc_vol(&vol3, volume, main_vol); calc_vol(&vol4, volume, main_vol); break; default:; } opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], vol3); opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], vol4); } } static int opl3_start_note(int dev, int voice, int note, int volume) { u_char data, fpc; int block, fnum, freq, voice_mode; struct sbi_instrument *instr; struct physical_voice_info *map; if (voice < 0 || voice >= devc->nr_voice) return 0; map = &pv_map[devc->lv_map[voice]]; if (map->voice_mode == 0) return 0; if (note == 255) { /* Just change the volume */ set_voice_volume(voice, volume, devc->voc[voice].volume); return 0; } /* * Kill previous note before playing */ opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* Carrier volume to min */ opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* Modulator volume to */ if (map->voice_mode == 4) { opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], 0xff); opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], 0xff); } opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* Note off */ instr = devc->act_i[voice]; if (!instr) instr = &devc->i_map[0]; if (instr->channel < 0) { printf( "OPL3: Initializing voice %d with undefined instrument\n", voice); return 0; } if (map->voice_mode == 2 && instr->key == OPL3_PATCH) return 0; /* Cannot play */ voice_mode = map->voice_mode; if (voice_mode == 4) { int voice_shift; voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3; voice_shift += map->voice_num; if (instr->key != OPL3_PATCH) { /* Just 2 OP patch */ voice_mode = 2; devc->cmask &= ~(1 << voice_shift); } else devc->cmask |= (1 << voice_shift); opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); } /* * Set Sound Characteristics */ opl3_command(map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); opl3_command(map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); /* * Set Attack/Decay */ opl3_command(map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); opl3_command(map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); /* * Set Sustain/Release */ opl3_command(map->ioaddr,SUSTAIN_RELEASE + map->op[0], instr->operators[6]); opl3_command(map->ioaddr,SUSTAIN_RELEASE + map->op[1], instr->operators[7]); /* * Set Wave Select */ opl3_command(map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); opl3_command(map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); /* * Set Feedback/Connection */ fpc = instr->operators[10]; if (!(fpc & 0x30)) fpc |= 0x30; /* Ensure that at least one chn is enabled */ opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, fpc); /* * If the voice is a 4 OP one, initialize the operators 3 and 4 also */ if (voice_mode == 4) { /* * Set Sound Characteristics */ opl3_command(map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); opl3_command(map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); /* * Set Attack/Decay */ opl3_command(map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); opl3_command(map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); /* * Set Sustain/Release */ opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); /* * Set Wave Select */ opl3_command(map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); opl3_command(map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); /* * Set Feedback/Connection */ fpc = instr->operators[OFFS_4OP + 10]; if (!(fpc & 0x30)) fpc |= 0x30; /* Ensure that at least one chn is enabled */ opl3_command(map->ioaddr,FEEDBACK_CONNECTION + map->voice_num + 3, fpc); } devc->voc[voice].mode = voice_mode; set_voice_volume(voice, volume, devc->voc[voice].volume); freq = devc->voc[voice].orig_freq = note_to_freq(note) / 1000; /* * Since the pitch bender may have been set before playing the note, * we have to calculate the bending now. */ freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range); devc->voc[voice].current_freq = freq; freq_to_fnum(freq, &block, &fnum); /* * Play note */ 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); if (voice_mode == 4) opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); return 0; } static void freq_to_fnum(int freq, int *block, int *fnum) { int f, octave; /* * Converts the note frequency to block and fnum values for the FM * chip */ /* * First try to compute the block -value (octave) where the note * belongs */ f = freq; octave = 5; if (f == 0) octave = 0; else if (f < 261) { while (f < 261) { octave--; f <<= 1; } } else if (f > 493) { while (f > 493) { octave++; f >>= 1; } } if (octave > 7) octave = 7; *fnum = freq * (1 << (20 - octave)) / 49716; *block = octave; } static void opl3_command(int io_addr, u_int addr, u_int val) { int i; /* * The original 2-OP synth requires a quite long delay after writing * to a register. The OPL-3 survives with just two INBs */ outb(io_addr, (u_char) (addr & 0xff)); if (!devc->model != 2) DELAY(10); else for (i = 0; i < 2; i++) inb(io_addr); +#ifdef PC98 + outb(io_addr + 0x100, (u_char) (val & 0xff)); +#else outb(io_addr + 1, (u_char) (val & 0xff)); - +#endif if (devc->model != 2) DELAY(30); else for (i = 0; i < 2; i++) inb(io_addr); } static void opl3_reset(int dev) { int i; for (i = 0; i < 18; i++) devc->lv_map[i] = i; for (i = 0; i < devc->nr_voice; i++) { opl3_command(pv_map[devc->lv_map[i]].ioaddr, KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff); opl3_command(pv_map[devc->lv_map[i]].ioaddr, KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff); if (pv_map[devc->lv_map[i]].voice_mode == 4) { opl3_command(pv_map[devc->lv_map[i]].ioaddr, KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff); opl3_command(pv_map[devc->lv_map[i]].ioaddr, KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); } opl3_kill_note(dev, i, 0, 64); } if (devc->model == 2) { devc->v_alloc->max_voice = devc->nr_voice = 18; for (i = 0; i < 18; i++) pv_map[i].voice_mode = 2; } } static int opl3_open(int dev, int mode) { int i; if (devc->busy) return -(EBUSY); devc->busy = 1; devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; devc->v_alloc->timestamp = 0; for (i = 0; i < 18; i++) { devc->v_alloc->map[i] = 0; devc->v_alloc->alloc_times[i] = 0; } devc->cmask = 0x00; /* Just 2 OP mode */ if (devc->model == 2) opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); return 0; } static void opl3_close(int dev) { devc->busy = 0; devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; devc->fm_info.nr_drums = 0; devc->fm_info.perc_mode = 0; opl3_reset(dev); } static void opl3_hw_control(int dev, u_char *event) { } static int opl3_load_patch(int dev, int format, snd_rw_buf * addr, int offs, int count, int pmgr_flag) { struct sbi_instrument ins; if (count < sizeof(ins)) { printf("FM Error: Patch record too short\n"); return -(EINVAL); } if (uiomove(&((char *) &ins)[offs], sizeof(ins) - offs, addr)) { printf("sb: Bad copyin()!\n"); }; if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { printf("FM Error: Invalid instrument number %d\n", ins.channel); return -(EINVAL); } ins.key = format; return store_instr(ins.channel, &ins); } static void opl3_panning(int dev, int voice, int pressure) { } static void opl3_volume_method(int dev, int mode) { } #define SET_VIBRATO(cell) { \ tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ if (pressure > 110) \ tmp |= 0x40; /* Vibrato on */ \ opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);} static void opl3_aftertouch(int dev, int voice, int pressure) { int tmp; struct sbi_instrument *instr; struct physical_voice_info *map; if (voice < 0 || voice >= devc->nr_voice) return; map = &pv_map[devc->lv_map[voice]]; DEB(printf("Aftertouch %d\n", voice)); if (map->voice_mode == 0) return; /* * Adjust the amount of vibrato depending the pressure */ instr = devc->act_i[voice]; if (!instr) instr = &devc->i_map[0]; if (devc->voc[voice].mode == 4) { int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); switch (connection) { case 0: SET_VIBRATO(4); break; case 1: SET_VIBRATO(2); SET_VIBRATO(4); break; case 2: SET_VIBRATO(1); SET_VIBRATO(4); break; case 3: SET_VIBRATO(1); SET_VIBRATO(3); SET_VIBRATO(4); break; } /* * Not implemented yet */ } else { SET_VIBRATO(1); if ((instr->operators[10] & 0x01)) /* Additive synthesis */ SET_VIBRATO(2); } } #undef SET_VIBRATO static void bend_pitch(int dev, int voice, int value) { u_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); 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); /* KEYON|OCTAVE|MS bits of f-num */ 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; } } static int opl3_patchmgr(int dev, struct patmgr_info * rec) { return -(EINVAL); } 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 = info->bender_value; devc->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME]; } static struct synth_operations opl3_operations = { NULL, 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, opl3_open, opl3_close, opl3_ioctl, opl3_kill_note, opl3_start_note, opl3_set_instr, opl3_reset, opl3_hw_control, opl3_load_patch, opl3_aftertouch, opl3_controller, opl3_panning, opl3_volume_method, opl3_patchmgr, opl3_bender, opl3_alloc_voice, opl3_setup_voice }; void opl3_init(int ioaddr, sound_os_info * osp) { int i; if (num_synths >= MAX_SYNTH_DEV) { printf("OPL3 Error: Too many synthesizers\n"); return ; } if (devc == NULL) { printf("OPL3: Device control structure not initialized.\n"); return ; } bzero((char *) devc, sizeof(*devc)); devc->osp = osp; devc->nr_voice = 9; strcpy(devc->fm_info.name, "OPL2-"); 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[num_synths++] = &opl3_operations; devc->v_alloc = &opl3_operations.alloc; devc->chn_info = &opl3_operations.chn_info[0]; if (devc->model == 2) { if (devc->is_opl4) conf_printf2("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); else conf_printf2("Yamaha OPL3 FM", ioaddr, 0, -1, -1); devc->v_alloc->max_voice = devc->nr_voice = 18; devc->fm_info.nr_drums = 0; devc->fm_info.capabilities |= SYNTH_CAP_OPL3; strcpy(devc->fm_info.name, "Yamaha OPL-3"); 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 { conf_printf2("Yamaha OPL2 FM", ioaddr, 0, -1, -1); 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; }; for (i = 0; i < SBFM_MAXINSTR; i++) devc->i_map[i].channel = -1; return ; } #endif Index: head/sys/i386/isa/sound/sb16_dsp.c =================================================================== --- head/sys/i386/isa/sound/sb16_dsp.c (revision 55120) +++ head/sys/i386/isa/sound/sb16_dsp.c (revision 55121) @@ -1,541 +1,561 @@ /* * sound/sb16_dsp.c * * The low level driver for the SoundBlaster DSP chip. * * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de) * * based on SB-driver by (C) Hannu Savolainen * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ * */ #define DEB(x) #define DEB1(x) #include #include "sb.h" #include #include #if defined(CONFIG_SB16) && (NSB > 0) && defined(CONFIG_AUDIO) && defined(CONFIG_SBPRO) extern sound_os_info *sb_osp; extern int sbc_base; static int sb16_dsp_ok = 0; static int dsp_16bit = 0; static int dsp_stereo = 0; static int dsp_current_speed = 8000; static int dsp_busy = 0; static int dma16, dma8; static int trigger_bits = 0; static u_long dsp_count = 0; static int irq_mode = IMODE_NONE; static int my_dev = 0; static volatile int intr_active = 0; static int sb16_dsp_open(int dev, int mode); static void sb16_dsp_close(int dev); static void sb16_dsp_output_block(int dev, u_long buf, int count, int intrflag, int dma_restart); static void sb16_dsp_start_input(int dev, u_long buf, int count, int intrflag, int dma_restart); static int sb16_dsp_ioctl(int dev, u_int cmd, ioctl_arg arg, int local); static int sb16_dsp_prepare_for_input(int dev, int bsize, int bcount); static int sb16_dsp_prepare_for_output(int dev, int bsize, int bcount); static void sb16_dsp_reset(int dev); static void sb16_dsp_halt(int dev); static void sb16_dsp_trigger(int dev, int bits); static int dsp_set_speed(int); static int dsp_set_stereo(int); static void dsp_cleanup(void); static struct audio_operations sb16_dsp_operations = { "SoundBlaster 16", DMA_AUTOMODE, AFMT_U8 | AFMT_S16_LE, NULL, sb16_dsp_open, sb16_dsp_close, sb16_dsp_output_block, sb16_dsp_start_input, sb16_dsp_ioctl, sb16_dsp_prepare_for_input, sb16_dsp_prepare_for_output, sb16_dsp_reset, sb16_dsp_halt, NULL, NULL, NULL, NULL, sb16_dsp_trigger }; static int sb_dsp_command01(u_char val) { int i = 1 << 16; while (--i & (!inb(DSP_STATUS) & 0x80)); if (!i) printf("SB16 sb_dsp_command01 Timeout\n"); return sb_dsp_command(val); } static int dsp_set_speed(int mode) { DEB(printf("dsp_set_speed(%d)\n", mode)); if (mode) { RANGE (mode, 5000, 44100); dsp_current_speed = mode; } return mode; } static int dsp_set_stereo(int mode) { DEB(printf("dsp_set_stereo(%d)\n", mode)); dsp_stereo = mode; return mode; } static int dsp_set_bits(int arg) { DEB(printf("dsp_set_bits(%d)\n", arg)); if (arg) dsp_16bit = (arg == 16) ? 1 : 0 ; return dsp_16bit ? 16 : 8; } static int sb16_dsp_ioctl(int dev, u_int cmd, ioctl_arg arg, int local) { switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) return dsp_set_speed((int) arg); return *(int *) arg = dsp_set_speed((*(int *) arg)); case SOUND_PCM_READ_RATE: if (local) return dsp_current_speed; return *(int *) arg = dsp_current_speed; case SNDCTL_DSP_STEREO: if (local) return dsp_set_stereo((int) arg); return *(int *) arg = dsp_set_stereo((*(int *) arg)); case SOUND_PCM_WRITE_CHANNELS: if (local) return dsp_set_stereo((int) arg - 1) + 1; return *(int *) arg = dsp_set_stereo((*(int *) arg) - 1) + 1; case SOUND_PCM_READ_CHANNELS: if (local) return dsp_stereo + 1; return *(int *) arg = dsp_stereo + 1; case SNDCTL_DSP_SETFMT: if (local) return dsp_set_bits((int) arg); return *(int *) arg = dsp_set_bits((*(int *) arg)); case SOUND_PCM_READ_BITS: if (local) return dsp_16bit ? 16 : 8; return *(int *) arg = dsp_16bit ? 16 : 8; case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */ if ((*(int *) arg) > 1) return *(int *) arg = -(EINVAL); case FIOASYNC: if (local) return 1; return *(int *) arg = 1; case FIONBIO: if (local) return 1; return *(int *) arg = 1; default: return -(EINVAL); } return -(EINVAL); } static int sb16_dsp_open(int dev, int mode) { DEB(printf("sb16_dsp_open()\n")); if (!sb16_dsp_ok) { printf("SB16 Error: SoundBlaster board not installed\n"); return -(ENXIO); } if (intr_active) return -(EBUSY); sb_reset_dsp(); irq_mode = IMODE_NONE; dsp_busy = 1; trigger_bits = 0; return 0; } static void sb16_dsp_close(int dev) { u_long flags; DEB(printf("sb16_dsp_close()\n")); sb_dsp_command01(0xd9); sb_dsp_command01(0xd5); flags = splhigh(); audio_devs[dev]->dmachan1 = dma8; dsp_cleanup(); dsp_busy = 0; splx(flags); } static void sb16_dsp_output_block(int dev, u_long buf, int count, int intrflag, int dma_restart) { u_long flags, cnt; cnt = count; if (dsp_16bit) cnt >>= 1; cnt--; if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt==dsp_count) { irq_mode = IMODE_OUTPUT; intr_active = 1; return; /* Auto mode on. No need to react */ } flags = splhigh(); if (dma_restart) { sb16_dsp_halt(dev); DMAbuf_start_dma(dev, buf, count, 1); } sb_dsp_command(0x41); sb_dsp_command((u_char) ((dsp_current_speed >> 8) & 0xff)); sb_dsp_command((u_char) (dsp_current_speed & 0xff)); sb_dsp_command((u_char) (dsp_16bit ? 0xb6 : 0xc6)); dsp_count = cnt; sb_dsp_command((u_char) ((dsp_stereo ? 0x20 : 0) + (dsp_16bit ? 0x10 : 0))); sb_dsp_command((u_char) (cnt & 0xff)); sb_dsp_command((u_char) (cnt >> 8)); irq_mode = IMODE_OUTPUT; intr_active = 1; splx(flags); } static void sb16_dsp_start_input(int dev, u_long buf, int count, int intrflag, int dma_restart) { u_long flags, cnt; cnt = count; if (dsp_16bit) cnt >>= 1; cnt--; if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == dsp_count) { irq_mode = IMODE_INPUT; intr_active = 1; return; /* Auto mode on. No need to react */ } flags = splhigh(); if (dma_restart) { sb_reset_dsp(); DMAbuf_start_dma(dev, buf, count, 0); } sb_dsp_command(0x42); sb_dsp_command((u_char) ((dsp_current_speed >> 8) & 0xff)); sb_dsp_command((u_char) (dsp_current_speed & 0xff)); sb_dsp_command((u_char) (dsp_16bit ? 0xbe : 0xce)); dsp_count = cnt; sb_dsp_command((u_char) ((dsp_stereo ? 0x20 : 0) + (dsp_16bit ? 0x10 : 0))); sb_dsp_command01((u_char) (cnt & 0xff)); sb_dsp_command((u_char) (cnt >> 8)); irq_mode = IMODE_INPUT; intr_active = 1; splx(flags); } static int sb16_dsp_prepare_for_input(int dev, int bsize, int bcount) { int fudge; struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; audio_devs[my_dev]->dmachan2 = dsp_16bit ? dma16 : dma8; fudge = audio_devs[my_dev]->dmachan2 ; if (dmap->dma_chan != fudge ) { isa_dma_release( dmap->dma_chan); isa_dma_acquire(fudge); dmap->dma_chan = fudge; } dsp_count = 0; dsp_cleanup(); if (dsp_16bit) sb_dsp_command(0xd5); /* Halt DMA until trigger() is called */ else sb_dsp_command(0xd0); /* Halt DMA until trigger() is called */ trigger_bits = 0; return 0; } static int sb16_dsp_prepare_for_output(int dev, int bsize, int bcount) { int fudge = dsp_16bit ? dma16 : dma8; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; if (dmap->dma_chan != fudge ) { isa_dma_release( dmap->dma_chan); isa_dma_acquire(fudge); dmap->dma_chan = fudge; } audio_devs[my_dev]->dmachan1 = fudge; dsp_count = 0; dsp_cleanup(); if (dsp_16bit) sb_dsp_command(0xd5); /* Halt DMA until trigger() is called */ else sb_dsp_command(0xd0); /* Halt DMA until trigger() is called */ trigger_bits = 0; return 0; } static void sb16_dsp_trigger(int dev, int bits) { if (bits != 0) bits = 1; if (bits == trigger_bits) /* No change */ return; trigger_bits = bits; if (!bits) sb_dsp_command(0xd0); /* Halt DMA */ else if (bits & irq_mode) { if (dsp_16bit) sb_dsp_command(0xd6); /* Continue 16bit DMA */ else sb_dsp_command(0xd4); /* Continue 8bit DMA */ } } static void dsp_cleanup(void) { irq_mode = IMODE_NONE; intr_active = 0; } static void sb16_dsp_reset(int dev) { u_long flags; flags = splhigh(); sb_reset_dsp(); dsp_cleanup(); splx(flags); } static void sb16_dsp_halt(int dev) { if (dsp_16bit) { sb_dsp_command01(0xd9); sb_dsp_command01(0xd5); } else { sb_dsp_command01(0xda); sb_dsp_command01(0xd0); } } static void set_irq_hw(int level) { int ival; switch (level) { +#ifdef PC98 case 5: + ival = 8; + break; + case 3: + ival = 1; + break; + case 10: ival = 2; + break; +#else + case 5: + ival = 2; break; case 7: ival = 4; break; case 9: ival = 1; break; case 10: ival = 8; break; +#endif default: printf("SB16_IRQ_LEVEL %d does not exist\n", level); return; } sb_setmixer(IRQ_NR, ival); } void sb16_dsp_init(struct address_info * hw_config) { if (sbc_major < 4) return; /* Not a SB16 */ snprintf(sb16_dsp_operations.name, sizeof(sb16_dsp_operations.name), "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); conf_printf(sb16_dsp_operations.name, hw_config); if (num_audiodevs < MAX_AUDIO_DEV) { audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations; audio_devs[my_dev]->dmachan1 = dma8; audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; } else printf("SB: Too many DSP devices available\n"); sb16_dsp_ok = 1; return; } int sb16_dsp_detect(struct address_info * hw_config) { struct address_info *sb_config; if (sb16_dsp_ok) return 1; /* Can't drive two cards */ if (!(sb_config = sound_getconf(SNDCARD_SB))) { printf("SB16 Error: Plain SB not configured\n"); return 0; } /* * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0; */ if (!sb_reset_dsp()) return 0; if (sbc_major < 4) /* Set by the plain SB driver */ return 0; /* Not a SB16 */ +#ifdef PC98 + hw_config->dma = sb_config->dma; +#else if (hw_config->dma < 4) if (hw_config->dma != sb_config->dma) { printf("SB16 Error: Invalid DMA channel %d/%d\n", sb_config->dma, hw_config->dma); return 0; } +#endif dma16 = hw_config->dma; dma8 = sb_config->dma; /* hw_config->irq = 0; sb_config->irq; hw_config->io_base = sb_config->io_base; */ set_irq_hw(sb_config->irq); +#ifdef PC98 + sb_setmixer (DMA_NR, hw_config->dma == 0 ? 1 : 2); +#else sb_setmixer(DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma)); +#endif DEB(printf("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma)); /* * dsp_showmessage(0xe3,99); */ sb16_dsp_ok = 1; return 1; } void sb16_dsp_interrupt(int unused) { int data; data = inb(DSP_DATA_AVL16); /* Interrupt acknowledge */ if (intr_active) switch (irq_mode) { case IMODE_OUTPUT: DMAbuf_outputintr(my_dev, 1); break; case IMODE_INPUT: DMAbuf_inputintr(my_dev); break; default: printf("SoundBlaster: Unexpected interrupt\n"); } } #endif Index: head/sys/i386/isa/sound/sb16_midi.c =================================================================== --- head/sys/i386/isa/sound/sb16_midi.c (revision 55120) +++ head/sys/i386/isa/sound/sb16_midi.c (revision 55121) @@ -1,299 +1,311 @@ /* * sound/sb16_midi.c * * The low level driver for the MPU-401 UART emulation of the SB16. * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD$ + * */ #include #include #if defined(CONFIG_SB) && defined(CONFIG_SB16) && defined(CONFIG_MIDI) #include "sb.h" +#ifdef PC98 +#define DATAPORT (sb16midi_base) +#define COMDPORT (sb16midi_base+0x100) +#define STATPORT (sb16midi_base+0x100) +#else #define DATAPORT (sb16midi_base) #define COMDPORT (sb16midi_base+1) #define STATPORT (sb16midi_base+1) +#endif extern sound_os_info *sb_osp; #define sb16midi_status() inb( STATPORT) #define input_avail() (!(sb16midi_status()&INPUT_AVAIL)) #define output_ready() (!(sb16midi_status()&OUTPUT_READY)) #define sb16midi_cmd(cmd) outb( COMDPORT, cmd) #define sb16midi_read() inb( DATAPORT) #define sb16midi_write(byte) outb( DATAPORT, byte) #define OUTPUT_READY 0x40 #define INPUT_AVAIL 0x80 #define MPU_ACK 0xFE #define MPU_RESET 0xFF #define UART_MODE_ON 0x3F static int sb16midi_opened = 0; +#ifdef PC98 +static int sb16midi_base = 0x80d2; +#else static int sb16midi_base = 0x330; +#endif static int sb16midi_detected = 0; static int my_dev; extern int sbc_base; static int reset_sb16midi(void); static void (*midi_input_intr) (int dev, u_char data); static volatile u_char input_byte; static void sb16midi_input_loop(void) { while (input_avail()) { u_char c = sb16midi_read(); if (c == MPU_ACK) input_byte = c; else if (sb16midi_opened & OPEN_READ && midi_input_intr) midi_input_intr(my_dev, c); } } void sb16midiintr(int unit) { if (input_avail()) sb16midi_input_loop(); } static int sb16midi_open(int dev, int mode, void (*input) (int dev, u_char data), void (*output) (int dev) ) { if (sb16midi_opened) { return -(EBUSY); } sb16midi_input_loop(); midi_input_intr = input; sb16midi_opened = mode; return 0; } static void sb16midi_close(int dev) { sb16midi_opened = 0; } static int sb16midi_out(int dev, u_char midi_byte) { int timeout; u_long flags; /* * Test for input since pending input seems to block the output. */ flags = splhigh(); if (input_avail()) sb16midi_input_loop(); splx(flags); /* * Sometimes it takes about 13000 loops before the output becomes * ready (After reset). Normally it takes just about 10 loops. */ for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* Wait */ if (!output_ready()) { printf("MPU-401: Timeout\n"); return 0; } sb16midi_write(midi_byte); return 1; } static int sb16midi_start_read(int dev) { return 0; } static int sb16midi_end_read(int dev) { return 0; } static int sb16midi_ioctl(int dev, u_int cmd, ioctl_arg arg) { return -(EINVAL); } static void sb16midi_kick(int dev) { } static int sb16midi_buffer_status(int dev) { return 0; /* No data in buffers */ } #define MIDI_SYNTH_NAME "SoundBlaster 16 Midi" #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT #include static struct midi_operations sb16midi_operations = { {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI}, &std_midi_synth, {0}, sb16midi_open, sb16midi_close, sb16midi_ioctl, sb16midi_out, sb16midi_start_read, sb16midi_end_read, sb16midi_kick, NULL, sb16midi_buffer_status, NULL }; void attach_sb16midi(struct address_info * hw_config) { int ok, timeout; u_long flags; sb16midi_base = hw_config->io_base; if (!sb16midi_detected) return; flags = splhigh(); for (timeout = 30000; timeout < 0 && !output_ready(); timeout--); /* Wait */ input_byte = 0; sb16midi_cmd(UART_MODE_ON); ok = 0; for (timeout = 50000; timeout > 0 && !ok; timeout--) if (input_byte == MPU_ACK) ok = 1; else if (input_avail()) if (sb16midi_read() == MPU_ACK) ok = 1; splx(flags); if (num_midis >= MAX_MIDI_DEV) { printf("Sound: Too many midi devices detected\n"); return; } conf_printf("SoundBlaster MPU-401", hw_config); std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &sb16midi_operations; return; } static int reset_sb16midi(void) { int ok, timeout, n; /* * Send the RESET command. Try again if no success at the first time. */ if (inb(STATPORT) == 0xff) return 0; ok = 0; /* flags = splhigh(); */ for (n = 0; n < 2 && !ok; n++) { for (timeout = 30000; timeout < 0 && !output_ready(); timeout--); /* Wait */ input_byte = 0; sb16midi_cmd(MPU_RESET); /* Send MPU-401 RESET Command */ /* * Wait at least 25 msec. This method is not accurate so * let's make the loop bit longer. Cannot sleep since this is * called during boot. */ for (timeout = 50000; timeout > 0 && !ok; timeout--) if (input_byte == MPU_ACK) /* Interrupt */ ok = 1; else if (input_avail()) if (sb16midi_read() == MPU_ACK) ok = 1; } sb16midi_opened = 0; if (ok) sb16midi_input_loop(); /* Flush input before enabling * interrupts */ /* splx(flags); */ return ok; } int probe_sb16midi(struct address_info * hw_config) { int ok = 0; struct address_info *sb_config; if (sbc_major < 4) return 0; /* Not a SB16 */ if (!(sb_config = sound_getconf(SNDCARD_SB))) { printf("SB16 Error: Plain SB not configured\n"); return 0; } sb16midi_base = hw_config->io_base; ok = reset_sb16midi(); sb16midi_detected = ok; return ok; } #endif Index: head/sys/i386/isa/sound/sb_dsp.c =================================================================== --- head/sys/i386/isa/sound/sb_dsp.c (revision 55120) +++ head/sys/i386/isa/sound/sb_dsp.c (revision 55121) @@ -1,1132 +1,1155 @@ /* * sound/sb_dsp.c * * The low level driver for the SoundBlaster DSP chip (SB1.0 to 2.1, SB Pro). * * Copyright by Hannu Savolainen 1994 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Modified: Hunyue Yau Jan 6 1994 Added code to support Sound Galaxy NX * Pro * * JRA Gibson April 1995 Code added for MV ProSonic/Jazz 16 in 16 bit mode + * + * $FreeBSD$ */ #include #if (NSB > 0) #ifdef SM_WAVE #define JAZZ16 #endif #include #include #include #undef SB_TEST_IRQ /* * XXX note -- only one sb-like device is supported until these * variables are put in a struct sb_unit[] array */ int sbc_base = 0; static int sbc_irq = 0; static int open_mode = 0; /* Read, write or both */ int Jazz16_detected = 0; int sb_no_recording = 0; static int dsp_count = 0; static int trigger_bits; /* * The DSP channel can be used either for input or output. Variable * 'sb_irq_mode' will be set when the program calls read or write first time * after open. Current version doesn't support mode changes without closing * and reopening the device. Support for this feature may be implemented in a * future version of this driver. */ int sb_dsp_ok = 0; /* Set to 1 after successful init */ static int midi_disabled = 0; int sb_dsp_highspeed = 0; int sbc_major = 1, sbc_minor = 0; /* DSP version */ static int dsp_stereo = 0; static int dsp_current_speed = DSP_DEFAULT_SPEED; static int sb16 = 0; int sb_midi_mode = NORMAL_MIDI; int sb_midi_busy = 0; /* 1 if the process has output to * * * MIDI */ int sb_dsp_busy = 0; volatile int sb_irq_mode = IMODE_NONE; /* or IMODE_INPUT or IMODE_OUTPUT */ static int dma8 = 1; #ifdef JAZZ16 /* 16 bit support for JAZZ16 */ static int dsp_16bit = 0; static int dma16 = 5; static int dsp_set_bits(int arg); static int initialize_ProSonic16(void); #endif /* end of 16 bit support for JAZZ16 */ int sb_duplex_midi = 0; static int my_dev = 0; volatile int sb_intr_active = 0; static int dsp_speed(int); static int dsp_set_stereo(int mode); static void sb_dsp_reset(int dev); sound_os_info *sb_osp = NULL; #if defined(CONFIG_MIDI) || defined(CONFIG_AUDIO) static void dsp_speaker(char state); /* * Common code for the midi and pcm functions */ int sb_dsp_command(u_char val) { int i; u_long limit; limit = get_time() + hz / 10; /* The timeout is 0.1 secods */ /* * Note! the i<500000 is an emergency exit. The sb_dsp_command() is * sometimes called while interrupts are disabled. This means that * the timer is disabled also. However the timeout situation is a * abnormal condition. Normally the DSP should be ready to accept * commands after just couple of loops. */ for (i = 0; i < 500000 && get_time() < limit; i++) { if ((inb(DSP_STATUS) & 0x80) == 0) { outb(DSP_COMMAND, val); return 1; } } printf("SoundBlaster: DSP Command(0x%02x) timeout. IRQ conflict ?\n", val); return 0; } void sbintr(int irq) { int status; #ifdef CONFIG_SBPRO if (sb16) { u_char src = sb_getmixer(IRQ_STAT); /* Interrupt source register */ #ifdef CONFIG_SB16 if (src & 3) sb16_dsp_interrupt(irq); #ifdef CONFIG_MIDI if (src & 4) sb16midiintr(irq); /* SB MPU401 interrupt */ #endif /* CONFIG_MIDI */ #endif /* CONFIG_SB16 */ if (!(src & 1)) return; /* Not a DSP interupt */ } #endif /* CONFIG_SBPRO */ status = inb(DSP_DATA_AVAIL); /* Clear interrupt */ if (sb_intr_active) switch (sb_irq_mode) { case IMODE_OUTPUT: sb_intr_active = 0; DMAbuf_outputintr(my_dev, 1); break; case IMODE_INPUT: sb_intr_active = 0; DMAbuf_inputintr(my_dev); /* * A complete buffer has been input. Let's start new one */ break; case IMODE_INIT: sb_intr_active = 0; break; case IMODE_MIDI: #ifdef CONFIG_MIDI sb_midi_interrupt(irq); #endif break; default: printf("SoundBlaster: Unexpected interrupt\n"); } } int sb_reset_dsp(void) { int loopc; outb(DSP_RESET, 1); DELAY(10); outb(DSP_RESET, 0); DELAY(30); for (loopc = 0; loopc < 100 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++) DELAY(10); if (inb(DSP_READ) != 0xAA) { printf("sb_reset_dsp failed\n"); return 0; /* Sorry */ } return 1; } #endif #ifdef CONFIG_AUDIO static void dsp_speaker(char state) { if (state) sb_dsp_command(DSP_CMD_SPKON); else sb_dsp_command(DSP_CMD_SPKOFF); } static int dsp_speed(int speed) { u_char tconst; u_long flags; int max_speed = 44100; if (speed < 4000) speed = 4000; /* * Older SB models don't support higher speeds than 22050. */ if (sbc_major < 2 || (sbc_major == 2 && sbc_minor == 0)) max_speed = 22050; /* * SB models earlier than SB Pro have low limit for the input speed. */ if (open_mode != OPEN_WRITE) { /* Recording is possible */ if (sbc_major < 3) { /* Limited input speed with these cards */ if (sbc_major == 2 && sbc_minor > 0) max_speed = 15000; else max_speed = 13000; } } if (speed > max_speed) speed = max_speed; /* Invalid speed */ /* * Logitech SoundMan Games and Jazz16 cards can support 44.1kHz * stereo */ #if !defined (SM_GAMES) /* * Max. stereo speed is 22050 */ if (dsp_stereo && speed > 22050 && Jazz16_detected == 0) speed = 22050; #endif if ((speed > 22050) && sb_midi_busy) { printf("SB Warning: High speed DSP not possible simultaneously with MIDI output\n"); speed = 22050; } if (dsp_stereo) speed *= 2; /* * Now the speed should be valid */ if (speed > 22050) { /* High speed mode */ int tmp; tconst = (u_char) ((65536 - ((256000000 + speed / 2) / speed)) >> 8); sb_dsp_highspeed = 1; flags = splhigh(); if (sb_dsp_command(DSP_CMD_TCONST)) sb_dsp_command(tconst); splx(flags); tmp = 65536 - (tconst << 8); speed = (256000000 + tmp / 2) / tmp; } else { int tmp; sb_dsp_highspeed = 0; tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; flags = splhigh(); if (sb_dsp_command(DSP_CMD_TCONST)) /* Set time constant */ sb_dsp_command(tconst); splx(flags); tmp = 256 - tconst; speed = (1000000 + tmp / 2) / tmp; } if (dsp_stereo) speed /= 2; dsp_current_speed = speed; return speed; } static int dsp_set_stereo(int mode) { dsp_stereo = 0; #ifndef CONFIG_SBPRO return 0; #else if (sbc_major < 3 || sb16) return 0; /* Sorry no stereo */ if (mode && sb_midi_busy) { printf("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n"); return 0; } dsp_stereo = !!mode; return dsp_stereo; #endif } static void sb_dsp_output_block(int dev, u_long buf, int count, int intrflag, int restart_dma) { u_long flags; if (!sb_irq_mode) dsp_speaker(ON); DMAbuf_start_dma(dev, buf, count, 1); sb_irq_mode = 0; if (audio_devs[dev]->dmachan1 > 3) count >>= 1; count--; dsp_count = count; sb_irq_mode = IMODE_OUTPUT; if (sb_dsp_highspeed) { flags = splhigh(); if (sb_dsp_command(DSP_CMD_HSSIZE)) { /* High speed size */ sb_dsp_command((u_char) (dsp_count & 0xff)); sb_dsp_command((u_char) ((dsp_count >> 8) & 0xff)); sb_dsp_command(DSP_CMD_HSDAC); /* High speed 8 bit DAC */ } else printf("SB Error: Unable to start (high speed) DAC\n"); splx(flags); } else { flags = splhigh(); if (sb_dsp_command(DSP_CMD_DAC8)) { /* 8-bit DAC (DMA) */ sb_dsp_command((u_char) (dsp_count & 0xff)); sb_dsp_command((u_char) ((dsp_count >> 8) & 0xff)); } else printf("SB Error: Unable to start DAC\n"); splx(flags); } sb_intr_active = 1; } static void sb_dsp_start_input(int dev, u_long buf, int count, int intrflag, int restart_dma) { u_long flags; if (sb_no_recording) { printf("SB Error: This device doesn't support recording\n"); return; } /* * Start a DMA input to the buffer pointed by dmaqtail */ if (!sb_irq_mode) dsp_speaker(OFF); DMAbuf_start_dma(dev, buf, count, 0); sb_irq_mode = 0; if (audio_devs[dev]->dmachan1 > 3) count >>= 1; count--; dsp_count = count; sb_irq_mode = IMODE_INPUT; if (sb_dsp_highspeed) { flags = splhigh(); if (sb_dsp_command(DSP_CMD_HSSIZE)) { /* High speed size */ sb_dsp_command((u_char) (dsp_count & 0xff)); sb_dsp_command((u_char) ((dsp_count >> 8) & 0xff)); sb_dsp_command(DSP_CMD_HSADC); /* High speed 8 bit ADC */ } else printf("SB Error: Unable to start (high speed) ADC\n"); splx(flags); } else { flags = splhigh(); if (sb_dsp_command(DSP_CMD_ADC8)) { /* 8-bit ADC (DMA) */ sb_dsp_command((u_char) (dsp_count & 0xff)); sb_dsp_command((u_char) ((dsp_count >> 8) & 0xff)); } else printf("SB Error: Unable to start ADC\n"); splx(flags); } sb_intr_active = 1; } static void sb_dsp_trigger(int dev, int bits) { if (bits == trigger_bits) return; if (!bits) sb_dsp_command(0xd0); /* Halt DMA */ else if (bits & sb_irq_mode) sb_dsp_command(0xd4); /* Continue DMA */ trigger_bits = bits; } static void dsp_cleanup(void) { sb_intr_active = 0; } static int sb_dsp_prepare_for_input(int dev, int bsize, int bcount) { int fudge = -1; struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; dsp_cleanup(); dsp_speaker(OFF); if (sbc_major == 3) { /* SB Pro */ #ifdef JAZZ16 /* * Select correct dma channel for 16/8 bit acccess */ audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8; if (dsp_stereo) sb_dsp_command(dsp_16bit ? 0xac : 0xa8); else sb_dsp_command(dsp_16bit ? 0xa4 : 0xa0); #else /* * 8 bit only cards use this */ if (dsp_stereo) sb_dsp_command(0xa8); else sb_dsp_command(0xa0); #endif dsp_speed(dsp_current_speed); /* Speed must be recalculated * if #channels * changes */ } fudge = audio_devs[my_dev]->dmachan1; if (dmap->dma_chan != fudge ) { isa_dma_release( dmap->dma_chan); isa_dma_acquire(fudge); dmap->dma_chan = fudge; } trigger_bits = 0; sb_dsp_command(DSP_CMD_DMAHALT); /* Halt DMA */ return 0; } static int sb_dsp_prepare_for_output(int dev, int bsize, int bcount) { int fudge; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; dsp_cleanup(); dsp_speaker(ON); #ifdef CONFIG_SBPRO if (sbc_major == 3) { /* SB Pro */ #ifdef JAZZ16 /* * 16 bit specific instructions */ audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8; if (Jazz16_detected != 2) /* SM Wave */ sb_mixer_set_stereo(dsp_stereo); if (dsp_stereo) sb_dsp_command(dsp_16bit ? 0xac : 0xa8); else sb_dsp_command(dsp_16bit ? 0xa4 : 0xa0); #else sb_mixer_set_stereo(dsp_stereo); #endif dsp_speed(dsp_current_speed); /* Speed must be recalculated * if #channels * changes */ } #endif fudge = audio_devs[my_dev]->dmachan1; if (dmap->dma_chan != fudge ) { isa_dma_release( dmap->dma_chan); isa_dma_acquire(fudge); dmap->dma_chan = fudge; } trigger_bits = 0; sb_dsp_command(DSP_CMD_DMAHALT); /* Halt DMA */ return 0; } static void sb_dsp_halt_xfer(int dev) { } static int sb_dsp_open(int dev, int mode) { if (!sb_dsp_ok) { printf("SB Error: SoundBlaster board not installed\n"); return -(ENXIO); } if (sb_no_recording && mode & OPEN_READ) { printf("SB Warning: Recording not supported by this device\n"); } if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI)) { printf("SB: PCM not possible during MIDI input\n"); return -(EBUSY); } /* * Allocate 8 bit dma */ #ifdef JAZZ16 audio_devs[my_dev]->dmachan1 = dma8; /* * Allocate 16 bit dma */ if (Jazz16_detected != 0) if (dma16 != dma8) { if (0) { return -(EBUSY); } } #endif sb_irq_mode = IMODE_NONE; sb_dsp_busy = 1; open_mode = mode; return 0; } static void sb_dsp_close(int dev) { #ifdef JAZZ16 /* * Release 16 bit dma channel */ if (Jazz16_detected) { audio_devs[my_dev]->dmachan1 = dma8; } #endif dsp_cleanup(); dsp_speaker(OFF); sb_dsp_busy = 0; sb_dsp_highspeed = 0; open_mode = 0; } #ifdef JAZZ16 /* * Function dsp_set_bits() only required for 16 bit cards */ static int dsp_set_bits(int arg) { if (arg) if (Jazz16_detected == 0) dsp_16bit = 0; else switch (arg) { case 8: dsp_16bit = 0; break; case 16: dsp_16bit = 1; break; default: dsp_16bit = 0; } return dsp_16bit ? 16 : 8; } #endif /* ifdef JAZZ16 */ static int sb_dsp_ioctl(int dev, u_int cmd, ioctl_arg arg, int local) { switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) return dsp_speed((int) arg); return *(int *) arg = dsp_speed((*(int *) arg)); break; case SOUND_PCM_READ_RATE: if (local) return dsp_current_speed; return *(int *) arg = dsp_current_speed; break; case SOUND_PCM_WRITE_CHANNELS: if (local) return dsp_set_stereo((int) arg - 1) + 1; return *(int *) arg = dsp_set_stereo((*(int *) arg) - 1) + 1; break; case SOUND_PCM_READ_CHANNELS: if (local) return dsp_stereo + 1; return *(int *) arg = dsp_stereo + 1; break; case SNDCTL_DSP_STEREO: if (local) return dsp_set_stereo((int) arg); return *(int *) arg = dsp_set_stereo((*(int *) arg)); break; #ifdef JAZZ16 /* * Word size specific cases here. * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS */ case SNDCTL_DSP_SETFMT: if (local) return dsp_set_bits((int) arg); return *(int *) arg = dsp_set_bits((*(int *) arg)); break; case SOUND_PCM_READ_BITS: if (local) return dsp_16bit ? 16 : 8; return *(int *) arg = dsp_16bit ? 16 : 8; break; #else case SOUND_PCM_WRITE_BITS: case SOUND_PCM_READ_BITS: if (local) return 8; return *(int *) (int) arg = 8; /* Only 8 bits/sample supported */ break; #endif /* ifdef JAZZ16 */ case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: return -(EINVAL); break; default:; } return -(EINVAL); } static void sb_dsp_reset(int dev) { u_long flags; flags = splhigh(); sb_reset_dsp(); dsp_speed(dsp_current_speed); dsp_cleanup(); splx(flags); } #endif #ifdef JAZZ16 /* * Initialization of a Media Vision ProSonic 16 Soundcard. The function * initializes a ProSonic 16 like PROS.EXE does for DOS. It sets the base * address, the DMA-channels, interrupts and enables the joystickport. * * Also used by Jazz 16 (same card, different name) * * written 1994 by Rainer Vranken E-Mail: * rvranken@polaris.informatik.uni-essen.de */ u_int get_sb_byte(void) { int i; for (i = 1000; i; i--) if (inb(DSP_DATA_AVAIL) & 0x80) { return inb(DSP_READ); } return 0xffff; } #ifdef SM_WAVE /* * Logitech Soundman Wave detection and initialization by Hannu Savolainen. * * There is a microcontroller (8031) in the SM Wave card for MIDI emulation. * it's located at address MPU_BASE+4. MPU_BASE+7 is a SM Wave specific * control register for MC reset, SCSI, OPL4 and DSP (future expansion) * address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16 based * soundcard. */ static void smw_putmem(int base, int addr, u_char val) { u_long flags; flags = splhigh(); outb(base + 1, addr & 0xff); /* Low address bits */ outb(base + 2, addr >> 8); /* High address bits */ outb(base, val); /* Data */ splx(flags); } static u_char smw_getmem(int base, int addr) { u_long flags; u_char val; flags = splhigh(); outb(base + 1, addr & 0xff); /* Low address bits */ outb(base + 2, addr >> 8); /* High address bits */ val = inb(base); /* Data */ splx(flags); return val; } #ifdef SMW_MIDI0001_INCLUDED #include #else u_char *smw_ucode = NULL; int smw_ucodeLen = 0; #endif static int initialize_smw(int mpu_base) { int mp_base = mpu_base + 4; /* Microcontroller base */ int i; u_char control; /* * Reset the microcontroller so that the RAM can be accessed */ control = inb(mpu_base + 7); outb(mpu_base + 7, control | 3); /* Set last two bits to 1 (?) */ outb(mpu_base + 7, (control & 0xfe) | 2); /* xxxxxxx0 resets the mc */ DELAY(3000); /* Wait at least 1ms */ outb(mpu_base + 7, control & 0xfc); /* xxxxxx00 enables RAM */ /* * Detect microcontroller by probing the 8k RAM area */ smw_putmem(mp_base, 0, 0x00); smw_putmem(mp_base, 1, 0xff); DELAY(10); if (smw_getmem(mp_base, 0) != 0x00 || smw_getmem(mp_base, 1) != 0xff) { printf("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", smw_getmem(mp_base, 0), smw_getmem(mp_base, 1)); return 0; /* No RAM */ } /* * There is RAM so assume it's really a SM Wave */ if (smw_ucodeLen > 0) { if (smw_ucodeLen != 8192) { printf("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); return 1; } /* * Download microcode */ for (i = 0; i < 8192; i++) smw_putmem(mp_base, i, smw_ucode[i]); /* * Verify microcode */ for (i = 0; i < 8192; i++) if (smw_getmem(mp_base, i) != smw_ucode[i]) { printf("SM Wave: Microcode verification failed\n"); return 0; } } control = 0; #ifdef SMW_SCSI_IRQ /* * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt * is disabled by default. * * Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10. */ { static u_char scsi_irq_bits[] = {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; } #endif #ifdef SMW_OPL4_ENABLE /* * Make the OPL4 chip visible on the PC bus at 0x380. * * There is no need to enable this feature since VoxWare doesn't support * OPL4 yet. Also there is no RAM in SM Wave so enabling OPL4 is * pretty useless. */ control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ /* control |= 0x20; Uncomment this if you want to use IRQ7 */ #endif outb(mpu_base + 7, control | 0x03); /* xxxxxx11 restarts */ return 1; } #endif static int initialize_ProSonic16(void) { int x; static u_char int_translat[16] = {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] = {0, 1, 0, 2, 0, 3, 0, 4}; struct address_info *mpu_config; int mpu_base, mpu_irq; if ((mpu_config = sound_getconf(SNDCARD_MPU401))) { mpu_base = mpu_config->io_base; mpu_irq = mpu_config->irq; } else { mpu_base = mpu_irq = 0; } outb(0x201, 0xAF); /* ProSonic/Jazz16 wakeup */ DELAY(15000); /* wait at least 10 milliseconds */ outb(0x201, 0x50); outb(0x201, (sbc_base & 0x70) | ((mpu_base & 0x30) >> 4)); if (sb_reset_dsp()) { /* OK. We have at least a SB */ /* Check the version number of ProSonic (I guess) */ if (!sb_dsp_command(0xFA)) return 1; if (get_sb_byte() != 0x12) return 1; if (sb_dsp_command(0xFB) && /* set DMA-channels and Interrupts */ sb_dsp_command((dma_translat[JAZZ_DMA16]<<4)|dma_translat[dma8]) && sb_dsp_command((int_translat[mpu_irq]<<4)|int_translat[sbc_irq])) { Jazz16_detected = 1; if (mpu_base == 0) printf("Jazz16: No MPU401 devices configured - MIDI port not initialized\n"); #ifdef SM_WAVE if (mpu_base != 0) if (initialize_smw(mpu_base)) Jazz16_detected = 2; #endif sb_dsp_disable_midi(); } return 1; /* There was at least a SB */ } return 0; /* No SB or ProSonic16 detected */ } #endif /* ifdef JAZZ16 */ int sb_dsp_detect(struct address_info * hw_config) { sbc_base = hw_config->io_base; sbc_irq = hw_config->irq; sb_osp = hw_config->osp; if (sb_dsp_ok) return 0; /* Already initialized */ dma8 = hw_config->dma; #ifdef JAZZ16 dma16 = JAZZ_DMA16; if (!initialize_ProSonic16()) return 0; #else if (!sb_reset_dsp()) return 0; #endif +#ifdef PC98 + switch (sbc_irq) { + case 3: + sb_setmixer (IRQ_NR, 1); + break; + case 5: + sb_setmixer (IRQ_NR, 8); + break; + case 10: + sb_setmixer (IRQ_NR, 2); + break; + } + switch (hw_config->dma) { + case 0: + sb_setmixer (DMA_NR, 1); + break; + case 3: + sb_setmixer (DMA_NR, 2); + break; + } +#endif return 1; /* Detected */ } #ifdef CONFIG_AUDIO static struct audio_operations sb_dsp_operations = { "SoundBlaster", NOTHING_SPECIAL, AFMT_U8, /* Just 8 bits. Poor old SB */ NULL, sb_dsp_open, sb_dsp_close, sb_dsp_output_block, sb_dsp_start_input, sb_dsp_ioctl, sb_dsp_prepare_for_input, sb_dsp_prepare_for_output, sb_dsp_reset, sb_dsp_halt_xfer, NULL, /* local_qlen */ NULL, /* copy_from_user */ NULL, NULL, sb_dsp_trigger }; #endif void sb_dsp_init(struct address_info * hw_config) { int i; char *fmt = NULL ; #ifdef CONFIG_SBPRO int mixer_type = 0; #endif sb_osp = hw_config->osp; sbc_major = sbc_minor = 0; sb_dsp_command(DSP_CMD_GETVER); /* Get version */ for (i = 10000; i; i--) { /* perhaps wait longer on a fast machine ? */ if (inb(DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */ if (sbc_major == 0) sbc_major = inb(DSP_READ); else { sbc_minor = inb(DSP_READ); break; } } else DELAY(20); } if (sbc_major == 0) { printf("\n\nFailed to get SB version (%x) - possible I/O conflict\n\n", inb(DSP_DATA_AVAIL)); sbc_major = 1; } if (sbc_major == 2 || sbc_major == 3) sb_duplex_midi = 1; if (sbc_major == 4) sb16 = 1; if (sbc_major == 3 && sbc_minor == 1) { int ess_major = 0, ess_minor = 0; /* * Try to detect ESS chips. */ sb_dsp_command(DSP_CMD_GETID); /* Return identification bytes. */ for (i = 1000; i; i--) { if (inb(DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */ if (ess_major == 0) ess_major = inb(DSP_READ); else { ess_minor = inb(DSP_READ); break; } } } if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) printf("Hmm... Could this be an ESS488 based card (rev %d)\n", ess_minor & 0x0f); else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) printf("Hmm... Could this be an ESS688 based card (rev %d)\n", ess_minor & 0x0f); } if (snd_set_irq_handler(sbc_irq, sbintr, sb_osp) < 0) printf("sb_dsp: Can't allocate IRQ\n");; #ifdef CONFIG_SBPRO if (sbc_major >= 3) mixer_type = sb_mixer_init(sbc_major); #else if (sbc_major >= 3) printf("\nNOTE! SB Pro support required with your soundcard!\n"); #endif #ifdef CONFIG_AUDIO if (sbc_major >= 3) { if (Jazz16_detected) { if (Jazz16_detected == 2) fmt = "SoundMan Wave %d.%d"; else fmt = "MV Jazz16 %d.%d"; sb_dsp_operations.format_mask |= AFMT_S16_LE; /* 16 bits */ } else #ifdef __SGNXPRO__ if (mixer_type == 2) fmt = "Sound Galaxy NX Pro %d.%d" ; else #endif /* __SGNXPRO__ */ if (sbc_major == 4) fmt = "SoundBlaster 16 %d.%d"; else fmt = "SoundBlaster Pro %d.%d"; } else { fmt = "SoundBlaster %d.%d" ; } snprintf(sb_dsp_operations.name, sizeof(sb_dsp_operations.name), fmt, sbc_major, sbc_minor); conf_printf(sb_dsp_operations.name, hw_config); #if defined(CONFIG_SB16) && defined(CONFIG_SBPRO) if (!sb16) { /* There is a better driver for SB16 */ #endif /* CONFIG_SB16 && CONFIG_SBPRO */ if (num_audiodevs < MAX_AUDIO_DEV) { audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations; audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; dma8 = audio_devs[my_dev]->dmachan1 = hw_config->dma; audio_devs[my_dev]->dmachan2 = -1; #ifdef JAZZ16 /* * Allocate 16 bit dma */ if (Jazz16_detected != 0) if (dma16 != dma8) { if (0) { printf("Jazz16: Can't allocate 16 bit DMA channel\n"); } } #endif /* JAZZ16 */ } else printf("SB: Too many DSP devices available\n"); #if defined(CONFIG_SB16) && defined(CONFIG_SBPRO) } #endif /* CONFIG_SB16 && CONFIG_SBPRO */ #else conf_printf("SoundBlaster (configured without audio support)", hw_config); #endif #ifdef CONFIG_MIDI if (!midi_disabled && !sb16) { /* * Midi don't work in the SB emulation mode of PAS, * SB16 has better midi interface */ sb_midi_init(sbc_major); } #endif /* CONFIG_MIDI */ sb_dsp_ok = 1; } void sb_dsp_disable_midi(void) { midi_disabled = 1; } #endif Index: head/sys/i386/isa/sound/sbcard.h =================================================================== --- head/sys/i386/isa/sound/sbcard.h (revision 55120) +++ head/sys/i386/isa/sound/sbcard.h (revision 55121) @@ -1,54 +1,72 @@ /* * file: sbcard.h + * + * $FreeBSD$ + * */ extern int sbc_major, sbc_minor ; /* * sound blaster registers */ +#ifdef PC98 +#define DSP_RESET (sbc_base + 0x600) +#define DSP_READ (sbc_base + 0xA00) +#define DSP_WRITE (sbc_base + 0xC00) +#define DSP_COMMAND (sbc_base + 0xC00) +#define DSP_STATUS (sbc_base + 0xC00) +#define DSP_DATA_AVAIL (sbc_base + 0xE00) +#define DSP_DATA_AVL16 (sbc_base + 0xF00) +#define MIXER_ADDR (sbc_base + 0x400) +#define MIXER_DATA (sbc_base + 0x500) +#define OPL3_LEFT (sbc_base + 0x000) +#define OPL3_RIGHT (sbc_base + 0x200) +#define OPL3_BOTH (sbc_base + 0x800) +#else #define DSP_RESET (sbc_base + 0x6) #define DSP_READ (sbc_base + 0xA) #define DSP_WRITE (sbc_base + 0xC) #define DSP_COMMAND (sbc_base + 0xC) #define DSP_STATUS (sbc_base + 0xC) #define DSP_DATA_AVAIL (sbc_base + 0xE) #define DSP_DATA_AVL16 (sbc_base + 0xF) #define MIXER_ADDR (sbc_base + 0x4) #define MIXER_DATA (sbc_base + 0x5) #define OPL3_LEFT (sbc_base + 0x0) #define OPL3_RIGHT (sbc_base + 0x2) #define OPL3_BOTH (sbc_base + 0x8) +#endif /* * DSP Commands. There are many, and in many cases they are used explicitly */ #define DSP_CMD_SPKON 0xD1 #define DSP_CMD_SPKOFF 0xD3 #define DSP_CMD_DMAON 0xD0 /* ??? the comment says Halt DMA */ #define DSP_CMD_DMAOFF 0xD4 /* ??? comment says continue dma */ #define DSP_CMD_DMAHALT 0xD0 #define DSP_CMD_TCONST 0x40 /* set time constant */ #define DSP_CMD_HSSIZE 0x48 /* high speed dma count */ #define DSP_CMD_HSDAC 0x91 /* high speed dac */ #define DSP_CMD_HSADC 0x99 /* high speed adc */ #define DSP_CMD_DAC8 0x14 /* 8-bit dac (dma count) */ #define DSP_CMD_ADC8 0x24 /* 8-bit adc (dma count) */ #define DSP_CMD_GETVER 0xE1 #define DSP_CMD_GETID 0xE7 /* return id bytes */ #if 0 /*** unknown ***/ #endif #define IMODE_NONE 0 #define IMODE_OUTPUT PCM_ENABLE_OUTPUT #define IMODE_INPUT PCM_ENABLE_INPUT #define IMODE_INIT 3 #define IMODE_MIDI 4 #define NORMAL_MIDI 0 #define UART_MIDI 1 Index: head/sys/i386/isa/sound/sound_config.h =================================================================== --- head/sys/i386/isa/sound/sound_config.h (revision 55120) +++ head/sys/i386/isa/sound/sound_config.h (revision 55121) @@ -1,205 +1,211 @@ /* sound_config.h * * A driver for Soundcards, misc configuration parameters. * * Copyright by Hannu Savolainen 1995 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD$ + * */ /* * many variables should be reduced to a range. Here define a macro */ #define RANGE(var, low, high) (var) = \ ((var)<(low)?(low) : (var)>(high)?(high) : (var)) #undef CONFIGURE_SOUNDCARD #undef DYNAMIC_BUFFER #include #define CONFIGURE_SOUNDCARD #define DYNAMIC_BUFFER #undef LOADABLE_SOUNDCARD #include #include #if defined(ISC) || defined(SCO) || defined(SVR42) #define GENERIC_SYSV #endif #ifndef SND_DEFAULT_ENABLE #define SND_DEFAULT_ENABLE 1 #endif #ifdef CONFIGURE_SOUNDCARD #ifndef MAX_REALTIME_FACTOR #define MAX_REALTIME_FACTOR 4 #endif /************* PCM DMA buffer sizes *******************/ /* If you are using high playback or recording speeds, the default buffersize is too small. DSP_BUFFSIZE must be 64k or less. A rule of thumb is 64k for PAS16, 32k for PAS+, 16k for SB Pro and 4k for SB. If you change the DSP_BUFFSIZE, don't modify this file. Use the make config command instead. Seems to allow only 4K, 16K, 32K, 64K. */ #ifndef DSP_BUFFSIZE #define DSP_BUFFSIZE (32760) #endif #ifndef DSP_BUFFCOUNT #define DSP_BUFFCOUNT 1 /* 1 is recommended. */ #endif #define DMA_AUTOINIT 0x10 /* XXX never used */ +#ifdef PC98 +#define FM_MONO 0x28d2 +#else #define FM_MONO 0x388 /* This is the I/O address used by AdLib */ +#endif #ifndef AWE32_BASE #define AWE32_BASE 0x620 /* Default = 0x620-3, 0xA20-3, 0xE20-3 */ #endif #ifndef PAS_BASE #define PAS_BASE 0x388 #endif #ifdef JAZZ16 #ifndef JAZZ_DMA16 #define JAZZ_DMA16 5 #endif #endif /* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the driver. (There is no need to alter this) */ #define SEQ_MAX_QUEUE 1024 #define SBFM_MAXINSTR (256) /* Size of the FM Instrument bank */ /* 128 instruments for general MIDI setup and 16 unassigned */ /* * Minor numbers for the sound driver. * * Unfortunately Creative called the codec chip of SB as a DSP. For this * reason the /dev/dsp is reserved for digitized audio use. There is a * device for true DSP processors but it will be called something else. * In v3.0 it's /dev/sndproc but this could be a temporary solution. */ #define SND_NDEVS 256 /* Number of supported devices */ #define SND_DEV_CTL 0 /* Control port /dev/mixer */ #define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */ #define SND_DEV_MIDIN 2 /* Raw midi access */ #define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ #define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ #define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ #define SND_DEV_STATUS 6 /* /dev/sndstat */ /* #7 not in use now. Was in 2.4. Free for use after v3.0. */ #define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ #define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ #define SND_DEV_PSS SND_DEV_SNDPROC #define DSP_DEFAULT_SPEED 8000 #define ON 1 #define OFF 0 #define MAX_AUDIO_DEV 5 #define MAX_MIXER_DEV 5 #define MAX_SYNTH_DEV 3 #define MAX_MIDI_DEV 6 #define MAX_TIMER_DEV 3 struct fileinfo { int mode; /* Open mode */ int flags; int dummy; /* Reference to file-flags. OS-dependent. */ }; struct address_info { int io_base; int irq; int dma; int dma2; int always_detect; /* 1=Trust me, it's there */ char *name; sound_os_info *osp; /* OS specific info */ int card_subtype; /* Driver specific. Usually 0 */ }; #define SYNTH_MAX_VOICES 32 struct voice_alloc_info { int max_voice; int used_voices; int ptr; /* For device specific use */ unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */ int timestamp; int alloc_times[SYNTH_MAX_VOICES]; }; struct channel_info { int pgm_num; int bender_value; unsigned char controllers[128]; }; /* * Process wakeup reasons */ #define WK_NONE 0x00 #define WK_WAKEUP 0x01 #define WK_TIMEOUT 0x02 #define WK_SIGNAL 0x04 #define WK_SLEEP 0x08 #define OPEN_READ PCM_ENABLE_INPUT #define OPEN_WRITE PCM_ENABLE_OUTPUT #define OPEN_READWRITE (OPEN_READ|OPEN_WRITE) #include #include #ifndef DEB #define DEB(x) #endif #ifndef DDB /* #define DDB(x) x XXX */ #define DDB(x) #endif #define TIMER_ARMED 121234 #define TIMER_NOT_ARMED 1 #endif