Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[pandora-kernel.git] / sound / pci / emu10k1 / emumpu401.c
1 /*
2  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
3  *  Routines for control of EMU10K1 MPU-401 in UART mode
4  *
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
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
30 static 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
39 static 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
60 static 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                 snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
68 #endif
69 }
70
71 /*
72
73  */
74
75 static void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, unsigned int status)
76 {
77         unsigned char byte;
78
79         if (midi->rmidi == NULL) {
80                 snd_emu10k1_intr_disable(emu, midi->tx_enable | midi->rx_enable);
81                 return;
82         }
83
84         spin_lock(&midi->input_lock);
85         if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
86                 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
87                         mpu401_clear_rx(emu, midi);
88                 } else {
89                         byte = mpu401_read_data(emu, midi);
90                         if (midi->substream_input)
91                                 snd_rawmidi_receive(midi->substream_input, &byte, 1);
92                 }
93         }
94         spin_unlock(&midi->input_lock);
95
96         spin_lock(&midi->output_lock);
97         if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
98                 if (midi->substream_output &&
99                     snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
100                         mpu401_write_data(emu, midi, byte);
101                 } else {
102                         snd_emu10k1_intr_disable(emu, midi->tx_enable);
103                 }
104         }
105         spin_unlock(&midi->output_lock);
106 }
107
108 static void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status)
109 {
110         do_emu10k1_midi_interrupt(emu, &emu->midi, status);
111 }
112
113 static void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int status)
114 {
115         do_emu10k1_midi_interrupt(emu, &emu->midi2, status);
116 }
117
118 static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack)
119 {
120         unsigned long flags;
121         int timeout, ok;
122
123         spin_lock_irqsave(&midi->input_lock, flags);
124         mpu401_write_data(emu, midi, 0x00);
125         /* mpu401_clear_rx(emu, midi); */
126
127         mpu401_write_cmd(emu, midi, cmd);
128         if (ack) {
129                 ok = 0;
130                 timeout = 10000;
131                 while (!ok && timeout-- > 0) {
132                         if (mpu401_input_avail(emu, midi)) {
133                                 if (mpu401_read_data(emu, midi) == MPU401_ACK)
134                                         ok = 1;
135                         }
136                 }
137                 if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
138                         ok = 1;
139         } else {
140                 ok = 1;
141         }
142         spin_unlock_irqrestore(&midi->input_lock, flags);
143         if (!ok) {
144                 snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
145                            cmd, emu->port,
146                            mpu401_read_stat(emu, midi),
147                            mpu401_read_data(emu, midi));
148                 return 1;
149         }
150         return 0;
151 }
152
153 static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream)
154 {
155         struct snd_emu10k1 *emu;
156         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
157         unsigned long flags;
158
159         emu = midi->emu;
160         if (snd_BUG_ON(!emu))
161                 return -ENXIO;
162         spin_lock_irqsave(&midi->open_lock, flags);
163         midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT;
164         midi->substream_input = substream;
165         if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
166                 spin_unlock_irqrestore(&midi->open_lock, flags);
167                 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
168                         goto error_out;
169                 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
170                         goto error_out;
171         } else {
172                 spin_unlock_irqrestore(&midi->open_lock, flags);
173         }
174         return 0;
175
176 error_out:
177         return -EIO;
178 }
179
180 static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream)
181 {
182         struct snd_emu10k1 *emu;
183         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
184         unsigned long flags;
185
186         emu = midi->emu;
187         if (snd_BUG_ON(!emu))
188                 return -ENXIO;
189         spin_lock_irqsave(&midi->open_lock, flags);
190         midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT;
191         midi->substream_output = substream;
192         if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
193                 spin_unlock_irqrestore(&midi->open_lock, flags);
194                 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
195                         goto error_out;
196                 if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
197                         goto error_out;
198         } else {
199                 spin_unlock_irqrestore(&midi->open_lock, flags);
200         }
201         return 0;
202
203 error_out:
204         return -EIO;
205 }
206
207 static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream)
208 {
209         struct snd_emu10k1 *emu;
210         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
211         unsigned long flags;
212         int err = 0;
213
214         emu = midi->emu;
215         if (snd_BUG_ON(!emu))
216                 return -ENXIO;
217         spin_lock_irqsave(&midi->open_lock, flags);
218         snd_emu10k1_intr_disable(emu, midi->rx_enable);
219         midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT;
220         midi->substream_input = NULL;
221         if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
222                 spin_unlock_irqrestore(&midi->open_lock, flags);
223                 err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
224         } else {
225                 spin_unlock_irqrestore(&midi->open_lock, flags);
226         }
227         return err;
228 }
229
230 static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream)
231 {
232         struct snd_emu10k1 *emu;
233         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
234         unsigned long flags;
235         int err = 0;
236
237         emu = midi->emu;
238         if (snd_BUG_ON(!emu))
239                 return -ENXIO;
240         spin_lock_irqsave(&midi->open_lock, flags);
241         snd_emu10k1_intr_disable(emu, midi->tx_enable);
242         midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT;
243         midi->substream_output = NULL;
244         if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
245                 spin_unlock_irqrestore(&midi->open_lock, flags);
246                 err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
247         } else {
248                 spin_unlock_irqrestore(&midi->open_lock, flags);
249         }
250         return err;
251 }
252
253 static void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
254 {
255         struct snd_emu10k1 *emu;
256         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
257         emu = midi->emu;
258         if (snd_BUG_ON(!emu))
259                 return;
260
261         if (up)
262                 snd_emu10k1_intr_enable(emu, midi->rx_enable);
263         else
264                 snd_emu10k1_intr_disable(emu, midi->rx_enable);
265 }
266
267 static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
268 {
269         struct snd_emu10k1 *emu;
270         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
271         unsigned long flags;
272
273         emu = midi->emu;
274         if (snd_BUG_ON(!emu))
275                 return;
276
277         if (up) {
278                 int max = 4;
279                 unsigned char byte;
280         
281                 /* try to send some amount of bytes here before interrupts */
282                 spin_lock_irqsave(&midi->output_lock, flags);
283                 while (max > 0) {
284                         if (mpu401_output_ready(emu, midi)) {
285                                 if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) ||
286                                     snd_rawmidi_transmit(substream, &byte, 1) != 1) {
287                                         /* no more data */
288                                         spin_unlock_irqrestore(&midi->output_lock, flags);
289                                         return;
290                                 }
291                                 mpu401_write_data(emu, midi, byte);
292                                 max--;
293                         } else {
294                                 break;
295                         }
296                 }
297                 spin_unlock_irqrestore(&midi->output_lock, flags);
298                 snd_emu10k1_intr_enable(emu, midi->tx_enable);
299         } else {
300                 snd_emu10k1_intr_disable(emu, midi->tx_enable);
301         }
302 }
303
304 /*
305
306  */
307
308 static struct snd_rawmidi_ops snd_emu10k1_midi_output =
309 {
310         .open =         snd_emu10k1_midi_output_open,
311         .close =        snd_emu10k1_midi_output_close,
312         .trigger =      snd_emu10k1_midi_output_trigger,
313 };
314
315 static struct snd_rawmidi_ops snd_emu10k1_midi_input =
316 {
317         .open =         snd_emu10k1_midi_input_open,
318         .close =        snd_emu10k1_midi_input_close,
319         .trigger =      snd_emu10k1_midi_input_trigger,
320 };
321
322 static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
323 {
324         struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
325         midi->interrupt = NULL;
326         midi->rmidi = NULL;
327 }
328
329 static int __devinit emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name)
330 {
331         struct snd_rawmidi *rmidi;
332         int err;
333
334         if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0)
335                 return err;
336         midi->emu = emu;
337         spin_lock_init(&midi->open_lock);
338         spin_lock_init(&midi->input_lock);
339         spin_lock_init(&midi->output_lock);
340         strcpy(rmidi->name, name);
341         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output);
342         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input);
343         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
344                              SNDRV_RAWMIDI_INFO_INPUT |
345                              SNDRV_RAWMIDI_INFO_DUPLEX;
346         rmidi->private_data = midi;
347         rmidi->private_free = snd_emu10k1_midi_free;
348         midi->rmidi = rmidi;
349         return 0;
350 }
351
352 int __devinit snd_emu10k1_midi(struct snd_emu10k1 *emu)
353 {
354         struct snd_emu10k1_midi *midi = &emu->midi;
355         int err;
356
357         if ((err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)")) < 0)
358                 return err;
359
360         midi->tx_enable = INTE_MIDITXENABLE;
361         midi->rx_enable = INTE_MIDIRXENABLE;
362         midi->port = MUDATA;
363         midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
364         midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
365         midi->interrupt = snd_emu10k1_midi_interrupt;
366         return 0;
367 }
368
369 int __devinit snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu)
370 {
371         struct snd_emu10k1_midi *midi;
372         int err;
373
374         midi = &emu->midi;
375         if ((err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)")) < 0)
376                 return err;
377
378         midi->tx_enable = INTE_MIDITXENABLE;
379         midi->rx_enable = INTE_MIDIRXENABLE;
380         midi->port = A_MUDATA1;
381         midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
382         midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
383         midi->interrupt = snd_emu10k1_midi_interrupt;
384
385         midi = &emu->midi2;
386         if ((err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2")) < 0)
387                 return err;
388
389         midi->tx_enable = INTE_A_MIDITXENABLE2;
390         midi->rx_enable = INTE_A_MIDIRXENABLE2;
391         midi->port = A_MUDATA2;
392         midi->ipr_tx = IPR_A_MIDITRANSBUFEMPTY2;
393         midi->ipr_rx = IPR_A_MIDIRECVBUFEMPTY2;
394         midi->interrupt = snd_emu10k1_midi_interrupt2;
395         return 0;
396 }