Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/drivers/mpu401/mpu401_uart.c
10817 views
1
/*
2
* Copyright (c) by Jaroslav Kysela <[email protected]>
3
* Routines for control of MPU-401 in UART mode
4
*
5
* MPU-401 supports UART mode which is not capable generate transmit
6
* interrupts thus output is done via polling. Also, if irq < 0, then
7
* input is done also via polling. Do not expect good performance.
8
*
9
*
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
14
*
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
19
*
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
*
24
* 13-03-2003:
25
* Added support for different kind of hardware I/O. Build in choices
26
* are port and mmio. For other kind of I/O, set mpu->read and
27
* mpu->write to your own I/O functions.
28
*
29
*/
30
31
#include <asm/io.h>
32
#include <linux/delay.h>
33
#include <linux/init.h>
34
#include <linux/slab.h>
35
#include <linux/ioport.h>
36
#include <linux/interrupt.h>
37
#include <linux/errno.h>
38
#include <sound/core.h>
39
#include <sound/mpu401.h>
40
41
MODULE_AUTHOR("Jaroslav Kysela <[email protected]>");
42
MODULE_DESCRIPTION("Routines for control of MPU-401 in UART mode");
43
MODULE_LICENSE("GPL");
44
45
static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu);
46
static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu);
47
48
/*
49
50
*/
51
52
#define snd_mpu401_input_avail(mpu) \
53
(!(mpu->read(mpu, MPU401C(mpu)) & MPU401_RX_EMPTY))
54
#define snd_mpu401_output_ready(mpu) \
55
(!(mpu->read(mpu, MPU401C(mpu)) & MPU401_TX_FULL))
56
57
/* Build in lowlevel io */
58
static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data,
59
unsigned long addr)
60
{
61
outb(data, addr);
62
}
63
64
static unsigned char mpu401_read_port(struct snd_mpu401 *mpu,
65
unsigned long addr)
66
{
67
return inb(addr);
68
}
69
70
static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data,
71
unsigned long addr)
72
{
73
writeb(data, (void __iomem *)addr);
74
}
75
76
static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu,
77
unsigned long addr)
78
{
79
return readb((void __iomem *)addr);
80
}
81
/* */
82
83
static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu)
84
{
85
int timeout = 100000;
86
for (; timeout > 0 && snd_mpu401_input_avail(mpu); timeout--)
87
mpu->read(mpu, MPU401D(mpu));
88
#ifdef CONFIG_SND_DEBUG
89
if (timeout <= 0)
90
snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n",
91
mpu->read(mpu, MPU401C(mpu)));
92
#endif
93
}
94
95
static void uart_interrupt_tx(struct snd_mpu401 *mpu)
96
{
97
unsigned long flags;
98
99
if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) &&
100
test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) {
101
spin_lock_irqsave(&mpu->output_lock, flags);
102
snd_mpu401_uart_output_write(mpu);
103
spin_unlock_irqrestore(&mpu->output_lock, flags);
104
}
105
}
106
107
static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
108
{
109
unsigned long flags;
110
111
if (mpu->info_flags & MPU401_INFO_INPUT) {
112
spin_lock_irqsave(&mpu->input_lock, flags);
113
if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
114
snd_mpu401_uart_input_read(mpu);
115
else
116
snd_mpu401_uart_clear_rx(mpu);
117
spin_unlock_irqrestore(&mpu->input_lock, flags);
118
}
119
if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
120
/* ok. for better Tx performance try do some output
121
when input is done */
122
uart_interrupt_tx(mpu);
123
}
124
125
/**
126
* snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler
127
* @irq: the irq number
128
* @dev_id: mpu401 instance
129
*
130
* Processes the interrupt for MPU401-UART i/o.
131
*/
132
irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id)
133
{
134
struct snd_mpu401 *mpu = dev_id;
135
136
if (mpu == NULL)
137
return IRQ_NONE;
138
_snd_mpu401_uart_interrupt(mpu);
139
return IRQ_HANDLED;
140
}
141
142
EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
143
144
/**
145
* snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler
146
* @irq: the irq number
147
* @dev_id: mpu401 instance
148
*
149
* Processes the interrupt for MPU401-UART output.
150
*/
151
irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id)
152
{
153
struct snd_mpu401 *mpu = dev_id;
154
155
if (mpu == NULL)
156
return IRQ_NONE;
157
uart_interrupt_tx(mpu);
158
return IRQ_HANDLED;
159
}
160
161
EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx);
162
163
/*
164
* timer callback
165
* reprogram the timer and call the interrupt job
166
*/
167
static void snd_mpu401_uart_timer(unsigned long data)
168
{
169
struct snd_mpu401 *mpu = (struct snd_mpu401 *)data;
170
unsigned long flags;
171
172
spin_lock_irqsave(&mpu->timer_lock, flags);
173
/*mpu->mode |= MPU401_MODE_TIMER;*/
174
mpu->timer.expires = 1 + jiffies;
175
add_timer(&mpu->timer);
176
spin_unlock_irqrestore(&mpu->timer_lock, flags);
177
if (mpu->rmidi)
178
_snd_mpu401_uart_interrupt(mpu);
179
}
180
181
/*
182
* initialize the timer callback if not programmed yet
183
*/
184
static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
185
{
186
unsigned long flags;
187
188
spin_lock_irqsave (&mpu->timer_lock, flags);
189
if (mpu->timer_invoked == 0) {
190
init_timer(&mpu->timer);
191
mpu->timer.data = (unsigned long)mpu;
192
mpu->timer.function = snd_mpu401_uart_timer;
193
mpu->timer.expires = 1 + jiffies;
194
add_timer(&mpu->timer);
195
}
196
mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
197
MPU401_MODE_OUTPUT_TIMER;
198
spin_unlock_irqrestore (&mpu->timer_lock, flags);
199
}
200
201
/*
202
* remove the timer callback if still active
203
*/
204
static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
205
{
206
unsigned long flags;
207
208
spin_lock_irqsave (&mpu->timer_lock, flags);
209
if (mpu->timer_invoked) {
210
mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER :
211
~MPU401_MODE_OUTPUT_TIMER;
212
if (! mpu->timer_invoked)
213
del_timer(&mpu->timer);
214
}
215
spin_unlock_irqrestore (&mpu->timer_lock, flags);
216
}
217
218
/*
219
* send a UART command
220
* return zero if successful, non-zero for some errors
221
*/
222
223
static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
224
int ack)
225
{
226
unsigned long flags;
227
int timeout, ok;
228
229
spin_lock_irqsave(&mpu->input_lock, flags);
230
if (mpu->hardware != MPU401_HW_TRID4DWAVE) {
231
mpu->write(mpu, 0x00, MPU401D(mpu));
232
/*snd_mpu401_uart_clear_rx(mpu);*/
233
}
234
/* ok. standard MPU-401 initialization */
235
if (mpu->hardware != MPU401_HW_SB) {
236
for (timeout = 1000; timeout > 0 &&
237
!snd_mpu401_output_ready(mpu); timeout--)
238
udelay(10);
239
#ifdef CONFIG_SND_DEBUG
240
if (!timeout)
241
snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n",
242
mpu->read(mpu, MPU401C(mpu)));
243
#endif
244
}
245
mpu->write(mpu, cmd, MPU401C(mpu));
246
if (ack && !(mpu->info_flags & MPU401_INFO_NO_ACK)) {
247
ok = 0;
248
timeout = 10000;
249
while (!ok && timeout-- > 0) {
250
if (snd_mpu401_input_avail(mpu)) {
251
if (mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
252
ok = 1;
253
}
254
}
255
if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
256
ok = 1;
257
} else
258
ok = 1;
259
spin_unlock_irqrestore(&mpu->input_lock, flags);
260
if (!ok) {
261
snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx "
262
"(status = 0x%x, data = 0x%x)\n", cmd, mpu->port,
263
mpu->read(mpu, MPU401C(mpu)),
264
mpu->read(mpu, MPU401D(mpu)));
265
return 1;
266
}
267
return 0;
268
}
269
270
static int snd_mpu401_do_reset(struct snd_mpu401 *mpu)
271
{
272
if (snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1))
273
return -EIO;
274
if (snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 0))
275
return -EIO;
276
return 0;
277
}
278
279
/*
280
* input/output open/close - protected by open_mutex in rawmidi.c
281
*/
282
static int snd_mpu401_uart_input_open(struct snd_rawmidi_substream *substream)
283
{
284
struct snd_mpu401 *mpu;
285
int err;
286
287
mpu = substream->rmidi->private_data;
288
if (mpu->open_input && (err = mpu->open_input(mpu)) < 0)
289
return err;
290
if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) {
291
if (snd_mpu401_do_reset(mpu) < 0)
292
goto error_out;
293
}
294
mpu->substream_input = substream;
295
set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode);
296
return 0;
297
298
error_out:
299
if (mpu->open_input && mpu->close_input)
300
mpu->close_input(mpu);
301
return -EIO;
302
}
303
304
static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream)
305
{
306
struct snd_mpu401 *mpu;
307
int err;
308
309
mpu = substream->rmidi->private_data;
310
if (mpu->open_output && (err = mpu->open_output(mpu)) < 0)
311
return err;
312
if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
313
if (snd_mpu401_do_reset(mpu) < 0)
314
goto error_out;
315
}
316
mpu->substream_output = substream;
317
set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode);
318
return 0;
319
320
error_out:
321
if (mpu->open_output && mpu->close_output)
322
mpu->close_output(mpu);
323
return -EIO;
324
}
325
326
static int snd_mpu401_uart_input_close(struct snd_rawmidi_substream *substream)
327
{
328
struct snd_mpu401 *mpu;
329
int err = 0;
330
331
mpu = substream->rmidi->private_data;
332
clear_bit(MPU401_MODE_BIT_INPUT, &mpu->mode);
333
mpu->substream_input = NULL;
334
if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode))
335
err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0);
336
if (mpu->close_input)
337
mpu->close_input(mpu);
338
if (err)
339
return -EIO;
340
return 0;
341
}
342
343
static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream)
344
{
345
struct snd_mpu401 *mpu;
346
int err = 0;
347
348
mpu = substream->rmidi->private_data;
349
clear_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode);
350
mpu->substream_output = NULL;
351
if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
352
err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0);
353
if (mpu->close_output)
354
mpu->close_output(mpu);
355
if (err)
356
return -EIO;
357
return 0;
358
}
359
360
/*
361
* trigger input callback
362
*/
363
static void
364
snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
365
{
366
unsigned long flags;
367
struct snd_mpu401 *mpu;
368
int max = 64;
369
370
mpu = substream->rmidi->private_data;
371
if (up) {
372
if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER,
373
&mpu->mode)) {
374
/* first time - flush FIFO */
375
while (max-- > 0)
376
mpu->read(mpu, MPU401D(mpu));
377
if (mpu->irq < 0)
378
snd_mpu401_uart_add_timer(mpu, 1);
379
}
380
381
/* read data in advance */
382
spin_lock_irqsave(&mpu->input_lock, flags);
383
snd_mpu401_uart_input_read(mpu);
384
spin_unlock_irqrestore(&mpu->input_lock, flags);
385
} else {
386
if (mpu->irq < 0)
387
snd_mpu401_uart_remove_timer(mpu, 1);
388
clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
389
}
390
391
}
392
393
/*
394
* transfer input pending data
395
* call with input_lock spinlock held
396
*/
397
static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu)
398
{
399
int max = 128;
400
unsigned char byte;
401
402
while (max-- > 0) {
403
if (! snd_mpu401_input_avail(mpu))
404
break; /* input not available */
405
byte = mpu->read(mpu, MPU401D(mpu));
406
if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
407
snd_rawmidi_receive(mpu->substream_input, &byte, 1);
408
}
409
}
410
411
/*
412
* Tx FIFO sizes:
413
* CS4237B - 16 bytes
414
* AudioDrive ES1688 - 12 bytes
415
* S3 SonicVibes - 8 bytes
416
* SoundBlaster AWE 64 - 2 bytes (ugly hardware)
417
*/
418
419
/*
420
* write output pending bytes
421
* call with output_lock spinlock held
422
*/
423
static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
424
{
425
unsigned char byte;
426
int max = 256;
427
428
do {
429
if (snd_rawmidi_transmit_peek(mpu->substream_output,
430
&byte, 1) == 1) {
431
/*
432
* Try twice because there is hardware that insists on
433
* setting the output busy bit after each write.
434
*/
435
if (!snd_mpu401_output_ready(mpu) &&
436
!snd_mpu401_output_ready(mpu))
437
break; /* Tx FIFO full - try again later */
438
mpu->write(mpu, byte, MPU401D(mpu));
439
snd_rawmidi_transmit_ack(mpu->substream_output, 1);
440
} else {
441
snd_mpu401_uart_remove_timer (mpu, 0);
442
break; /* no other data - leave the tx loop */
443
}
444
} while (--max > 0);
445
}
446
447
/*
448
* output trigger callback
449
*/
450
static void
451
snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
452
{
453
unsigned long flags;
454
struct snd_mpu401 *mpu;
455
456
mpu = substream->rmidi->private_data;
457
if (up) {
458
set_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
459
460
/* try to add the timer at each output trigger,
461
* since the output timer might have been removed in
462
* snd_mpu401_uart_output_write().
463
*/
464
if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
465
snd_mpu401_uart_add_timer(mpu, 0);
466
467
/* output pending data */
468
spin_lock_irqsave(&mpu->output_lock, flags);
469
snd_mpu401_uart_output_write(mpu);
470
spin_unlock_irqrestore(&mpu->output_lock, flags);
471
} else {
472
if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
473
snd_mpu401_uart_remove_timer(mpu, 0);
474
clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
475
}
476
}
477
478
/*
479
480
*/
481
482
static struct snd_rawmidi_ops snd_mpu401_uart_output =
483
{
484
.open = snd_mpu401_uart_output_open,
485
.close = snd_mpu401_uart_output_close,
486
.trigger = snd_mpu401_uart_output_trigger,
487
};
488
489
static struct snd_rawmidi_ops snd_mpu401_uart_input =
490
{
491
.open = snd_mpu401_uart_input_open,
492
.close = snd_mpu401_uart_input_close,
493
.trigger = snd_mpu401_uart_input_trigger,
494
};
495
496
static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
497
{
498
struct snd_mpu401 *mpu = rmidi->private_data;
499
if (mpu->irq_flags && mpu->irq >= 0)
500
free_irq(mpu->irq, (void *) mpu);
501
release_and_free_resource(mpu->res);
502
kfree(mpu);
503
}
504
505
/**
506
* snd_mpu401_uart_new - create an MPU401-UART instance
507
* @card: the card instance
508
* @device: the device index, zero-based
509
* @hardware: the hardware type, MPU401_HW_XXXX
510
* @port: the base address of MPU401 port
511
* @info_flags: bitflags MPU401_INFO_XXX
512
* @irq: the irq number, -1 if no interrupt for mpu
513
* @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved.
514
* @rrawmidi: the pointer to store the new rawmidi instance
515
*
516
* Creates a new MPU-401 instance.
517
*
518
* Note that the rawmidi instance is returned on the rrawmidi argument,
519
* not the mpu401 instance itself. To access to the mpu401 instance,
520
* cast from rawmidi->private_data (with struct snd_mpu401 magic-cast).
521
*
522
* Returns zero if successful, or a negative error code.
523
*/
524
int snd_mpu401_uart_new(struct snd_card *card, int device,
525
unsigned short hardware,
526
unsigned long port,
527
unsigned int info_flags,
528
int irq, int irq_flags,
529
struct snd_rawmidi ** rrawmidi)
530
{
531
struct snd_mpu401 *mpu;
532
struct snd_rawmidi *rmidi;
533
int in_enable, out_enable;
534
int err;
535
536
if (rrawmidi)
537
*rrawmidi = NULL;
538
if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT)))
539
info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT;
540
in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0;
541
out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0;
542
if ((err = snd_rawmidi_new(card, "MPU-401U", device,
543
out_enable, in_enable, &rmidi)) < 0)
544
return err;
545
mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
546
if (mpu == NULL) {
547
snd_printk(KERN_ERR "mpu401_uart: cannot allocate\n");
548
snd_device_free(card, rmidi);
549
return -ENOMEM;
550
}
551
rmidi->private_data = mpu;
552
rmidi->private_free = snd_mpu401_uart_free;
553
spin_lock_init(&mpu->input_lock);
554
spin_lock_init(&mpu->output_lock);
555
spin_lock_init(&mpu->timer_lock);
556
mpu->hardware = hardware;
557
if (! (info_flags & MPU401_INFO_INTEGRATED)) {
558
int res_size = hardware == MPU401_HW_PC98II ? 4 : 2;
559
mpu->res = request_region(port, res_size, "MPU401 UART");
560
if (mpu->res == NULL) {
561
snd_printk(KERN_ERR "mpu401_uart: "
562
"unable to grab port 0x%lx size %d\n",
563
port, res_size);
564
snd_device_free(card, rmidi);
565
return -EBUSY;
566
}
567
}
568
if (info_flags & MPU401_INFO_MMIO) {
569
mpu->write = mpu401_write_mmio;
570
mpu->read = mpu401_read_mmio;
571
} else {
572
mpu->write = mpu401_write_port;
573
mpu->read = mpu401_read_port;
574
}
575
mpu->port = port;
576
if (hardware == MPU401_HW_PC98II)
577
mpu->cport = port + 2;
578
else
579
mpu->cport = port + 1;
580
if (irq >= 0 && irq_flags) {
581
if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags,
582
"MPU401 UART", (void *) mpu)) {
583
snd_printk(KERN_ERR "mpu401_uart: "
584
"unable to grab IRQ %d\n", irq);
585
snd_device_free(card, rmidi);
586
return -EBUSY;
587
}
588
}
589
mpu->info_flags = info_flags;
590
mpu->irq = irq;
591
mpu->irq_flags = irq_flags;
592
if (card->shortname[0])
593
snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI",
594
card->shortname);
595
else
596
sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device);
597
if (out_enable) {
598
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
599
&snd_mpu401_uart_output);
600
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
601
}
602
if (in_enable) {
603
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
604
&snd_mpu401_uart_input);
605
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
606
if (out_enable)
607
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
608
}
609
mpu->rmidi = rmidi;
610
if (rrawmidi)
611
*rrawmidi = rmidi;
612
return 0;
613
}
614
615
EXPORT_SYMBOL(snd_mpu401_uart_new);
616
617
/*
618
* INIT part
619
*/
620
621
static int __init alsa_mpu401_uart_init(void)
622
{
623
return 0;
624
}
625
626
static void __exit alsa_mpu401_uart_exit(void)
627
{
628
}
629
630
module_init(alsa_mpu401_uart_init)
631
module_exit(alsa_mpu401_uart_exit)
632
633