Viewing file: cardmo.c (6 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* ********************************************************************** * cardmo.c - MIDI UART output HAL for emu10k1 driver * Copyright 1999, 2000 Creative Labs, Inc. * ********************************************************************** * * Date Author Summary of changes * ---- ------ ------------------ * October 20, 1999 Bertrand Lee base code release * November 2, 1999 Alan Cox cleaned up * ********************************************************************** * * 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/slab.h>
#include "hwaccess.h" #include "8010.h" #include "cardmo.h" #include "irqmgr.h"
/* Installs the IRQ handler for the MPU out port * * and initialize parameters */
int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinfo) { struct emu10k1_mpuout *card_mpuout = card->mpuout;
DPF(2, "emu10k1_mpuout_open()\n");
if (!(card_mpuout->status & FLAGS_AVAILABLE)) return -1;
/* Copy open info and mark channel as in use */ card_mpuout->intr = 0; card_mpuout->openinfo = *openinfo; card_mpuout->status &= ~FLAGS_AVAILABLE; card_mpuout->laststatus = 0x80; card_mpuout->firstmidiq = NULL; card_mpuout->lastmidiq = NULL;
emu10k1_mpu_reset(card); emu10k1_mpu_acquire(card);
return 0; }
int emu10k1_mpuout_close(struct emu10k1_card *card) { struct emu10k1_mpuout *card_mpuout = card->mpuout; struct midi_queue *midiq; struct midi_hdr *midihdr; unsigned long flags;
DPF(2, "emu10k1_mpuout_close()\n");
emu10k1_irq_disable(card, INTE_MIDITXENABLE);
spin_lock_irqsave(&card_mpuout->lock, flags);
while (card_mpuout->firstmidiq != NULL) { midiq = card_mpuout->firstmidiq; midihdr = (struct midi_hdr *) midiq->refdata;
card_mpuout->firstmidiq = midiq->next;
kfree(midihdr->data); kfree(midihdr); kfree(midiq); }
card_mpuout->lastmidiq = NULL;
emu10k1_mpu_release(card);
card_mpuout->status |= FLAGS_AVAILABLE;
spin_unlock_irqrestore(&card_mpuout->lock, flags);
return 0; }
/* If there isn't enough buffer space, reject Midi Buffer. * * Otherwise, disable TX, create object to hold Midi * * uffer, update buffer flags and other parameters * * before enabling TX again. */
int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihdr) { struct emu10k1_mpuout *card_mpuout = card->mpuout; struct midi_queue *midiq; unsigned long flags;
DPF(2, "emu10k1_mpuout_add_buffer()\n");
if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND) return 0;
midihdr->flags |= MIDIBUF_INQUEUE; midihdr->flags &= ~MIDIBUF_DONE;
if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) { /* Message lost */ return -1; }
midiq->next = NULL; midiq->qtype = 1; midiq->length = midihdr->bufferlength; midiq->sizeLeft = midihdr->bufferlength; midiq->midibyte = midihdr->data;
midiq->refdata = (unsigned long) midihdr;
spin_lock_irqsave(&card_mpuout->lock, flags);
if (card_mpuout->firstmidiq == NULL) { card_mpuout->firstmidiq = midiq; card_mpuout->lastmidiq = midiq; } else { (card_mpuout->lastmidiq)->next = midiq; card_mpuout->lastmidiq = midiq; }
card_mpuout->intr = 0;
emu10k1_irq_enable(card, INTE_MIDITXENABLE);
spin_unlock_irqrestore(&card_mpuout->lock, flags);
return 0; }
void emu10k1_mpuout_bh(unsigned long refdata) { struct emu10k1_card *card = (struct emu10k1_card *) refdata; struct emu10k1_mpuout *card_mpuout = card->mpuout; int cByteSent = 0; struct midi_queue *midiq; struct midi_queue *doneq = NULL; unsigned long flags;
spin_lock_irqsave(&card_mpuout->lock, flags);
while (card_mpuout->firstmidiq != NULL) { midiq = card_mpuout->firstmidiq;
while (cByteSent < 4 && midiq->sizeLeft) { if (emu10k1_mpu_write_data(card, *midiq->midibyte) < 0) { DPF(2, "emu10k1_mpuoutDpcCallback error!!\n"); } else { ++cByteSent; --midiq->sizeLeft; ++midiq->midibyte; } }
if (midiq->sizeLeft == 0) { if (doneq == NULL) doneq = midiq; card_mpuout->firstmidiq = midiq->next; } else break; }
if (card_mpuout->firstmidiq == NULL) card_mpuout->lastmidiq = NULL;
if (doneq != NULL) { while (doneq != card_mpuout->firstmidiq) { unsigned long callback_msg[3];
midiq = doneq; doneq = midiq->next;
if (midiq->qtype) { callback_msg[0] = 0; callback_msg[1] = midiq->length; callback_msg[2] = midiq->refdata;
emu10k1_midi_callback(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg); } else if (((u8) midiq->refdata) < 0xF0 && ((u8) midiq->refdata) > 0x7F) card_mpuout->laststatus = (u8) midiq->refdata;
kfree(midiq); } }
if ((card_mpuout->firstmidiq != NULL) || cByteSent) { card_mpuout->intr = 0; emu10k1_irq_enable(card, INTE_MIDITXENABLE); }
spin_unlock_irqrestore(&card_mpuout->lock, flags);
return; }
int emu10k1_mpuout_irqhandler(struct emu10k1_card *card) { struct emu10k1_mpuout *card_mpuout = card->mpuout;
DPF(4, "emu10k1_mpuout_irqhandler\n");
card_mpuout->intr = 1; emu10k1_irq_disable(card, INTE_MIDITXENABLE);
tasklet_hi_schedule(&card_mpuout->tasklet);
return 0; }
|