123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- /*
- **********************************************************************
- * midi.c - /dev/midi interface for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
- #include <linux/module.h>
- #include <linux/poll.h>
- #include <linux/slab.h>
- #include <linux/sched.h>
- #include <linux/smp_lock.h>
- #include <asm/uaccess.h>
- #include "hwaccess.h"
- #include "cardmo.h"
- #include "cardmi.h"
- #include "midi.h"
- #ifdef EMU10K1_SEQUENCER
- #include "../sound_config.h"
- #endif
- static DEFINE_SPINLOCK(midi_spinlock __attribute((unused)));
- static void init_midi_hdr(struct midi_hdr *midihdr)
- {
- midihdr->bufferlength = MIDIIN_BUFLEN;
- midihdr->bytesrecorded = 0;
- midihdr->flags = 0;
- }
- static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hdr **midihdrptr)
- {
- struct midi_hdr *midihdr;
- if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) {
- ERROR();
- return -EINVAL;
- }
- init_midi_hdr(midihdr);
- if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) {
- ERROR();
- kfree(midihdr);
- return -1;
- }
- if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) < 0) {
- ERROR();
- kfree(midihdr->data);
- kfree(midihdr);
- return -1;
- }
- *midihdrptr = midihdr;
- list_add_tail(&midihdr->list, &midi_dev->mid_hdrs);
- return 0;
- }
- static int emu10k1_midi_open(struct inode *inode, struct file *file)
- {
- int minor = iminor(inode);
- struct emu10k1_card *card = NULL;
- struct emu10k1_mididevice *midi_dev;
- struct list_head *entry;
- DPF(2, "emu10k1_midi_open()\n");
- /* Check for correct device to open */
- list_for_each(entry, &emu10k1_devs) {
- card = list_entry(entry, struct emu10k1_card, list);
- if (card->midi_dev == minor)
- goto match;
- }
- return -ENODEV;
- match:
- #ifdef EMU10K1_SEQUENCER
- if (card->seq_mididev) /* card is opened by sequencer */
- return -EBUSY;
- #endif
- /* Wait for device to become free */
- down(&card->open_sem);
- while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
- if (file->f_flags & O_NONBLOCK) {
- up(&card->open_sem);
- return -EBUSY;
- }
- up(&card->open_sem);
- interruptible_sleep_on(&card->open_wait);
- if (signal_pending(current)) {
- return -ERESTARTSYS;
- }
- down(&card->open_sem);
- }
- if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
- return -EINVAL;
- midi_dev->card = card;
- midi_dev->mistate = MIDIIN_STATE_STOPPED;
- init_waitqueue_head(&midi_dev->oWait);
- init_waitqueue_head(&midi_dev->iWait);
- midi_dev->ird = 0;
- midi_dev->iwr = 0;
- midi_dev->icnt = 0;
- INIT_LIST_HEAD(&midi_dev->mid_hdrs);
- if (file->f_mode & FMODE_READ) {
- struct midi_openinfo dsCardMidiOpenInfo;
- struct midi_hdr *midihdr1;
- struct midi_hdr *midihdr2;
- dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
- if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) < 0) {
- ERROR();
- kfree(midi_dev);
- return -ENODEV;
- }
- /* Add two buffers to receive sysex buffer */
- if (midiin_add_buffer(midi_dev, &midihdr1) < 0) {
- kfree(midi_dev);
- return -ENODEV;
- }
- if (midiin_add_buffer(midi_dev, &midihdr2) < 0) {
- list_del(&midihdr1->list);
- kfree(midihdr1->data);
- kfree(midihdr1);
- kfree(midi_dev);
- return -ENODEV;
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- struct midi_openinfo dsCardMidiOpenInfo;
- dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
- if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) {
- ERROR();
- kfree(midi_dev);
- return -ENODEV;
- }
- }
- file->private_data = (void *) midi_dev;
- card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
- up(&card->open_sem);
- return nonseekable_open(inode, file);
- }
- static int emu10k1_midi_release(struct inode *inode, struct file *file)
- {
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
- struct emu10k1_card *card;
- lock_kernel();
- card = midi_dev->card;
- DPF(2, "emu10k1_midi_release()\n");
- if (file->f_mode & FMODE_WRITE) {
- if (!(file->f_flags & O_NONBLOCK)) {
- while (!signal_pending(current) && (card->mpuout->firstmidiq != NULL)) {
- DPF(4, "Cannot close - buffers not empty\n");
- interruptible_sleep_on(&midi_dev->oWait);
- }
- }
- emu10k1_mpuout_close(card);
- }
- if (file->f_mode & FMODE_READ) {
- struct midi_hdr *midihdr;
- if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
- emu10k1_mpuin_stop(card);
- midi_dev->mistate = MIDIIN_STATE_STOPPED;
- }
- emu10k1_mpuin_reset(card);
- emu10k1_mpuin_close(card);
- while (!list_empty(&midi_dev->mid_hdrs)) {
- midihdr = list_entry(midi_dev->mid_hdrs.next, struct midi_hdr, list);
- list_del(midi_dev->mid_hdrs.next);
- kfree(midihdr->data);
- kfree(midihdr);
- }
- }
- kfree(midi_dev);
- down(&card->open_sem);
- card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
- up(&card->open_sem);
- wake_up_interruptible(&card->open_wait);
- unlock_kernel();
- return 0;
- }
- static ssize_t emu10k1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t * pos)
- {
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
- ssize_t ret = 0;
- u16 cnt;
- unsigned long flags;
- DPD(4, "emu10k1_midi_read(), count %#x\n", (u32) count);
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- if (midi_dev->mistate == MIDIIN_STATE_STOPPED) {
- if (emu10k1_mpuin_start(midi_dev->card) < 0) {
- ERROR();
- return -EINVAL;
- }
- midi_dev->mistate = MIDIIN_STATE_STARTED;
- }
- while (count > 0) {
- cnt = MIDIIN_BUFLEN - midi_dev->ird;
- spin_lock_irqsave(&midi_spinlock, flags);
- if (midi_dev->icnt < cnt)
- cnt = midi_dev->icnt;
- spin_unlock_irqrestore(&midi_spinlock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- DPF(2, " Go to sleep...\n");
- interruptible_sleep_on(&midi_dev->iWait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) {
- ERROR();
- return ret ? ret : -EFAULT;
- }
- midi_dev->ird += cnt;
- midi_dev->ird %= MIDIIN_BUFLEN;
- spin_lock_irqsave(&midi_spinlock, flags);
- midi_dev->icnt -= cnt;
- spin_unlock_irqrestore(&midi_spinlock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (midi_dev->icnt == 0)
- break;
- }
- return ret;
- }
- static ssize_t emu10k1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t * pos)
- {
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
- struct midi_hdr *midihdr;
- unsigned long flags;
- DPD(4, "emu10k1_midi_write(), count=%#x\n", (u32) count);
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
- return -EINVAL;
- midihdr->bufferlength = count;
- midihdr->bytesrecorded = 0;
- midihdr->flags = 0;
- if ((midihdr->data = (u8 *) kmalloc(count, GFP_KERNEL)) == NULL) {
- ERROR();
- kfree(midihdr);
- return -EINVAL;
- }
- if (copy_from_user(midihdr->data, buffer, count)) {
- kfree(midihdr->data);
- kfree(midihdr);
- return -EFAULT;
- }
- spin_lock_irqsave(&midi_spinlock, flags);
- if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) < 0) {
- ERROR();
- kfree(midihdr->data);
- kfree(midihdr);
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return count;
- }
- static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait)
- {
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
- DPF(4, "emu10k1_midi_poll() called\n");
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &midi_dev->oWait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &midi_dev->iWait, wait);
- spin_lock_irqsave(&midi_spinlock, flags);
- if (file->f_mode & FMODE_WRITE)
- mask |= POLLOUT | POLLWRNORM;
- if (file->f_mode & FMODE_READ) {
- if (midi_dev->mistate == MIDIIN_STATE_STARTED)
- if (midi_dev->icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return mask;
- }
- int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
- {
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) refdata;
- struct midi_hdr *midihdr = NULL;
- unsigned long flags;
- int i;
- DPF(4, "emu10k1_midi_callback()\n");
- spin_lock_irqsave(&midi_spinlock, flags);
- switch (msg) {
- case ICARDMIDI_OUTLONGDATA:
- midihdr = (struct midi_hdr *) pmsg[2];
- kfree(midihdr->data);
- kfree(midihdr);
- wake_up_interruptible(&midi_dev->oWait);
- break;
- case ICARDMIDI_INLONGDATA:
- midihdr = (struct midi_hdr *) pmsg[2];
- for (i = 0; i < midihdr->bytesrecorded; i++) {
- midi_dev->iBuf[midi_dev->iwr++] = midihdr->data[i];
- midi_dev->iwr %= MIDIIN_BUFLEN;
- }
- midi_dev->icnt += midihdr->bytesrecorded;
- if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
- init_midi_hdr(midihdr);
- emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr);
- wake_up_interruptible(&midi_dev->iWait);
- }
- break;
- case ICARDMIDI_INDATA:
- {
- u8 *pBuf = (u8 *) & pmsg[1];
- u16 bytesvalid = pmsg[2];
- for (i = 0; i < bytesvalid; i++) {
- midi_dev->iBuf[midi_dev->iwr++] = pBuf[i];
- midi_dev->iwr %= MIDIIN_BUFLEN;
- }
- midi_dev->icnt += bytesvalid;
- }
- wake_up_interruptible(&midi_dev->iWait);
- break;
- default: /* Unknown message */
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return -1;
- }
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return 0;
- }
- /* MIDI file operations */
- struct file_operations emu10k1_midi_fops = {
- .owner = THIS_MODULE,
- .read = emu10k1_midi_read,
- .write = emu10k1_midi_write,
- .poll = emu10k1_midi_poll,
- .open = emu10k1_midi_open,
- .release = emu10k1_midi_release,
- };
- #ifdef EMU10K1_SEQUENCER
- /* functions used for sequencer access */
- int emu10k1_seq_midi_open(int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev))
- {
- struct emu10k1_card *card;
- struct midi_openinfo dsCardMidiOpenInfo;
- struct emu10k1_mididevice *midi_dev;
- if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
- return -EINVAL;
- card = midi_devs[dev]->devc;
- if (card->open_mode) /* card is opened native */
- return -EBUSY;
-
- DPF(2, "emu10k1_seq_midi_open()\n");
-
- if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
- return -EINVAL;
- midi_dev->card = card;
- midi_dev->mistate = MIDIIN_STATE_STOPPED;
- init_waitqueue_head(&midi_dev->oWait);
- init_waitqueue_head(&midi_dev->iWait);
- midi_dev->ird = 0;
- midi_dev->iwr = 0;
- midi_dev->icnt = 0;
- INIT_LIST_HEAD(&midi_dev->mid_hdrs);
- dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
- if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) {
- ERROR();
- return -ENODEV;
- }
- card->seq_mididev = midi_dev;
-
- return 0;
- }
- void emu10k1_seq_midi_close(int dev)
- {
- struct emu10k1_card *card;
- DPF(2, "emu10k1_seq_midi_close()\n");
- if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
- return;
- card = midi_devs[dev]->devc;
- emu10k1_mpuout_close(card);
- kfree(card->seq_mididev);
- card->seq_mididev = NULL;
- }
- int emu10k1_seq_midi_out(int dev, unsigned char midi_byte)
- {
- struct emu10k1_card *card;
- struct midi_hdr *midihdr;
- unsigned long flags;
- if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
- return -EINVAL;
- card = midi_devs[dev]->devc;
- if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
- return -EINVAL;
- midihdr->bufferlength = 1;
- midihdr->bytesrecorded = 0;
- midihdr->flags = 0;
- if ((midihdr->data = (u8 *) kmalloc(1, GFP_KERNEL)) == NULL) {
- ERROR();
- kfree(midihdr);
- return -EINVAL;
- }
- *(midihdr->data) = midi_byte;
-
- spin_lock_irqsave(&midi_spinlock, flags);
- if (emu10k1_mpuout_add_buffer(card, midihdr) < 0) {
- ERROR();
- kfree(midihdr->data);
- kfree(midihdr);
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return 1;
- }
- int emu10k1_seq_midi_start_read(int dev)
- {
- return 0;
- }
- int emu10k1_seq_midi_end_read(int dev)
- {
- return 0;
- }
- void emu10k1_seq_midi_kick(int dev)
- {
- }
- int emu10k1_seq_midi_buffer_status(int dev)
- {
- int count;
- struct midi_queue *queue;
- struct emu10k1_card *card;
- if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
- return -EINVAL;
- count = 0;
- card = midi_devs[dev]->devc;
- queue = card->mpuout->firstmidiq;
- while (queue != NULL) {
- count++;
- if (queue == card->mpuout->lastmidiq)
- break;
- queue = queue->next;
- }
- return count;
- }
- #endif
|