source: GPL/trunk/alsa-kernel/drivers/mpu401/mpu401_uart.c

Last change on this file was 777, checked in by David Azarewicz, 7 months ago

Merge from uniaud32-exp branch

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