📄 wavfront.c
字号:
case SNDCTL_SEQ_PERCMODE: return 0; /* don't force an error */ break; case SNDCTL_SYNTH_MEMAVL: if ((dev.freemem = wavefront_freemem ()) < 0) { printk (KERN_ERR LOGNAME "cannot get memory size\n"); return -EIO; } else { return dev.freemem; } break; case SNDCTL_SYNTH_CONTROL: copy_from_user (&wc, arg, sizeof (wc)); if ((err = wavefront_synth_control (cmd, &wc)) == 0) { copy_to_user (arg, &wc, sizeof (wc)); } return err; default: return -(EINVAL); }}intwavefront_oss_load_patch (int devno, int format, const char *addr, int offs, int count, int pmgr_flag){ if (format == SYSEX_PATCH) { /* Handled by midi_synth.c */ if (midi_load_patch == NULL) { printk (KERN_ERR LOGNAME "SYSEX not loadable: " "no midi patch loader!\n"); return -(EINVAL); } return midi_load_patch (devno, format, addr, offs, count, pmgr_flag); } else if (format == GUS_PATCH) { return wavefront_load_gus_patch (devno, format, addr, offs, count, pmgr_flag); } else if (format != WAVEFRONT_PATCH) { printk (KERN_ERR LOGNAME "unknown patch format %d\n", format); return -(EINVAL); } if (count < sizeof (wavefront_patch_info)) { printk (KERN_ERR LOGNAME "sample header too short\n"); return -(EINVAL); } /* "addr" points to a user-space wavefront_patch_info */ return wavefront_load_patch (addr);} static struct synth_operations wavefront_operations ={ owner: THIS_MODULE, id: "WaveFront", info: &wavefront_info, midi_dev: 0, synth_type: SYNTH_TYPE_SAMPLE, synth_subtype: SAMPLE_TYPE_WAVEFRONT, open: wavefront_oss_open, close: wavefront_oss_close, ioctl: wavefront_oss_ioctl, kill_note: midi_synth_kill_note, start_note: midi_synth_start_note, set_instr: midi_synth_set_instr, reset: midi_synth_reset, load_patch: midi_synth_load_patch, aftertouch: midi_synth_aftertouch, controller: midi_synth_controller, panning: midi_synth_panning, bender: midi_synth_bender, setup_voice: midi_synth_setup_voice};#endif OSS_SUPPORT_SEQ#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALLstatic void __init attach_wavefront (struct address_info *hw_config){ (void) install_wavefront ();}static int __init probe_wavefront (struct address_info *hw_config){ return !detect_wavefront (hw_config->irq, hw_config->io_base);}static void __exit unload_wavefront (struct address_info *hw_config) { (void) uninstall_wavefront ();}#endif OSS_SUPPORT_STATIC_INSTALL/***********************************************************************//* WaveFront: Linux modular sound kernel installation interface *//***********************************************************************/voidwavefrontintr (int irq, void *dev_id, struct pt_regs *dummy){ struct wf_config *hw = dev_id; /* Some comments on interrupts. I attempted a version of this driver that used interrupts throughout the code instead of doing busy and/or sleep-waiting. Alas, it appears that once the Motorola firmware is downloaded, the card *never* generates an RX interrupt. These are successfully generated during firmware loading, and after that wavefront_status() reports that an interrupt is pending on the card from time to time, but it never seems to be delivered to this driver. Note also that wavefront_status() continues to report that RX interrupts are enabled, suggesting that I didn't goof up and disable them by mistake. Thus, I stepped back to a prior version of wavefront_wait(), the only place where this really matters. Its sad, but I've looked through the code to check on things, and I really feel certain that the Motorola firmware prevents RX-ready interrupts. */ if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) { return; } hw->irq_ok = 1; hw->irq_cnt++; wake_up_interruptible (&hw->interrupt_sleeper);}/* STATUS REGISTER 0 Host Rx Interrupt Enable (1=Enabled)1 Host Rx Register Full (1=Full)2 Host Rx Interrupt Pending (1=Interrupt)3 Unused4 Host Tx Interrupt (1=Enabled)5 Host Tx Register empty (1=Empty)6 Host Tx Interrupt Pending (1=Interrupt)7 Unused*/intwavefront_interrupt_bits (int irq){ int bits; switch (irq) { case 9: bits = 0x00; break; case 5: bits = 0x08; break; case 12: bits = 0x10; break; case 15: bits = 0x18; break; default: printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq); bits = -1; } return bits;}voidwavefront_should_cause_interrupt (int val, int port, int timeout){ unsigned long flags; save_flags (flags); cli(); dev.irq_ok = 0; outb (val,port); interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout); restore_flags (flags);}static int __init wavefront_hw_reset (void){ int bits; int hwv[2]; unsigned long irq_mask; short reported_irq; /* IRQ already checked in init_module() */ bits = wavefront_interrupt_bits (dev.irq); printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n"); sti (); irq_mask = probe_irq_on (); outb (0x0, dev.control_port); outb (0x80 | 0x40 | bits, dev.data_port); wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1, dev.control_port, (reset_time*HZ)/100); reported_irq = probe_irq_off (irq_mask); if (reported_irq != dev.irq) { if (reported_irq == 0) { printk (KERN_ERR LOGNAME "No unassigned interrupts detected " "after h/w reset\n"); } else if (reported_irq < 0) { printk (KERN_ERR LOGNAME "Multiple unassigned interrupts detected " "after h/w reset\n"); } else { printk (KERN_ERR LOGNAME "autodetected IRQ %d not the " "value provided (%d)\n", reported_irq, dev.irq); } dev.irq = -1; return 1; } else { printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n", reported_irq); } if (request_irq (dev.irq, wavefrontintr, SA_INTERRUPT|SA_SHIRQ, "wavefront synth", &dev) < 0) { printk (KERN_WARNING LOGNAME "IRQ %d not available!\n", dev.irq); return 1; } /* try reset of port */ outb (0x0, dev.control_port); /* At this point, the board is in reset, and the H/W initialization register is accessed at the same address as the data port. Bit 7 - Enable IRQ Driver 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus. Bit 6 - MIDI Interface Select 0 - Use the MIDI Input from the 26-pin WaveBlaster compatible header as the serial MIDI source 1 - Use the MIDI Input from the 9-pin D connector as the serial MIDI source. Bits 5:3 - IRQ Selection 0 0 0 - IRQ 2/9 0 0 1 - IRQ 5 0 1 0 - IRQ 12 0 1 1 - IRQ 15 1 0 0 - Reserved 1 0 1 - Reserved 1 1 0 - Reserved 1 1 1 - Reserved Bits 2:1 - Reserved Bit 0 - Disable Boot ROM 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM 1 - memory accesses to 03FC30-03FFFFH are directed to external storage. */ /* configure hardware: IRQ, enable interrupts, plus external 9-pin MIDI interface selected */ outb (0x80 | 0x40 | bits, dev.data_port); /* CONTROL REGISTER 0 Host Rx Interrupt Enable (1=Enabled) 0x1 1 Unused 0x2 2 Unused 0x4 3 Unused 0x8 4 Host Tx Interrupt Enable 0x10 5 Mute (0=Mute; 1=Play) 0x20 6 Master Interrupt Enable (1=Enabled) 0x40 7 Master Reset (0=Reset; 1=Run) 0x80 Take us out of reset, mute output, master + TX + RX interrupts on. We'll get an interrupt presumably to tell us that the TX register is clear. */ wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1, dev.control_port, (reset_time*HZ)/100); /* Note: data port is now the data port, not the h/w initialization port. */ if (!dev.irq_ok) { printk (KERN_WARNING LOGNAME "intr not received after h/w un-reset.\n"); goto gone_bad; } dev.interrupts_on = 1; /* Note: data port is now the data port, not the h/w initialization port. At this point, only "HW VERSION" or "DOWNLOAD OS" commands will work. So, issue one of them, and wait for TX interrupt. This can take a *long* time after a cold boot, while the ISC ROM does its RAM test. The SDK says up to 4 seconds - with 12MB of RAM on a Tropez+, it takes a lot longer than that (~16secs). Note that the card understands the difference between a warm and a cold boot, so subsequent ISC2115 reboots (say, caused by module reloading) will get through this much faster. XXX Interesting question: why is no RX interrupt received first ? */ wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION, dev.data_port, ramcheck_time*HZ); if (!dev.irq_ok) { printk (KERN_WARNING LOGNAME "post-RAM-check interrupt not received.\n"); goto gone_bad; } if (!wavefront_wait (STAT_CAN_READ)) { printk (KERN_WARNING LOGNAME "no response to HW version cmd.\n"); goto gone_bad; } if ((hwv[0] = wavefront_read ()) == -1) { printk (KERN_WARNING LOGNAME "board not responding correctly.\n"); goto gone_bad; } if (hwv[0] == 0xFF) { /* NAK */ /* Board's RAM test failed. Try to read error code, and tell us about it either way. */ if ((hwv[0] = wavefront_read ()) == -1) { printk (KERN_WARNING LOGNAME "on-board RAM test failed " "(bad error code).\n"); } else { printk (KERN_WARNING LOGNAME "on-board RAM test failed " "(error code: 0x%x).\n", hwv[0]); } goto gone_bad; } /* We're OK, just get the next byte of the HW version response */ if ((hwv[1] = wavefront_read ()) == -1) { printk (KERN_WARNING LOGNAME "incorrect h/w response.\n"); goto gone_bad; } printk (KERN_INFO LOGNAME "hardware version %d.%d\n", hwv[0], hwv[1]); return 0; gone_bad: if (dev.irq >= 0) { free_irq (dev.irq, &dev); dev.irq = -1; } return (1);}static int __init detect_wavefront (int irq, int io_base){ unsigned char rbuf[4], wbuf[4]; /* TB docs say the device takes up 8 ports, but we know that if there is an FX device present (i.e. a Tropez+) it really consumes 16. */ if (check_region (io_base, 16)) { printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x " "already in use - ignored\n", dev.base, dev.base+15); return -1; } dev.irq = irq; dev.base = io_base; dev.israw = 0; dev.debug = debug_default; dev.interrupts_on = 0; dev.irq_cnt = 0; dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */ if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { dev.fw_version[0] = rbuf[0]; dev.fw_version[1] = rbuf[1]; printk (KERN_INFO LOGNAME "firmware %d.%d already loaded.\n", rbuf[0], rbuf[1]); /* check that a command actually works */ if (wavefront_cmd (WFC_HARDWARE_VERSION, rbuf, wbuf) == 0) { dev.hw_version[0] = rbuf[0]; dev.hw_version[1] = rbuf[1]; } else { printk (KERN_WARNING LOGNAME "not raw, but no " "hardware version!\n"); return 0; } if (!wf_raw) { return 1; } else { printk (KERN_INFO LOGNAME "reloading firmware anyway.\n"); dev.israw = 1; } } else { dev.israw = 1; printk (KERN_INFO LOGNAME "no response to firmware probe, assume raw.\n"); } init_waitqueue_head (&dev.interrupt_sleeper); if (wavefront_hw_reset ()) { printk (KERN_WARNING LOGNAME "hardware reset failed\n"); return 0; } /* Check for FX device, present only on Tropez+ */ dev.has_fx = (detect_wffx () == 0); return 1;}#include "os.h"#define __KERNEL_SYSCALLS__#include <linux/fs.h>#include <linux/mm.h>#include <linux/malloc.h>#include <linux/unistd.h>#include <asm/uaccess.h>static int errno; static intwavefront_download_firmware (char *path){ unsigned char section[WF_SECTION_MAX]; char section_length; /* yes, just a char; max value is WF_SECTION_MAX */ int section_cnt_downloaded = 0; int fd; int c; int i; mm_segment_t fs; /* This tries to be a bit cleverer than the stuff Alan Cox did for the generic sound firmware, in that it actually knows something about the structure of the Motorola firmware. In particular, it uses a version that has been stripped of the 20K of useless header information, and had section lengths added, making it possible to load the entire OS without any [kv]malloc() activity, since the longest entity we ever read is 42 bytes (well, WF_SECTION_MAX) long. */ fs = get_fs(); set_fs (get_ds()); if ((fd = open (path, 0, 0)) < 0) { printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n", path)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -