/* * linux/kernel/chr_drv/sound/sequencer.c * * The sequencer personality manager. * * 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. * */ #define SEQUENCER_C #include "sound_config.h" #ifdef CONFIGURE_SOUNDCARD #ifndef EXCLUDE_SEQUENCER static int sequencer_ok = 0; DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag); DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); static int midi_opened[MAX_MIDI_DEV] = {0}; /* 1 if the process has opened MIDI */ static int midi_written[MAX_MIDI_DEV] = {0}; long seq_time = 0; /* Reference point for the timer */ #include "tuning.h" #define EV_SZ 8 static unsigned char queue[SEQ_MAX_QUEUE][EV_SZ]; static unsigned char iqueue[SEQ_MAX_QUEUE][4]; static volatile int qhead = 0, qtail = 0, qlen = 0; static volatile int iqhead = 0, iqtail = 0, iqlen = 0; static volatile int seq_playing = 0; static int sequencer_busy = 0; static int output_treshold; static unsigned synth_open_mask; static int seq_queue (unsigned char *note); static void seq_startplay (void); static int seq_sync (void); static void seq_reset (void); static int pmgr_present[MAX_SYNTH_DEV] = {0}; #if MAX_SYNTH_DEV > 15 #error Too many synthesizer devices #endif int sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { int c = count, p = 0; dev = dev >> 4; if (dev) /* Patch manager device */ return pmgr_read (dev - 1, file, buf, count); while (c > 3) { if (!iqlen) { INTERRUPTIBLE_SLEEP_ON (midi_sleeper, midi_sleep_flag); if (!iqlen) return count - c; } COPY_TO_USER (buf, p, &iqueue[iqhead][0], 4); p += 4; c -= 4; iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; iqlen--; } return count - c; } static void sequencer_midi_output (int dev) { /* Currently NOP */ } static void copy_to_input (unsigned char *event) { unsigned long flags; if (iqlen >= (SEQ_MAX_QUEUE - 1)) return; /* Overflow */ memcpy (iqueue[iqtail], event, 4); iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; DISABLE_INTR (flags); if (midi_sleep_flag) { WAKE_UP (midi_sleeper); } RESTORE_INTR (flags); } static void sequencer_midi_input (int dev, unsigned char data) { int tstamp; unsigned char event[4]; if (data == 0xfe) /* Active sensing */ return; /* Ignore */ tstamp = GET_TIME () - seq_time; /* Time since open() */ tstamp = (tstamp << 8) | SEQ_WAIT; copy_to_input ((unsigned char *) &tstamp); event[0] = SEQ_MIDIPUTC; event[1] = data; event[2] = dev; event[3] = 0; copy_to_input (event); } int sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { unsigned char event[EV_SZ], ev_code; int p = 0, c, ev_size; int err; int mode = file->mode & O_ACCMODE; dev = dev >> 4; DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count)); if (mode == OPEN_READ) return RET_ERROR (EIO); if (dev) /* Patch manager device */ return pmgr_write (dev - 1, file, buf, count); c = count; while (c >= 4) { COPY_FROM_USER (event, buf, p, 4); ev_code = event[0]; if (ev_code == SEQ_FULLSIZE) { int err; dev = *(unsigned short *) &event[2]; if (dev < 0 || dev >= num_synths) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev))) return RET_ERROR (ENXIO); err = synth_devs[dev]->load_patch (dev, *(short *) &event[0], buf, p + 4, c, 0); if (err < 0) return err; return err; } if (ev_code == SEQ_EXTENDED || ev_code == SEQ_PRIVATE) { ev_size = 8; if (c < ev_size) { if (!seq_playing) seq_startplay (); return count - c; } COPY_FROM_USER (&event[4], buf, p + 4, 4); } else ev_size = 4; if (event[0] == SEQ_MIDIPUTC) { if (!midi_opened[event[2]]) { int mode; int dev = event[2]; if (dev >= num_midis) { printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev); return RET_ERROR (ENXIO); } mode = file->mode & O_ACCMODE; if ((err = midi_devs[dev]->open (dev, mode, sequencer_midi_input, sequencer_midi_output)) < 0) { seq_reset (); printk ("Sequencer Error: Unable to open Midi #%d\n", dev); return err; } midi_opened[dev] = 1; } } if (!seq_queue (event)) { if (!seq_playing) seq_startplay (); return count - c; } p += ev_size; c -= ev_size; } if (!seq_playing) seq_startplay (); return count; } static int seq_queue (unsigned char *note) { /* Test if there is space in the queue */ if (qlen >= SEQ_MAX_QUEUE) if (!seq_playing) seq_startplay (); /* Give chance to drain the queue */ if (qlen >= SEQ_MAX_QUEUE && !seq_sleep_flag) { /* Sleep until there is enough space on the queue */ INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag); } if (qlen >= SEQ_MAX_QUEUE) return 0; /* To be sure */ memcpy (&queue[qtail][0], note, EV_SZ); qtail = (qtail + 1) % SEQ_MAX_QUEUE; qlen++; return 1; } static int extended_event (unsigned char *q) { int dev = q[2]; if (dev < 0 || dev >= num_synths) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev))) return RET_ERROR (ENXIO); switch (q[1]) { case SEQ_NOTEOFF: synth_devs[dev]->kill_note (dev, q[3], q[5]); break; case SEQ_NOTEON: if (q[4] > 127 && q[4] != 255) return 0; synth_devs[dev]->start_note (dev, q[3], q[4], q[5]); break; case SEQ_PGMCHANGE: synth_devs[dev]->set_instr (dev, q[3], q[4]); break; case SEQ_AFTERTOUCH: synth_devs[dev]->aftertouch (dev, q[3], q[4]); break; case SEQ_BALANCE: synth_devs[dev]->panning (dev, q[3], (char) q[4]); break; case SEQ_CONTROLLER: synth_devs[dev]->controller (dev, q[3], q[4], *(short *) &q[5]); break; default: return RET_ERROR (EINVAL); } return 0; } static void seq_startplay (void) { int this_one; unsigned long *delay; unsigned char *q; while (qlen > 0) { qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; qlen--; q = &queue[this_one][0]; switch (q[0]) { case SEQ_NOTEOFF: if (synth_open_mask & (1 << 0)) if (synth_devs[0]) synth_devs[0]->kill_note (0, q[1], q[3]); break; case SEQ_NOTEON: if (q[4] < 128 || q[4] == 255) if (synth_open_mask & (1 << 0)) if (synth_devs[0]) synth_devs[0]->start_note (0, q[1], q[2], q[3]); break; case SEQ_WAIT: delay = (unsigned long *) q; /* Bytes 1 to 3 are containing the * delay in GET_TIME() */ *delay = (*delay >> 8) & 0xffffff; if (*delay > 0) { long time; seq_playing = 1; time = *delay; request_sound_timer (time); if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) { unsigned long flags; DISABLE_INTR (flags); if (seq_sleep_flag) { seq_sleep_flag = 0; WAKE_UP (seq_sleeper); } RESTORE_INTR (flags); } return; /* Stop here. Timer routine will continue * playing after the delay */ } break; case SEQ_PGMCHANGE: if (synth_open_mask & (1 << 0)) if (synth_devs[0]) synth_devs[0]->set_instr (0, q[1], q[2]); break; case SEQ_SYNCTIMER: /* Reset timer */ seq_time = GET_TIME (); break; case SEQ_MIDIPUTC: /* Put a midi character */ if (midi_opened[q[2]]) { int dev; dev = q[2]; if (!midi_devs[dev]->putc (dev, q[1])) { /* * Output FIFO is full. Wait one timer cycle and try again. */ qlen++; qhead = this_one; /* Restore queue */ seq_playing = 1; request_sound_timer (-1); return; } else midi_written[dev] = 1; } break; case SEQ_ECHO: copy_to_input (q); /* Echo back to the process */ break; case SEQ_PRIVATE: if (q[1] < num_synths) synth_devs[q[1]]->hw_control (q[1], q); break; case SEQ_EXTENDED: extended_event (q); break; default:; } } seq_playing = 0; if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) { unsigned long flags; DISABLE_INTR (flags); if (seq_sleep_flag) { seq_sleep_flag = 0; WAKE_UP (seq_sleeper); } RESTORE_INTR (flags); } } int sequencer_open (int dev, struct fileinfo *file) { int retval, mode, i; dev = dev >> 4; mode = file->mode & O_ACCMODE; DEB (printk ("sequencer_open(dev=%d)\n", dev)); if (!sequencer_ok) { printk ("Soundcard: Sequencer not initialized\n"); return RET_ERROR (ENXIO); } if (dev) /* Patch manager device */ { int err; dev--; if (pmgr_present[dev]) return RET_ERROR (EBUSY); if ((err = pmgr_open (dev)) < 0) return err; /* Failed */ pmgr_present[dev] = 1; return err; } if (sequencer_busy) { printk ("Sequencer busy\n"); return RET_ERROR (EBUSY); } if (!(num_synths + num_midis)) return RET_ERROR (ENXIO); synth_open_mask = 0; if (mode == OPEN_WRITE || mode == OPEN_READWRITE) for (i = 0; i < num_synths; i++) /* Open synth devices */ if (synth_devs[i]->open (i, mode) < 0) printk ("Sequencer: Warning! Cannot open synth device #%d\n", i); else synth_open_mask |= (1 << i); seq_time = GET_TIME (); for (i = 0; i < num_midis; i++) { midi_opened[i] = 0; midi_written[i] = 0; } if (mode == OPEN_READ || mode == OPEN_READWRITE) { /* Initialize midi input devices */ if (!num_midis) { printk ("Sequencer: No Midi devices. Input not possible\n"); return RET_ERROR (ENXIO); } for (i = 0; i < num_midis; i++) { if ((retval = midi_devs[i]->open (i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) midi_opened[i] = 1; } } sequencer_busy = 1; seq_sleep_flag = midi_sleep_flag = 0; output_treshold = SEQ_MAX_QUEUE / 2; for (i = 0; i < num_synths; i++) if (pmgr_present[i]) pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0); return 0; } void seq_drain_midi_queues (void) { int i, n; /* * Give the Midi drivers time to drain their output queues */ n = 1; while (!PROCESS_ABORTING && n) { n = 0; for (i = 0; i < num_midis; i++) if (midi_opened[i] && midi_written[i]) if (midi_devs[i]->buffer_status != NULL) if (midi_devs[i]->buffer_status (i)) n++; /* * Let's have a delay */ if (n) { REQUEST_TIMEOUT (HZ / 10, seq_sleeper); INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag); } } } void sequencer_release (int dev, struct fileinfo *file) { int i; int mode = file->mode & O_ACCMODE; dev = dev >> 4; DEB (printk ("sequencer_release(dev=%d)\n", dev)); if (dev) /* Patch manager device */ { dev--; pmgr_release (dev); pmgr_present[dev] = 0; return; } /* * Wait until the queue is empty */ while (!PROCESS_ABORTING && qlen) { seq_sync (); } if (mode != OPEN_READ) seq_drain_midi_queues (); /* Ensure the output queues are empty */ seq_reset (); if (mode != OPEN_READ) seq_drain_midi_queues (); /* Flush the all notes off messages */ for (i = 0; i < num_midis; i++) if (midi_opened[i]) midi_devs[i]->close (i); if (mode == OPEN_WRITE || mode == OPEN_READWRITE) for (i = 0; i < num_synths; i++) if (synth_open_mask & (1 << i)) /* Actually opened */ if (synth_devs[i]) synth_devs[i]->close (i); for (i = 0; i < num_synths; i++) if (pmgr_present[i]) pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0); sequencer_busy = 0; } static int seq_sync (void) { if (qlen && !seq_playing && !PROCESS_ABORTING) seq_startplay (); if (qlen && !seq_sleep_flag) /* Queue not empty */ { INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag); } return qlen; } static void midi_outc (int dev, unsigned char data) { /* * NOTE! Calls sleep(). Don't call this from interrupt. */ int n; /* This routine sends one byte to the Midi channel. */ /* If the output Fifo is full, it waits until there */ /* is space in the queue */ n = 300; /* Timeout in jiffies */ while (n && !midi_devs[dev]->putc (dev, data)) { REQUEST_TIMEOUT (1, seq_sleeper); INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag); n--; } } static void seq_reset (void) { /* * NOTE! Calls sleep(). Don't call this from interrupt. */ int i, chn; sound_stop_timer (); qlen = qhead = qtail = 0; iqlen = iqhead = iqtail = 0; for (i = 0; i < num_synths; i++) if (synth_open_mask & (1 << i)) if (synth_devs[i]) synth_devs[i]->reset (i); for (i = 0; i < num_midis; i++) if (midi_written[i]) /* Midi used. Some notes may still be playing */ { for (chn = 0; chn < 16; chn++) { midi_outc (i, 0xb0 + chn); /* Channel message */ midi_outc (i, 0x7b);/* All notes off */ midi_outc (i, 0); /* Dummy parameter */ } midi_devs[i]->close (i); midi_written[i] = 0; midi_opened[i] = 0; } seq_playing = 0; if (seq_sleep_flag) printk ("Sequencer Warning: Unexpected sleeping process\n"); } int sequencer_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg) { int midi_dev, orig_dev; int mode = file->mode & O_ACCMODE; orig_dev = dev = dev >> 4; switch (cmd) { case SNDCTL_SEQ_SYNC: if (dev) /* Patch manager */ return RET_ERROR (EIO); if (mode == OPEN_READ) return 0; while (qlen && !PROCESS_ABORTING) seq_sync (); return 0; break; case SNDCTL_SEQ_RESET: if (dev) /* Patch manager */ return RET_ERROR (EIO); seq_reset (); return 0; break; case SNDCTL_SEQ_TESTMIDI: if (dev) /* Patch manager */ return RET_ERROR (EIO); midi_dev = IOCTL_IN (arg); if (midi_dev >= num_midis) return RET_ERROR (ENXIO); if (!midi_opened[midi_dev]) { int err, mode; mode = file->mode & O_ACCMODE; if ((err = midi_devs[midi_dev]->open (midi_dev, mode, sequencer_midi_input, sequencer_midi_output)) < 0) return err; } midi_opened[midi_dev] = 1; return 0; break; case SNDCTL_SEQ_GETINCOUNT: if (dev) /* Patch manager */ return RET_ERROR (EIO); if (mode == OPEN_WRITE) return 0; return IOCTL_OUT (arg, iqlen); break; case SNDCTL_SEQ_GETOUTCOUNT: if (mode == OPEN_READ) return 0; return IOCTL_OUT (arg, SEQ_MAX_QUEUE - qlen); break; case SNDCTL_SEQ_CTRLRATE: if (dev) /* Patch manager */ return RET_ERROR (EIO); /* If *arg == 0, just return the current rate */ return IOCTL_OUT (arg, HZ); break; case SNDCTL_SEQ_RESETSAMPLES: dev = IOCTL_IN (arg); if (dev < 0 || dev >= num_synths) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev)) && !orig_dev) return RET_ERROR (EBUSY); if (!orig_dev && pmgr_present[dev]) pmgr_inform (dev, PM_E_PATCH_RESET, 0, 0, 0, 0); return synth_devs[dev]->ioctl (dev, cmd, arg); break; case SNDCTL_SEQ_NRSYNTHS: return IOCTL_OUT (arg, num_synths); break; case SNDCTL_SEQ_NRMIDIS: return IOCTL_OUT (arg, num_midis); break; case SNDCTL_SYNTH_MEMAVL: { int dev = IOCTL_IN (arg); if (dev < 0 || dev >= num_synths) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev)) && !orig_dev) return RET_ERROR (EBUSY); return IOCTL_OUT (arg, synth_devs[dev]->ioctl (dev, cmd, arg)); } break; case SNDCTL_FM_4OP_ENABLE: { int dev = IOCTL_IN (arg); if (dev < 0 || dev >= num_synths) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev))) return RET_ERROR (ENXIO); synth_devs[dev]->ioctl (dev, cmd, arg); return 0; } break; case SNDCTL_SYNTH_INFO: { struct synth_info inf; int dev; IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf)); dev = inf.device; if (dev < 0 || dev >= num_synths) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev)) && !orig_dev) return RET_ERROR (EBUSY); return synth_devs[dev]->ioctl (dev, cmd, arg); } break; case SNDCTL_MIDI_INFO: { struct midi_info inf; int dev; IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf)); dev = inf.device; if (dev < 0 || dev >= num_midis) return RET_ERROR (ENXIO); IOCTL_TO_USER ((char *) arg, 0, (char *) &(midi_devs[dev]->info), sizeof (inf)); return 0; } break; case SNDCTL_PMGR_IFACE: { struct patmgr_info *inf; int dev, err; inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf)); IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf)); dev = inf->device; if (dev < 0 || dev >= num_synths) { KERNEL_FREE (inf); return RET_ERROR (ENXIO); } if (!synth_devs[dev]->pmgr_interface) { KERNEL_FREE (inf); return RET_ERROR (ENXIO); } if ((err = synth_devs[dev]->pmgr_interface (dev, inf)) == -1) { KERNEL_FREE (inf); return err; } IOCTL_TO_USER ((char *) arg, 0, (char *) inf, sizeof (*inf)); KERNEL_FREE (inf); return 0; } break; case SNDCTL_PMGR_ACCESS: { struct patmgr_info *inf; int dev, err; inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf)); IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf)); dev = inf->device; if (dev < 0 || dev >= num_synths) { KERNEL_FREE (inf); return RET_ERROR (ENXIO); } if (!pmgr_present[dev]) { KERNEL_FREE (inf); return RET_ERROR (ESRCH); } if ((err = pmgr_access (dev, inf)) < 0) { KERNEL_FREE (inf); return err; } IOCTL_TO_USER ((char *) arg, 0, (char *) inf, sizeof (*inf)); KERNEL_FREE (inf); return 0; } break; case SNDCTL_SEQ_TRESHOLD: { int tmp = IOCTL_IN (arg); if (dev) /* Patch manager */ return RET_ERROR (EIO); if (tmp < 1) tmp = 1; if (tmp >= SEQ_MAX_QUEUE) tmp = SEQ_MAX_QUEUE - 1; output_treshold = tmp; return 0; } break; default: if (dev) /* Patch manager */ return RET_ERROR (EIO); if (mode == OPEN_READ) return RET_ERROR (EIO); if (!synth_devs[0]) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << 0))) return RET_ERROR (ENXIO); return synth_devs[0]->ioctl (0, cmd, arg); break; } return RET_ERROR (EINVAL); } #ifdef ALLOW_SELECT int sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) { dev = dev >> 4; switch (sel_type) { case SEL_IN: if (!iqlen) { midi_sleep_flag = 1; select_wait (&midi_sleeper, wait); return 0; } return 1; break; case SEL_OUT: if (qlen >= SEQ_MAX_QUEUE) { seq_sleep_flag = 1; select_wait (&seq_sleeper, wait); return 0; } return 1; break; case SEL_EX: return 0; } return 0; } #endif void sequencer_timer (void) { seq_startplay (); } int note_to_freq (int note_num) { /* * This routine converts a midi note to a frequency (multiplied by 1000) */ int note, octave, note_freq; int notes[] = { 261632, 277189, 293671, 311132, 329632, 349232, 369998, 391998, 415306, 440000, 466162, 493880 }; /* Note freq*1000 for octave 5 */ #define BASE_OCTAVE 5 octave = note_num / 12; note = note_num % 12; note_freq = notes[note]; if (octave < BASE_OCTAVE) note_freq >>= (BASE_OCTAVE - octave); else if (octave > BASE_OCTAVE) note_freq <<= (octave - BASE_OCTAVE); /* note_freq >>= 1; */ return note_freq; } unsigned long compute_finetune (unsigned long base_freq, int bend, int range) { unsigned long amount; int negative, semitones, cents; if (!bend) return base_freq; if (!range) return base_freq; if (!base_freq) return base_freq; if (range >= 8192) range = 8191; bend = bend * range / 8192; if (!bend) return base_freq; negative = bend < 0 ? 1 : 0; if (bend < 0) bend *= -1; if (bend > range) bend = range; if (bend > 2399) bend = 2399; semitones = bend / 100; cents = bend % 100; amount = semitone_tuning[semitones] * cent_tuning[cents] / 10000; if (negative) return (base_freq * 10000) / amount; /* Bend down */ else return (base_freq * amount) / 10000; /* Bend up */ } long sequencer_init (long mem_start) { sequencer_ok = 1; return mem_start; } #else /* Stub version */ int sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { return RET_ERROR (EIO); } int sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { return RET_ERROR (EIO); } int sequencer_open (int dev, struct fileinfo *file) { return RET_ERROR (ENXIO); } void sequencer_release (int dev, struct fileinfo *file) { } int sequencer_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg) { return RET_ERROR (EIO); } int sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig) { return RET_ERROR (EIO); } long sequencer_init (long mem_start) { return mem_start; } int sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) { return RET_ERROR (EIO); } #endif #endif