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