1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/time.h>
23#include <linux/init.h>
24#include <sound/core.h>
25#include <sound/emu10k1.h>
26
27#define EMU10K1_MIDI_MODE_INPUT (1<<0)
28#define EMU10K1_MIDI_MODE_OUTPUT (1<<1)
29
30static inline unsigned char mpu401_read(struct snd_emu10k1 *emu,
31 struct snd_emu10k1_midi *mpu, int idx)
32{
33 if (emu->audigy)
34 return (unsigned char)snd_emu10k1_ptr_read(emu, mpu->port + idx, 0);
35 else
36 return inb(emu->port + mpu->port + idx);
37}
38
39static inline void mpu401_write(struct snd_emu10k1 *emu,
40 struct snd_emu10k1_midi *mpu, int data, int idx)
41{
42 if (emu->audigy)
43 snd_emu10k1_ptr_write(emu, mpu->port + idx, 0, data);
44 else
45 outb(data, emu->port + mpu->port + idx);
46}
47
48#define mpu401_write_data(emu, mpu, data) mpu401_write(emu, mpu, data, 0)
49#define mpu401_write_cmd(emu, mpu, data) mpu401_write(emu, mpu, data, 1)
50#define mpu401_read_data(emu, mpu) mpu401_read(emu, mpu, 0)
51#define mpu401_read_stat(emu, mpu) mpu401_read(emu, mpu, 1)
52
53#define mpu401_input_avail(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x80))
54#define mpu401_output_ready(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x40))
55
56#define MPU401_RESET 0xff
57#define MPU401_ENTER_UART 0x3f
58#define MPU401_ACK 0xfe
59
60static void mpu401_clear_rx(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *mpu)
61{
62 int timeout = 100000;
63 for (; timeout > 0 && mpu401_input_avail(emu, mpu); timeout--)
64 mpu401_read_data(emu, mpu);
65#ifdef CONFIG_SND_DEBUG
66 if (timeout <= 0)
67 dev_err(emu->card->dev,
68 "cmd: clear rx timeout (status = 0x%x)\n",
69 mpu401_read_stat(emu, mpu));
70#endif
71}
72
73
74
75
76
77static void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, unsigned int status)
78{
79 unsigned char byte;
80
81 if (midi->rmidi == NULL) {
82 snd_emu10k1_intr_disable(emu, midi->tx_enable | midi->rx_enable);
83 return;
84 }
85
86 spin_lock(&midi->input_lock);
87 if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
88 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
89 mpu401_clear_rx(emu, midi);
90 } else {
91 byte = mpu401_read_data(emu, midi);
92 if (midi->substream_input)
93 snd_rawmidi_receive(midi->substream_input, &byte, 1);
94 }
95 }
96 spin_unlock(&midi->input_lock);
97
98 spin_lock(&midi->output_lock);
99 if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
100 if (midi->substream_output &&
101 snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
102 mpu401_write_data(emu, midi, byte);
103 } else {
104 snd_emu10k1_intr_disable(emu, midi->tx_enable);
105 }
106 }
107 spin_unlock(&midi->output_lock);
108}
109
110static void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status)
111{
112 do_emu10k1_midi_interrupt(emu, &emu->midi, status);
113}
114
115static void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int status)
116{
117 do_emu10k1_midi_interrupt(emu, &emu->midi2, status);
118}
119
120static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack)
121{
122 unsigned long flags;
123 int timeout, ok;
124
125 spin_lock_irqsave(&midi->input_lock, flags);
126 mpu401_write_data(emu, midi, 0x00);
127
128
129 mpu401_write_cmd(emu, midi, cmd);
130 if (ack) {
131 ok = 0;
132 timeout = 10000;
133 while (!ok && timeout-- > 0) {
134 if (mpu401_input_avail(emu, midi)) {
135 if (mpu401_read_data(emu, midi) == MPU401_ACK)
136 ok = 1;
137 }
138 }
139 if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
140 ok = 1;
141 } else {
142 ok = 1;
143 }
144 spin_unlock_irqrestore(&midi->input_lock, flags);
145 if (!ok) {
146 dev_err(emu->card->dev,
147 "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
148 cmd, emu->port,
149 mpu401_read_stat(emu, midi),
150 mpu401_read_data(emu, midi));
151 return 1;
152 }
153 return 0;
154}
155
156static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream)
157{
158 struct snd_emu10k1 *emu;
159 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
160 unsigned long flags;
161
162 emu = midi->emu;
163 if (snd_BUG_ON(!emu))
164 return -ENXIO;
165 spin_lock_irqsave(&midi->open_lock, flags);
166 midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT;
167 midi->substream_input = substream;
168 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
169 spin_unlock_irqrestore(&midi->open_lock, flags);
170 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
171 goto error_out;
172 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
173 goto error_out;
174 } else {
175 spin_unlock_irqrestore(&midi->open_lock, flags);
176 }
177 return 0;
178
179error_out:
180 return -EIO;
181}
182
183static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream)
184{
185 struct snd_emu10k1 *emu;
186 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
187 unsigned long flags;
188
189 emu = midi->emu;
190 if (snd_BUG_ON(!emu))
191 return -ENXIO;
192 spin_lock_irqsave(&midi->open_lock, flags);
193 midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT;
194 midi->substream_output = substream;
195 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
196 spin_unlock_irqrestore(&midi->open_lock, flags);
197 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
198 goto error_out;
199 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
200 goto error_out;
201 } else {
202 spin_unlock_irqrestore(&midi->open_lock, flags);
203 }
204 return 0;
205
206error_out:
207 return -EIO;
208}
209
210static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream)
211{
212 struct snd_emu10k1 *emu;
213 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
214 unsigned long flags;
215 int err = 0;
216
217 emu = midi->emu;
218 if (snd_BUG_ON(!emu))
219 return -ENXIO;
220 spin_lock_irqsave(&midi->open_lock, flags);
221 snd_emu10k1_intr_disable(emu, midi->rx_enable);
222 midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT;
223 midi->substream_input = NULL;
224 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
225 spin_unlock_irqrestore(&midi->open_lock, flags);
226 err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
227 } else {
228 spin_unlock_irqrestore(&midi->open_lock, flags);
229 }
230 return err;
231}
232
233static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream)
234{
235 struct snd_emu10k1 *emu;
236 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
237 unsigned long flags;
238 int err = 0;
239
240 emu = midi->emu;
241 if (snd_BUG_ON(!emu))
242 return -ENXIO;
243 spin_lock_irqsave(&midi->open_lock, flags);
244 snd_emu10k1_intr_disable(emu, midi->tx_enable);
245 midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT;
246 midi->substream_output = NULL;
247 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
248 spin_unlock_irqrestore(&midi->open_lock, flags);
249 err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
250 } else {
251 spin_unlock_irqrestore(&midi->open_lock, flags);
252 }
253 return err;
254}
255
256static void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
257{
258 struct snd_emu10k1 *emu;
259 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
260 emu = midi->emu;
261 if (snd_BUG_ON(!emu))
262 return;
263
264 if (up)
265 snd_emu10k1_intr_enable(emu, midi->rx_enable);
266 else
267 snd_emu10k1_intr_disable(emu, midi->rx_enable);
268}
269
270static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
271{
272 struct snd_emu10k1 *emu;
273 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
274 unsigned long flags;
275
276 emu = midi->emu;
277 if (snd_BUG_ON(!emu))
278 return;
279
280 if (up) {
281 int max = 4;
282 unsigned char byte;
283
284
285 spin_lock_irqsave(&midi->output_lock, flags);
286 while (max > 0) {
287 if (mpu401_output_ready(emu, midi)) {
288 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) ||
289 snd_rawmidi_transmit(substream, &byte, 1) != 1) {
290
291 spin_unlock_irqrestore(&midi->output_lock, flags);
292 return;
293 }
294 mpu401_write_data(emu, midi, byte);
295 max--;
296 } else {
297 break;
298 }
299 }
300 spin_unlock_irqrestore(&midi->output_lock, flags);
301 snd_emu10k1_intr_enable(emu, midi->tx_enable);
302 } else {
303 snd_emu10k1_intr_disable(emu, midi->tx_enable);
304 }
305}
306
307
308
309
310
311static const struct snd_rawmidi_ops snd_emu10k1_midi_output =
312{
313 .open = snd_emu10k1_midi_output_open,
314 .close = snd_emu10k1_midi_output_close,
315 .trigger = snd_emu10k1_midi_output_trigger,
316};
317
318static const struct snd_rawmidi_ops snd_emu10k1_midi_input =
319{
320 .open = snd_emu10k1_midi_input_open,
321 .close = snd_emu10k1_midi_input_close,
322 .trigger = snd_emu10k1_midi_input_trigger,
323};
324
325static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
326{
327 struct snd_emu10k1_midi *midi = rmidi->private_data;
328 midi->interrupt = NULL;
329 midi->rmidi = NULL;
330}
331
332static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name)
333{
334 struct snd_rawmidi *rmidi;
335 int err;
336
337 if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0)
338 return err;
339 midi->emu = emu;
340 spin_lock_init(&midi->open_lock);
341 spin_lock_init(&midi->input_lock);
342 spin_lock_init(&midi->output_lock);
343 strcpy(rmidi->name, name);
344 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output);
345 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input);
346 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
347 SNDRV_RAWMIDI_INFO_INPUT |
348 SNDRV_RAWMIDI_INFO_DUPLEX;
349 rmidi->private_data = midi;
350 rmidi->private_free = snd_emu10k1_midi_free;
351 midi->rmidi = rmidi;
352 return 0;
353}
354
355int snd_emu10k1_midi(struct snd_emu10k1 *emu)
356{
357 struct snd_emu10k1_midi *midi = &emu->midi;
358 int err;
359
360 if ((err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)")) < 0)
361 return err;
362
363 midi->tx_enable = INTE_MIDITXENABLE;
364 midi->rx_enable = INTE_MIDIRXENABLE;
365 midi->port = MUDATA;
366 midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
367 midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
368 midi->interrupt = snd_emu10k1_midi_interrupt;
369 return 0;
370}
371
372int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu)
373{
374 struct snd_emu10k1_midi *midi;
375 int err;
376
377 midi = &emu->midi;
378 if ((err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)")) < 0)
379 return err;
380
381 midi->tx_enable = INTE_MIDITXENABLE;
382 midi->rx_enable = INTE_MIDIRXENABLE;
383 midi->port = A_MUDATA1;
384 midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
385 midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
386 midi->interrupt = snd_emu10k1_midi_interrupt;
387
388 midi = &emu->midi2;
389 if ((err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2")) < 0)
390 return err;
391
392 midi->tx_enable = INTE_A_MIDITXENABLE2;
393 midi->rx_enable = INTE_A_MIDIRXENABLE2;
394 midi->port = A_MUDATA2;
395 midi->ipr_tx = IPR_A_MIDITRANSBUFEMPTY2;
396 midi->ipr_rx = IPR_A_MIDIRECVBUFEMPTY2;
397 midi->interrupt = snd_emu10k1_midi_interrupt2;
398 return 0;
399}
400