📄 mpu401.c
字号:
{ int i, timeout, ok; int ret = 0; unsigned long flags; struct mpu_config *devc; devc = &dev_conf[dev]; if (devc->uart_mode) /* * Not possible in UART mode */ { printk ("MPU-401 commands not possible in the UART mode\n"); return RET_ERROR (EINVAL); } /* * Test for input since pending input seems to block the output. */ if (input_avail (devc->base)) mpu401_input_loop (devc); /* * Sometimes it takes about 30000 loops before the output becomes ready * (After reset). Normally it takes just about 10 loops. */ timeout = 30000;retry: if (timeout-- <= 0) { printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); return RET_ERROR (EIO); } DISABLE_INTR (flags); if (!output_ready (devc->base)) { RESTORE_INTR (flags); goto retry; } write_command (devc->base, cmd->cmd); ok = 0; for (timeout = 50000; timeout > 0 && !ok; timeout--) if (input_avail (devc->base)) { if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK) ok = 1; } if (!ok) { RESTORE_INTR (flags); /* printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ return RET_ERROR (EIO); } if (cmd->nr_args) for (i = 0; i < cmd->nr_args; i++) { for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--); if (!mpu401_out (dev, cmd->data[i])) { RESTORE_INTR (flags); printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); return RET_ERROR (EIO); } } ret = 0; cmd->data[0] = 0; if (cmd->nr_returns) for (i = 0; i < cmd->nr_returns; i++) { ok = 0; for (timeout = 5000; timeout > 0 && !ok; timeout--) if (input_avail (devc->base)) { cmd->data[i] = read_data (devc->base); ok = 1; } if (!ok) { RESTORE_INTR (flags); /* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ return RET_ERROR (EIO); } } RESTORE_INTR (flags); return ret;}static intexec_cmd (int dev, int cmd, int data){ int ret; static mpu_command_rec rec; rec.cmd = cmd & 0xff; rec.nr_args = ((cmd & 0xf0) == 0xE0); rec.nr_returns = ((cmd & 0xf0) == 0xA0); rec.data[0] = data & 0xff; if ((ret = mpu401_command (dev, &rec)) < 0) return ret; return (unsigned char) rec.data[0];}static intmpu401_prefix_cmd (int dev, unsigned char status){ struct mpu_config *devc = &dev_conf[dev]; if (devc->uart_mode) return 1; if (status < 0xf0) { if (exec_cmd (dev, 0xD0, 0) < 0) return 0; return 1; } switch (status) { case 0xF0: if (exec_cmd (dev, 0xDF, 0) < 0) return 0; return 1; break; default: return 0; } return 0;}static intmpu401_start_read (int dev){ return 0;}static intmpu401_end_read (int dev){ return 0;}static intmpu401_ioctl (int dev, unsigned cmd, unsigned arg){ struct mpu_config *devc; devc = &dev_conf[dev]; switch (cmd) { case 1: IOCTL_FROM_USER ((char *) &init_sequence, (char *) arg, 0, sizeof (init_sequence)); return 0; break; case SNDCTL_MIDI_MPUMODE: if (devc->version == 0) { printk ("MPU-401: Intelligent mode not supported by the HW\n"); return RET_ERROR (EINVAL); } set_uart_mode (dev, devc, !IOCTL_IN (arg)); return 0; break; case SNDCTL_MIDI_MPUCMD: { int ret; mpu_command_rec rec; IOCTL_FROM_USER ((char *) &rec, (char *) arg, 0, sizeof (rec)); if ((ret = mpu401_command (dev, &rec)) < 0) return ret; IOCTL_TO_USER ((char *) arg, 0, (char *) &rec, sizeof (rec)); return 0; } break; default: return RET_ERROR (EINVAL); }}static voidmpu401_kick (int dev){}static intmpu401_buffer_status (int dev){ return 0; /* * No data in buffers */}static intmpu_synth_ioctl (int dev, unsigned int cmd, unsigned int arg){ int midi_dev; struct mpu_config *devc; midi_dev = synth_devs[dev]->midi_dev; if (midi_dev < 0 || midi_dev > num_midis) return RET_ERROR (ENXIO); devc = &dev_conf[midi_dev]; switch (cmd) { case SNDCTL_SYNTH_INFO: IOCTL_TO_USER ((char *) arg, 0, &mpu_synth_info[midi_dev], sizeof (struct synth_info)); return 0; break; case SNDCTL_SYNTH_MEMAVL: return 0x7fffffff; break; default: return RET_ERROR (EINVAL); }}static intmpu_synth_open (int dev, int mode){ int midi_dev, err; struct mpu_config *devc; midi_dev = synth_devs[dev]->midi_dev; if (midi_dev < 0 || midi_dev > num_midis) { return RET_ERROR (ENXIO); } devc = &dev_conf[midi_dev]; /* * Verify that the device is really running. * Some devices (such as Ensoniq SoundScape don't * work before the on board processor (OBP) is initialized * by downloadin it's microcode. */ if (!devc->initialized) { if (mpu401_status (devc->base) == 0xff) /* Bus float */ { printk ("MPU-401: Device not initialized properly\n"); return RET_ERROR (EIO); } reset_mpu401 (devc); } if (devc->opened) { printk ("MPU-401: Midi busy\n"); return RET_ERROR (EBUSY); } devc->mode = MODE_SYNTH; devc->synthno = dev; devc->inputintr = NULL; irq2dev[devc->irq] = midi_dev; if (devc->shared_irq == 0) if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[midi_dev]->info.name) < 0)) { return err; } if (midi_devs[midi_dev]->coproc) if ((err = midi_devs[midi_dev]->coproc-> open (midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) { if (devc->shared_irq == 0) snd_release_irq (devc->irq); printk ("MPU-401: Can't access coprocessor device\n"); return err; } devc->opened = mode; reset_mpu401 (devc); if (mode & OPEN_READ) { exec_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */ exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ } return 0;}static voidmpu_synth_close (int dev){ int midi_dev; struct mpu_config *devc; midi_dev = synth_devs[dev]->midi_dev; devc = &dev_conf[midi_dev]; exec_cmd (midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ exec_cmd (midi_dev, 0x8a, 0); /* Disable data in stopped mode */ if (devc->shared_irq == 0) snd_release_irq (devc->irq); devc->inputintr = NULL; if (midi_devs[midi_dev]->coproc) midi_devs[midi_dev]->coproc->close (midi_devs[midi_dev]->coproc->devc, COPR_MIDI); devc->opened = 0; devc->mode = 0;}#define MIDI_SYNTH_NAME "MPU-401 UART Midi"#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT#include <i386/isa/sound/midi_synth.h>static struct synth_operations mpu401_synth_proto ={ NULL, 0, SYNTH_TYPE_MIDI, 0, mpu_synth_open, mpu_synth_close, mpu_synth_ioctl, midi_synth_kill_note, midi_synth_start_note, midi_synth_set_instr, midi_synth_reset, midi_synth_hw_control, midi_synth_load_patch, midi_synth_aftertouch, midi_synth_controller, midi_synth_panning, NULL, midi_synth_patchmgr, midi_synth_bender, NULL, /* alloc */ midi_synth_setup_voice};static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV];static struct midi_operations mpu401_midi_proto ={ {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, NULL, {0}, mpu401_open, mpu401_close, mpu401_ioctl, mpu401_out, mpu401_start_read, mpu401_end_read, mpu401_kick, NULL, mpu401_buffer_status, mpu401_prefix_cmd};static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];static voidmpu401_chk_version (struct mpu_config *devc){ int tmp; devc->version = devc->revision = 0; if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0) return; if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ return; devc->version = tmp; if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0) { devc->version = 0; return; } devc->revision = tmp;}longattach_mpu401 (long mem_start, struct address_info *hw_config){ unsigned long flags; char revision_char; struct mpu_config *devc; if (num_midis >= MAX_MIDI_DEV) { printk ("MPU-401: Too many midi devices detected\n"); return mem_start; } devc = &dev_conf[num_midis]; devc->base = hw_config->io_base; devc->irq = hw_config->irq; devc->opened = 0; devc->uart_mode = 0; devc->initialized = 0; devc->version = 0; devc->revision = 0; devc->capabilities = 0; devc->timer_flag = 0; devc->m_busy = 0; devc->m_state = ST_INIT; devc->shared_irq = hw_config->always_detect; if (!hw_config->always_detect) { /* Verify the hardware again */ if (!reset_mpu401 (devc)) return mem_start; DISABLE_INTR (flags); mpu401_chk_version (devc); if (devc->version == 0) mpu401_chk_version (devc); RESTORE_INTR (flags); } if (devc->version == 0) { memcpy ((char *) &mpu401_synth_operations[num_midis], (char *) &std_midi_synth, sizeof (struct synth_operations)); } else { devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ memcpy ((char *) &mpu401_synth_operations[num_midis], (char *) &mpu401_synth_proto, sizeof (struct synth_operations)); } memcpy ((char *) &mpu401_midi_operations[num_midis], (char *) &mpu401_midi_proto, sizeof (struct midi_operations)); mpu401_midi_operations[num_midis].converter = &mpu401_synth_operations[num_midis]; memcpy ((char *) &mpu_synth_info[num_midis], (char *) &mpu_synth_info_proto, sizeof (struct synth_info)); n_mpu_devs++; if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */ { int ports = (devc->revision & 0x08) ? 32 : 16; devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | MPU_CAP_CLS | MPU_CAP_2PORT; revision_char = (devc->revision == 0x7f) ? 'M' : ' ';#if defined(__FreeBSD__) printk ("mpu0: <MQX-%d%c MIDI Interface>",#else printk (" <MQX-%d%c MIDI Interface>",#endif ports, revision_char); sprintf (mpu_synth_info[num_midis].name, "MQX-%d%c MIDI Interface #%d", ports, revision_char, n_mpu_devs); } else { revision_char = devc->revision ? devc->revision + '@' : ' '; if (devc->revision > ('Z' - '@')) revision_char = '+'; devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;#if defined(__FreeBSD__) printk ("mpu0: <MPU-401 MIDI Interface %d.%d%c>",#else printk (" <MPU-401 MIDI Interface %d.%d%c>",#endif (devc->version & 0xf0) >> 4, devc->version & 0x0f, revision_char); sprintf (mpu_synth_info[num_midis].name, "MPU-401 %d.%d%c Midi interface #%d", (devc->version & 0xf0) >> 4, devc->version & 0x0f, revision_char, n_mpu_devs); } strcpy (mpu401_midi_operations[num_midis].info.name, mpu_synth_info[num_midis].name); mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis; mpu401_synth_operations[devc->devno].info = &mpu_synth_info[devc->devno]; if (devc->capabilities & MPU_CAP_INTLG) /* Has timer */ mpu_timer_init (num_midis); irq2dev[devc->irq] = num_midis; midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; return mem_start;}static intreset_mpu401 (struct mpu_config *devc){ unsigned long flags; int ok, timeout, n; int timeout_limit; /* * Send the RESET command. Try again if no success at the first time. * (If the device is in the UART mode, it will not ack the reset cmd). */ ok = 0; timeout_limit = devc->initialized ? 30000 : 100000; devc->initialized = 1; for (n = 0; n < 2 && !ok; n++) { for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) ok = output_ready (devc->base); write_command (devc->base, 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 = timeout_limit * 2; timeout > 0 && !ok; timeout--) { DISABLE_INTR (flags); if (input_avail (devc->base)) if (read_data (devc->base) == MPU_ACK) ok = 1; RESTORE_INTR (flags); } } devc->m_state = ST_INIT; devc->m_ptr = 0; devc->m_left = 0; devc->last_status = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -