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 
emu10k1_mpuout_open(struct emu10k1_card * card,struct midi_openinfo * openinfo)43 int 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 
emu10k1_mpuout_close(struct emu10k1_card * card)66 int 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, 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 
emu10k1_mpuout_add_buffer(struct emu10k1_card * card,struct midi_hdr * midihdr)106 int 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 = (struct midi_queue *) 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, INTE_MIDITXENABLE);
146 
147 	spin_unlock_irqrestore(&card_mpuout->lock, flags);
148 
149 	return 0;
150 }
151 
emu10k1_mpuout_bh(unsigned long refdata)152 void 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, INTE_MIDITXENABLE);
210 	}
211 
212 	spin_unlock_irqrestore(&card_mpuout->lock, flags);
213 
214 	return;
215 }
216 
emu10k1_mpuout_irqhandler(struct emu10k1_card * card)217 int 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, INTE_MIDITXENABLE);
225 
226 	tasklet_hi_schedule(&card_mpuout->tasklet);
227 
228 	return 0;
229 }
230