📄 cmpci.c
字号:
static /*const*/ struct file_operations cm_audio_fops = { owner: THIS_MODULE, llseek: cm_llseek, read: cm_read, write: cm_write, poll: cm_poll, ioctl: cm_ioctl, mmap: cm_mmap, open: cm_open, release: cm_release,};/* --------------------------------------------------------------------- */static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ struct cm_state *s = (struct cm_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; int cnt; VALIDATE_STATE(s); if (ppos != &file->f_pos) return -ESPIPE; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; if (count == 0) return 0; ret = 0; add_wait_queue(&s->midi.iwait, &wait); while (count > 0) { set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); ptr = s->midi.ird; cnt = MIDIINBUF - ptr; if (s->midi.icnt < cnt) cnt = s->midi.icnt; spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } schedule(); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } continue; } if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { if (!ret) ret = -EFAULT; break; } ptr = (ptr + cnt) % MIDIINBUF; spin_lock_irqsave(&s->lock, flags); s->midi.ird = ptr; s->midi.icnt -= cnt; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; break; } __set_current_state(TASK_RUNNING); remove_wait_queue(&s->midi.iwait, &wait); return ret;}static ssize_t cm_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct cm_state *s = (struct cm_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned ptr; int cnt; VALIDATE_STATE(s); if (ppos != &file->f_pos) return -ESPIPE; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; if (count == 0) return 0; ret = 0; add_wait_queue(&s->midi.owait, &wait); while (count > 0) { set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); ptr = s->midi.owr; cnt = MIDIOUTBUF - ptr; if (s->midi.ocnt + cnt > MIDIOUTBUF) cnt = MIDIOUTBUF - s->midi.ocnt; if (cnt <= 0) cm_handle_midi(s); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } schedule(); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } continue; } if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { if (!ret) ret = -EFAULT; break; } ptr = (ptr + cnt) % MIDIOUTBUF; spin_lock_irqsave(&s->lock, flags); s->midi.owr = ptr; s->midi.ocnt += cnt; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; spin_lock_irqsave(&s->lock, flags); cm_handle_midi(s); spin_unlock_irqrestore(&s->lock, flags); } __set_current_state(TASK_RUNNING); remove_wait_queue(&s->midi.owait, &wait); return ret;}static unsigned int cm_midi_poll(struct file *file, struct poll_table_struct *wait){ struct cm_state *s = (struct cm_state *)file->private_data; unsigned long flags; unsigned int mask = 0; VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) poll_wait(file, &s->midi.owait, wait); if (file->f_mode & FMODE_READ) poll_wait(file, &s->midi.iwait, wait); spin_lock_irqsave(&s->lock, flags); if (file->f_mode & FMODE_READ) { if (s->midi.icnt > 0) mask |= POLLIN | POLLRDNORM; } if (file->f_mode & FMODE_WRITE) { if (s->midi.ocnt < MIDIOUTBUF) mask |= POLLOUT | POLLWRNORM; } spin_unlock_irqrestore(&s->lock, flags); return mask;}static int cm_midi_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct cm_state *s = devs; unsigned long flags; while (s && s->dev_midi != minor) s = s->next; if (!s) return -ENODEV; VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ down(&s->open_sem); while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { if (file->f_flags & O_NONBLOCK) { up(&s->open_sem); return -EBUSY; } up(&s->open_sem); interruptible_sleep_on(&s->open_wait); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); } spin_lock_irqsave(&s->lock, flags); if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { s->midi.ird = s->midi.iwr = s->midi.icnt = 0; s->midi.ord = s->midi.owr = s->midi.ocnt = 0; /* enable MPU-401 */ outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 4, s->iobase + CODEC_CMI_FUNCTRL1); outb(0xff, s->iomidi+1); /* reset command */ if (!(inb(s->iomidi+1) & 0x80)) inb(s->iomidi); outb(0x3f, s->iomidi+1); /* uart command */ if (!(inb(s->iomidi+1) & 0x80)) inb(s->iomidi); s->midi.ird = s->midi.iwr = s->midi.icnt = 0; init_timer(&s->midi.timer); s->midi.timer.expires = jiffies+1; s->midi.timer.data = (unsigned long)s; s->midi.timer.function = cm_midi_timer; add_timer(&s->midi.timer); } if (file->f_mode & FMODE_READ) { s->midi.ird = s->midi.iwr = s->midi.icnt = 0; } if (file->f_mode & FMODE_WRITE) { s->midi.ord = s->midi.owr = s->midi.ocnt = 0; } spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); up(&s->open_sem); return 0;}static int cm_midi_release(struct inode *inode, struct file *file){ struct cm_state *s = (struct cm_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); unsigned long flags; unsigned count, tmo; VALIDATE_STATE(s); lock_kernel(); if (file->f_mode & FMODE_WRITE) { add_wait_queue(&s->midi.owait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->midi.ocnt; spin_unlock_irqrestore(&s->lock, flags); if (count <= 0) break; if (signal_pending(current)) break; if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); return -EBUSY; } tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "cmpci: midi timed out??\n"); } remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); } down(&s->open_sem); s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE); spin_lock_irqsave(&s->lock, flags); if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { del_timer(&s->midi.timer); outb(0xff, s->iomidi+1); /* reset command */ if (!(inb(s->iomidi+1) & 0x80)) inb(s->iomidi); /* disable MPU-401 */ outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~4, s->iobase + CODEC_CMI_FUNCTRL1); } spin_unlock_irqrestore(&s->lock, flags); up(&s->open_sem); wake_up(&s->open_wait); unlock_kernel(); return 0;}static /*const*/ struct file_operations cm_midi_fops = { owner: THIS_MODULE, llseek: cm_llseek, read: cm_midi_read, write: cm_midi_write, poll: cm_midi_poll, open: cm_midi_open, release: cm_midi_release,};/* --------------------------------------------------------------------- */static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ static const unsigned char op_offset[18] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }; struct cm_state *s = (struct cm_state *)file->private_data; struct dm_fm_voice v; struct dm_fm_note n; struct dm_fm_params p; unsigned int io; unsigned int regb; switch (cmd) { case FM_IOCTL_RESET: for (regb = 0xb0; regb < 0xb9; regb++) { outb(regb, s->iosynth); outb(0, s->iosynth+1); outb(regb, s->iosynth+2); outb(0, s->iosynth+3); } return 0; case FM_IOCTL_PLAY_NOTE: if (copy_from_user(&n, (void *)arg, sizeof(n))) return -EFAULT; if (n.voice >= 18) return -EINVAL; if (n.voice >= 9) { regb = n.voice - 9; io = s->iosynth+2; } else { regb = n.voice; io = s->iosynth; } outb(0xa0 + regb, io); outb(n.fnum & 0xff, io+1); outb(0xb0 + regb, io); outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1); return 0; case FM_IOCTL_SET_VOICE: if (copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; if (v.voice >= 18) return -EINVAL; regb = op_offset[v.voice]; io = s->iosynth + ((v.op & 1) << 1); outb(0x20 + regb, io); outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) | ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1); outb(0x40 + regb, io); outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1); outb(0x60 + regb, io); outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1); outb(0x80 + regb, io); outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1); outb(0xe0 + regb, io); outb(v.waveform & 0x7, io+1); if (n.voice >= 9) { regb = n.voice - 9; io = s->iosynth+2; } else { regb = n.voice; io = s->iosynth; } outb(0xc0 + regb, io); outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) | (v.connection & 1), io+1); return 0; case FM_IOCTL_SET_PARAMS: if (copy_from_user(&p, (void *)arg, sizeof(p))) return -EFAULT; outb(0x08, s->iosynth); outb((p.kbd_split & 1) << 6, s->iosynth+1); outb(0xbd, s->iosynth); outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) | ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->iosynth+1); return 0; case FM_IOCTL_SET_OPL: outb(4, s->iosynth+2); outb(arg, s->iosynth+3); return 0; case FM_IOCTL_SET_MODE: outb(5, s->iosynth+2); outb(arg & 1, s->iosynth+3); return 0; default: return -EINVAL; }}static int cm_dmfm_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct cm_state *s = devs; while (s && s->dev_dmfm != minor) s = s->next; if (!s) return -ENODEV; VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ down(&s->open_sem); while (s->open_mode & FMODE_DMFM) { if (file->f_flags & O_NONBLOCK) { up(&s->open_sem); return -EBUSY; } up(&s->open_sem); interruptible_sleep_on(&s->open_wait); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); } /* init the stuff */ outb(1, s->iosynth); outb(0x20, s->iosynth+1); /* enable waveforms */ outb(4, s->iosynth+2); outb(0, s->iosynth+3); /* no 4op enabled */ outb(5, s->iosynth+2); outb(1, s->iosynth+3); /* enable OPL3 */ s->open_mode |= FMODE_DMFM; up(&s->open_sem); return 0;}static int cm_dmfm_release(struct inode *inode, struct file *file){ struct cm_state *s = (struct cm_state *)file->private_data; unsigned int regb; VALIDATE_STATE(s); lock_kernel(); down(&s->open_sem); s->open_mode &= ~FMODE_DMFM; for (regb = 0xb0; regb < 0xb9; regb++) { outb(regb, s->iosynth); outb(0, s->iosynth+1); outb(regb, s->iosynth+2); outb(0, s->iosynth+3); } up(&s->open_sem); wake_up(&s->open_wait); unlock_kernel(); return 0;}static /*const*/ struct file_operations cm_dmfm_fops = { owner: THIS_MODULE, llseek: cm_llseek, ioctl: cm_dmfm_ioctl, open: cm_dmfm_open, release: cm_dmfm_release,};/* --------------------------------------------------------------------- *//* maximum number of device
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -