1/* 2 ********************************************************************** 3 * cardmo.c - MIDI UART output HAL for emu10k1 driver 4 * Copyright 1999, 2000 Creative Labs, Inc. 5 * 6 ********************************************************************** 7 * 8 * Date Author Summary of changes 9 * ---- ------ ------------------ 10 * October 20, 1999 Bertrand Lee base code release 11 * November 2, 1999 Alan Cox cleaned up 12 * 13 ********************************************************************** 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License as 17 * published by the Free Software Foundation; either version 2 of 18 * the License, or (at your option) any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * You should have received a copy of the GNU General Public 26 * License along with this program; if not, write to the Free 27 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 28 * USA. 29 * 30 ********************************************************************** 31 */ 32 33#include <linux/slab.h> 34 35#include "hwaccess.h" 36#include "8010.h" 37#include "cardmo.h" 38#include "irqmgr.h" 39 40/* Installs the IRQ handler for the MPU out port * 41 * and initialize parameters */ 42 43int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinfo) 44{ 45 struct emu10k1_mpuout *card_mpuout = card->mpuout; 46 47 DPF(2, "emu10k1_mpuout_open()\n"); 48 49 if (!(card_mpuout->status & FLAGS_AVAILABLE)) 50 return -1; 51 52 /* Copy open info and mark channel as in use */ 53 card_mpuout->intr = 0; 54 card_mpuout->openinfo = *openinfo; 55 card_mpuout->status &= ~FLAGS_AVAILABLE; 56 card_mpuout->laststatus = 0x80; 57 card_mpuout->firstmidiq = NULL; 58 card_mpuout->lastmidiq = NULL; 59 60 emu10k1_mpu_reset(card); 61 emu10k1_mpu_acquire(card); 62 63 return 0; 64} 65 66int emu10k1_mpuout_close(struct emu10k1_card *card) 67{ 68 struct emu10k1_mpuout *card_mpuout = card->mpuout; 69 struct midi_queue *midiq; 70 struct midi_hdr *midihdr; 71 unsigned long flags; 72 73 DPF(2, "emu10k1_mpuout_close()\n"); 74 75 emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE); 76 77 spin_lock_irqsave(&card_mpuout->lock, flags); 78 79 while (card_mpuout->firstmidiq != NULL) { 80 midiq = card_mpuout->firstmidiq; 81 midihdr = (struct midi_hdr *) midiq->refdata; 82 83 card_mpuout->firstmidiq = midiq->next; 84 85 kfree(midihdr->data); 86 kfree(midihdr); 87 kfree(midiq); 88 } 89 90 card_mpuout->lastmidiq = NULL; 91 92 emu10k1_mpu_release(card); 93 94 card_mpuout->status |= FLAGS_AVAILABLE; 95 96 spin_unlock_irqrestore(&card_mpuout->lock, flags); 97 98 return 0; 99} 100 101/* If there isn't enough buffer space, reject Midi Buffer. * 102* Otherwise, disable TX, create object to hold Midi * 103* uffer, update buffer flags and other parameters * 104* before enabling TX again. */ 105 106int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihdr) 107{ 108 struct emu10k1_mpuout *card_mpuout = card->mpuout; 109 struct midi_queue *midiq; 110 unsigned long flags; 111 112 DPF(2, "emu10k1_mpuout_add_buffer()\n"); 113 114 if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND) 115 return 0; 116 117 midihdr->flags |= MIDIBUF_INQUEUE; 118 midihdr->flags &= ~MIDIBUF_DONE; 119 120 if ((midiq = kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) { 121 /* Message lost */ 122 return -1; 123 } 124 125 midiq->next = NULL; 126 midiq->qtype = 1; 127 midiq->length = midihdr->bufferlength; 128 midiq->sizeLeft = midihdr->bufferlength; 129 midiq->midibyte = midihdr->data; 130 131 midiq->refdata = (unsigned long) midihdr; 132 133 spin_lock_irqsave(&card_mpuout->lock, flags); 134 135 if (card_mpuout->firstmidiq == NULL) { 136 card_mpuout->firstmidiq = midiq; 137 card_mpuout->lastmidiq = midiq; 138 } else { 139 (card_mpuout->lastmidiq)->next = midiq; 140 card_mpuout->lastmidiq = midiq; 141 } 142 143 card_mpuout->intr = 0; 144 145 emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE); 146 147 spin_unlock_irqrestore(&card_mpuout->lock, flags); 148 149 return 0; 150} 151 152void emu10k1_mpuout_bh(unsigned long refdata) 153{ 154 struct emu10k1_card *card = (struct emu10k1_card *) refdata; 155 struct emu10k1_mpuout *card_mpuout = card->mpuout; 156 int cByteSent = 0; 157 struct midi_queue *midiq; 158 struct midi_queue *doneq = NULL; 159 unsigned long flags; 160 161 spin_lock_irqsave(&card_mpuout->lock, flags); 162 163 while (card_mpuout->firstmidiq != NULL) { 164 midiq = card_mpuout->firstmidiq; 165 166 while (cByteSent < 4 && midiq->sizeLeft) { 167 if (emu10k1_mpu_write_data(card, *midiq->midibyte) < 0) { 168 DPF(2, "emu10k1_mpuoutDpcCallback error!!\n"); 169 } else { 170 ++cByteSent; 171 --midiq->sizeLeft; 172 ++midiq->midibyte; 173 } 174 } 175 176 if (midiq->sizeLeft == 0) { 177 if (doneq == NULL) 178 doneq = midiq; 179 card_mpuout->firstmidiq = midiq->next; 180 } else 181 break; 182 } 183 184 if (card_mpuout->firstmidiq == NULL) 185 card_mpuout->lastmidiq = NULL; 186 187 if (doneq != NULL) { 188 while (doneq != card_mpuout->firstmidiq) { 189 unsigned long callback_msg[3]; 190 191 midiq = doneq; 192 doneq = midiq->next; 193 194 if (midiq->qtype) { 195 callback_msg[0] = 0; 196 callback_msg[1] = midiq->length; 197 callback_msg[2] = midiq->refdata; 198 199 emu10k1_midi_callback(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg); 200 } else if (((u8) midiq->refdata) < 0xF0 && ((u8) midiq->refdata) > 0x7F) 201 card_mpuout->laststatus = (u8) midiq->refdata; 202 203 kfree(midiq); 204 } 205 } 206 207 if ((card_mpuout->firstmidiq != NULL) || cByteSent) { 208 card_mpuout->intr = 0; 209 emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE); 210 } 211 212 spin_unlock_irqrestore(&card_mpuout->lock, flags); 213 214 return; 215} 216 217int emu10k1_mpuout_irqhandler(struct emu10k1_card *card) 218{ 219 struct emu10k1_mpuout *card_mpuout = card->mpuout; 220 221 DPF(4, "emu10k1_mpuout_irqhandler\n"); 222 223 card_mpuout->intr = 1; 224 emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE); 225 226 tasklet_hi_schedule(&card_mpuout->tasklet); 227 228 return 0; 229} 230