]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - sound/pci/emu10k1/emumpu401.c
Merge tag 'xtensa-20161219' of git://github.com/jcmvbkbc/linux-xtensa
[mirror_ubuntu-zesty-kernel.git] / sound / pci / emu10k1 / emumpu401.c
CommitLineData
1da177e4 1/*
c1017a4c 2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
1da177e4
LT
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
1da177e4
LT
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
eb4698f3
TI
30static inline unsigned char mpu401_read(struct snd_emu10k1 *emu,
31 struct snd_emu10k1_midi *mpu, int idx)
1da177e4
LT
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
eb4698f3
TI
39static inline void mpu401_write(struct snd_emu10k1 *emu,
40 struct snd_emu10k1_midi *mpu, int data, int idx)
1da177e4
LT
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
eb4698f3 60static void mpu401_clear_rx(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *mpu)
1da177e4
LT
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)
6f002b02
TI
67 dev_err(emu->card->dev,
68 "cmd: clear rx timeout (status = 0x%x)\n",
69 mpu401_read_stat(emu, mpu));
1da177e4
LT
70#endif
71}
72
73/*
74
75 */
76
eb4698f3 77static void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, unsigned int status)
1da177e4
LT
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
eb4698f3 110static void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status)
1da177e4
LT
111{
112 do_emu10k1_midi_interrupt(emu, &emu->midi, status);
113}
114
eb4698f3 115static void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int status)
1da177e4
LT
116{
117 do_emu10k1_midi_interrupt(emu, &emu->midi2, status);
118}
119
b130807d 120static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack)
1da177e4
LT
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 /* mpu401_clear_rx(emu, midi); */
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);
b130807d 145 if (!ok) {
6f002b02
TI
146 dev_err(emu->card->dev,
147 "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
1da177e4
LT
148 cmd, emu->port,
149 mpu401_read_stat(emu, midi),
150 mpu401_read_data(emu, midi));
b130807d
RD
151 return 1;
152 }
153 return 0;
1da177e4
LT
154}
155
eb4698f3 156static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream)
1da177e4 157{
eb4698f3
TI
158 struct snd_emu10k1 *emu;
159 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
1da177e4
LT
160 unsigned long flags;
161
162 emu = midi->emu;
da3cec35
TI
163 if (snd_BUG_ON(!emu))
164 return -ENXIO;
1da177e4
LT
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);
b130807d
RD
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;
1da177e4
LT
174 } else {
175 spin_unlock_irqrestore(&midi->open_lock, flags);
176 }
177 return 0;
b130807d
RD
178
179error_out:
180 return -EIO;
1da177e4
LT
181}
182
eb4698f3 183static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream)
1da177e4 184{
eb4698f3
TI
185 struct snd_emu10k1 *emu;
186 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
1da177e4
LT
187 unsigned long flags;
188
189 emu = midi->emu;
da3cec35
TI
190 if (snd_BUG_ON(!emu))
191 return -ENXIO;
1da177e4
LT
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);
b130807d
RD
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;
1da177e4
LT
201 } else {
202 spin_unlock_irqrestore(&midi->open_lock, flags);
203 }
204 return 0;
b130807d
RD
205
206error_out:
207 return -EIO;
1da177e4
LT
208}
209
eb4698f3 210static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream)
1da177e4 211{
eb4698f3
TI
212 struct snd_emu10k1 *emu;
213 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
1da177e4 214 unsigned long flags;
b130807d 215 int err = 0;
1da177e4
LT
216
217 emu = midi->emu;
da3cec35
TI
218 if (snd_BUG_ON(!emu))
219 return -ENXIO;
1da177e4
LT
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);
b130807d 226 err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
1da177e4
LT
227 } else {
228 spin_unlock_irqrestore(&midi->open_lock, flags);
229 }
b130807d 230 return err;
1da177e4
LT
231}
232
eb4698f3 233static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream)
1da177e4 234{
eb4698f3
TI
235 struct snd_emu10k1 *emu;
236 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
1da177e4 237 unsigned long flags;
b130807d 238 int err = 0;
1da177e4
LT
239
240 emu = midi->emu;
da3cec35
TI
241 if (snd_BUG_ON(!emu))
242 return -ENXIO;
1da177e4
LT
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);
b130807d 249 err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
1da177e4
LT
250 } else {
251 spin_unlock_irqrestore(&midi->open_lock, flags);
252 }
b130807d 253 return err;
1da177e4
LT
254}
255
eb4698f3 256static void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
1da177e4 257{
eb4698f3
TI
258 struct snd_emu10k1 *emu;
259 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
1da177e4 260 emu = midi->emu;
da3cec35
TI
261 if (snd_BUG_ON(!emu))
262 return;
1da177e4
LT
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
eb4698f3 270static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
1da177e4 271{
eb4698f3
TI
272 struct snd_emu10k1 *emu;
273 struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
1da177e4
LT
274 unsigned long flags;
275
276 emu = midi->emu;
da3cec35
TI
277 if (snd_BUG_ON(!emu))
278 return;
1da177e4
LT
279
280 if (up) {
281 int max = 4;
282 unsigned char byte;
283
284 /* try to send some amount of bytes here before interrupts */
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 /* no more data */
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
eb4698f3 311static struct snd_rawmidi_ops snd_emu10k1_midi_output =
1da177e4
LT
312{
313 .open = snd_emu10k1_midi_output_open,
314 .close = snd_emu10k1_midi_output_close,
315 .trigger = snd_emu10k1_midi_output_trigger,
316};
317
eb4698f3 318static struct snd_rawmidi_ops snd_emu10k1_midi_input =
1da177e4
LT
319{
320 .open = snd_emu10k1_midi_input_open,
321 .close = snd_emu10k1_midi_input_close,
322 .trigger = snd_emu10k1_midi_input_trigger,
323};
324
eb4698f3 325static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
1da177e4 326{
9fe856e4 327 struct snd_emu10k1_midi *midi = rmidi->private_data;
1da177e4
LT
328 midi->interrupt = NULL;
329 midi->rmidi = NULL;
330}
331
e23e7a14 332static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name)
1da177e4 333{
eb4698f3 334 struct snd_rawmidi *rmidi;
1da177e4
LT
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
e23e7a14 355int snd_emu10k1_midi(struct snd_emu10k1 *emu)
1da177e4 356{
eb4698f3 357 struct snd_emu10k1_midi *midi = &emu->midi;
1da177e4
LT
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
e23e7a14 372int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu)
1da177e4 373{
eb4698f3 374 struct snd_emu10k1_midi *midi;
1da177e4
LT
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}