File Index
Files and directories
Sign in
FILE

mpu401_uart.c

File preview with syntax highlighting.

linux-6.19.14/sound/drivers/mpu401/mpu401_uart.c C
  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	if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) &&
 85	    test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) {
 86		guard(spinlock_irqsave)(&mpu->output_lock);
 87		snd_mpu401_uart_output_write(mpu);
 88	}
 89}
 90
 91static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
 92{
 93	if (mpu->info_flags & MPU401_INFO_INPUT) {
 94		guard(spinlock_irqsave)(&mpu->input_lock);
 95		if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
 96			snd_mpu401_uart_input_read(mpu);
 97		else
 98			snd_mpu401_uart_clear_rx(mpu);
 99	}
100	if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
101		/* ok. for better Tx performance try do some output
102		   when input is done */
103		uart_interrupt_tx(mpu);
104}
105
106/**
107 * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler
108 * @irq: the irq number
109 * @dev_id: mpu401 instance
110 *
111 * Processes the interrupt for MPU401-UART i/o.
112 *
113 * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise.
114 */
115irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id)
116{
117	struct snd_mpu401 *mpu = dev_id;
118	
119	if (!mpu)
120		return IRQ_NONE;
121	_snd_mpu401_uart_interrupt(mpu);
122	return IRQ_HANDLED;
123}
124
125EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
126
127/**
128 * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler
129 * @irq: the irq number
130 * @dev_id: mpu401 instance
131 *
132 * Processes the interrupt for MPU401-UART output.
133 *
134 * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise.
135 */
136irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id)
137{
138	struct snd_mpu401 *mpu = dev_id;
139	
140	if (!mpu)
141		return IRQ_NONE;
142	uart_interrupt_tx(mpu);
143	return IRQ_HANDLED;
144}
145
146EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx);
147
148/*
149 * timer callback
150 * reprogram the timer and call the interrupt job
151 */
152static void snd_mpu401_uart_timer(struct timer_list *t)
153{
154	struct snd_mpu401 *mpu = timer_container_of(mpu, t, timer);
155
156	scoped_guard(spinlock_irqsave, &mpu->timer_lock) {
157		/*mpu->mode |= MPU401_MODE_TIMER;*/
158		mod_timer(&mpu->timer,  1 + jiffies);
159	}
160	if (mpu->rmidi)
161		_snd_mpu401_uart_interrupt(mpu);
162}
163
164/*
165 * initialize the timer callback if not programmed yet
166 */
167static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
168{
169	guard(spinlock_irqsave)(&mpu->timer_lock);
170	if (mpu->timer_invoked == 0) {
171		timer_setup(&mpu->timer, snd_mpu401_uart_timer, 0);
172		mod_timer(&mpu->timer, 1 + jiffies);
173	} 
174	mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
175		MPU401_MODE_OUTPUT_TIMER;
176}
177
178/*
179 * remove the timer callback if still active
180 */
181static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
182{
183	guard(spinlock_irqsave)(&mpu->timer_lock);
184	if (mpu->timer_invoked) {
185		mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER :
186			~MPU401_MODE_OUTPUT_TIMER;
187		if (! mpu->timer_invoked)
188			timer_delete(&mpu->timer);
189	}
190}
191
192/*
193 * send a UART command
194 * return zero if successful, non-zero for some errors
195 */
196
197static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
198			       int ack)
199{
200	int timeout, ok;
201
202	guard(spinlock_irqsave)(&mpu->input_lock);
203	if (mpu->hardware != MPU401_HW_TRID4DWAVE) {
204		mpu->write(mpu, 0x00, MPU401D(mpu));
205		/*snd_mpu401_uart_clear_rx(mpu);*/
206	}
207	/* ok. standard MPU-401 initialization */
208	if (mpu->hardware != MPU401_HW_SB) {
209		for (timeout = 1000; timeout > 0 &&
210			     !snd_mpu401_output_ready(mpu); timeout--)
211			udelay(10);
212#ifdef CONFIG_SND_DEBUG
213		if (!timeout)
214			dev_err(mpu->rmidi->dev,
215				"cmd: tx timeout (status = 0x%x)\n",
216				mpu->read(mpu, MPU401C(mpu)));
217#endif
218	}
219	mpu->write(mpu, cmd, MPU401C(mpu));
220	if (ack && !(mpu->info_flags & MPU401_INFO_NO_ACK)) {
221		ok = 0;
222		timeout = 10000;
223		while (!ok && timeout-- > 0) {
224			if (snd_mpu401_input_avail(mpu)) {
225				if (mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
226					ok = 1;
227			}
228		}
229		if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
230			ok = 1;
231	} else
232		ok = 1;
233	if (!ok) {
234		dev_err(mpu->rmidi->dev,
235			"cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n",
236			cmd, mpu->port,
237			mpu->read(mpu, MPU401C(mpu)),
238			mpu->read(mpu, MPU401D(mpu)));
239		return 1;
240	}
241	return 0;
242}
243
244static int snd_mpu401_do_reset(struct snd_mpu401 *mpu)
245{
246	if (snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1))
247		return -EIO;
248	if (snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 0))
249		return -EIO;
250	return 0;
251}
252
253/*
254 * input/output open/close - protected by open_mutex in rawmidi.c
255 */
256static int snd_mpu401_uart_input_open(struct snd_rawmidi_substream *substream)
257{
258	struct snd_mpu401 *mpu;
259	int err;
260
261	mpu = substream->rmidi->private_data;
262	if (mpu->open_input) {
263		err = mpu->open_input(mpu);
264		if (err < 0)
265			return err;
266	}
267	if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) {
268		if (snd_mpu401_do_reset(mpu) < 0)
269			goto error_out;
270	}
271	mpu->substream_input = substream;
272	set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode);
273	return 0;
274
275error_out:
276	if (mpu->open_input && mpu->close_input)
277		mpu->close_input(mpu);
278	return -EIO;
279}
280
281static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream)
282{
283	struct snd_mpu401 *mpu;
284	int err;
285
286	mpu = substream->rmidi->private_data;
287	if (mpu->open_output) {
288		err = mpu->open_output(mpu);
289		if (err < 0)
290			return err;
291	}
292	if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
293		if (snd_mpu401_do_reset(mpu) < 0)
294			goto error_out;
295	}
296	mpu->substream_output = substream;
297	set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode);
298	return 0;
299
300error_out:
301	if (mpu->open_output && mpu->close_output)
302		mpu->close_output(mpu);
303	return -EIO;
304}
305
306static int snd_mpu401_uart_input_close(struct snd_rawmidi_substream *substream)
307{
308	struct snd_mpu401 *mpu;
309	int err = 0;
310
311	mpu = substream->rmidi->private_data;
312	clear_bit(MPU401_MODE_BIT_INPUT, &mpu->mode);
313	mpu->substream_input = NULL;
314	if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode))
315		err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0);
316	if (mpu->close_input)
317		mpu->close_input(mpu);
318	if (err)
319		return -EIO;
320	return 0;
321}
322
323static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream)
324{
325	struct snd_mpu401 *mpu;
326	int err = 0;
327
328	mpu = substream->rmidi->private_data;
329	clear_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode);
330	mpu->substream_output = NULL;
331	if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
332		err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0);
333	if (mpu->close_output)
334		mpu->close_output(mpu);
335	if (err)
336		return -EIO;
337	return 0;
338}
339
340/*
341 * trigger input callback
342 */
343static void
344snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
345{
346	struct snd_mpu401 *mpu;
347	int max = 64;
348
349	mpu = substream->rmidi->private_data;
350	if (up) {
351		if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER,
352				       &mpu->mode)) {
353			/* first time - flush FIFO */
354			while (max-- > 0)
355				mpu->read(mpu, MPU401D(mpu));
356			if (mpu->info_flags & MPU401_INFO_USE_TIMER)
357				snd_mpu401_uart_add_timer(mpu, 1);
358		}
359		
360		/* read data in advance */
361		guard(spinlock_irqsave)(&mpu->input_lock);
362		snd_mpu401_uart_input_read(mpu);
363	} else {
364		if (mpu->info_flags & MPU401_INFO_USE_TIMER)
365			snd_mpu401_uart_remove_timer(mpu, 1);
366		clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
367	}
368
369}
370
371/*
372 * transfer input pending data
373 * call with input_lock spinlock held
374 */
375static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu)
376{
377	int max = 128;
378	unsigned char byte;
379
380	while (max-- > 0) {
381		if (! snd_mpu401_input_avail(mpu))
382			break; /* input not available */
383		byte = mpu->read(mpu, MPU401D(mpu));
384		if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
385			snd_rawmidi_receive(mpu->substream_input, &byte, 1);
386	}
387}
388
389/*
390 *  Tx FIFO sizes:
391 *    CS4237B			- 16 bytes
392 *    AudioDrive ES1688         - 12 bytes
393 *    S3 SonicVibes             -  8 bytes
394 *    SoundBlaster AWE 64       -  2 bytes (ugly hardware)
395 */
396
397/*
398 * write output pending bytes
399 * call with output_lock spinlock held
400 */
401static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
402{
403	unsigned char byte;
404	int max = 256;
405
406	do {
407		if (snd_rawmidi_transmit_peek(mpu->substream_output,
408					      &byte, 1) == 1) {
409			/*
410			 * Try twice because there is hardware that insists on
411			 * setting the output busy bit after each write.
412			 */
413			if (!snd_mpu401_output_ready(mpu) &&
414			    !snd_mpu401_output_ready(mpu))
415				break;	/* Tx FIFO full - try again later */
416			mpu->write(mpu, byte, MPU401D(mpu));
417			snd_rawmidi_transmit_ack(mpu->substream_output, 1);
418		} else {
419			snd_mpu401_uart_remove_timer (mpu, 0);
420			break;	/* no other data - leave the tx loop */
421		}
422	} while (--max > 0);
423}
424
425/*
426 * output trigger callback
427 */
428static void
429snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
430{
431	struct snd_mpu401 *mpu;
432
433	mpu = substream->rmidi->private_data;
434	if (up) {
435		set_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
436
437		/* try to add the timer at each output trigger,
438		 * since the output timer might have been removed in
439		 * snd_mpu401_uart_output_write().
440		 */
441		if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
442			snd_mpu401_uart_add_timer(mpu, 0);
443
444		/* output pending data */
445		guard(spinlock_irqsave)(&mpu->output_lock);
446		snd_mpu401_uart_output_write(mpu);
447	} else {
448		if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
449			snd_mpu401_uart_remove_timer(mpu, 0);
450		clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
451	}
452}
453
454/*
455
456 */
457
458static const struct snd_rawmidi_ops snd_mpu401_uart_output =
459{
460	.open =		snd_mpu401_uart_output_open,
461	.close =	snd_mpu401_uart_output_close,
462	.trigger =	snd_mpu401_uart_output_trigger,
463};
464
465static const struct snd_rawmidi_ops snd_mpu401_uart_input =
466{
467	.open =		snd_mpu401_uart_input_open,
468	.close =	snd_mpu401_uart_input_close,
469	.trigger =	snd_mpu401_uart_input_trigger,
470};
471
472static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
473{
474	struct snd_mpu401 *mpu = rmidi->private_data;
475	if (mpu->irq >= 0)
476		free_irq(mpu->irq, (void *) mpu);
477	release_and_free_resource(mpu->res);
478	kfree(mpu);
479}
480
481/**
482 * snd_mpu401_uart_new - create an MPU401-UART instance
483 * @card: the card instance
484 * @device: the device index, zero-based
485 * @hardware: the hardware type, MPU401_HW_XXXX
486 * @port: the base address of MPU401 port
487 * @info_flags: bitflags MPU401_INFO_XXX
488 * @irq: the ISA irq number, -1 if not to be allocated
489 * @rrawmidi: the pointer to store the new rawmidi instance
490 *
491 * Creates a new MPU-401 instance.
492 *
493 * Note that the rawmidi instance is returned on the rrawmidi argument,
494 * not the mpu401 instance itself.  To access to the mpu401 instance,
495 * cast from rawmidi->private_data (with struct snd_mpu401 magic-cast).
496 *
497 * Return: Zero if successful, or a negative error code.
498 */
499int snd_mpu401_uart_new(struct snd_card *card, int device,
500			unsigned short hardware,
501			unsigned long port,
502			unsigned int info_flags,
503			int irq,
504			struct snd_rawmidi ** rrawmidi)
505{
506	struct snd_mpu401 *mpu;
507	struct snd_rawmidi *rmidi;
508	int in_enable, out_enable;
509	int err;
510
511	if (rrawmidi)
512		*rrawmidi = NULL;
513	if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT)))
514		info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT;
515	in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0;
516	out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0;
517	err = snd_rawmidi_new(card, "MPU-401U", device,
518			      out_enable, in_enable, &rmidi);
519	if (err < 0)
520		return err;
521	mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
522	if (!mpu) {
523		err = -ENOMEM;
524		goto free_device;
525	}
526	rmidi->private_data = mpu;
527	rmidi->private_free = snd_mpu401_uart_free;
528	spin_lock_init(&mpu->input_lock);
529	spin_lock_init(&mpu->output_lock);
530	spin_lock_init(&mpu->timer_lock);
531	mpu->hardware = hardware;
532	mpu->irq = -1;
533	mpu->rmidi = rmidi;
534	if (! (info_flags & MPU401_INFO_INTEGRATED)) {
535		int res_size = hardware == MPU401_HW_PC98II ? 4 : 2;
536		mpu->res = request_region(port, res_size, "MPU401 UART");
537		if (!mpu->res) {
538			dev_err(rmidi->dev,
539				"mpu401_uart: unable to grab port 0x%lx size %d\n",
540				port, res_size);
541			err = -EBUSY;
542			goto free_device;
543		}
544	}
545	if (info_flags & MPU401_INFO_MMIO) {
546		mpu->write = mpu401_write_mmio;
547		mpu->read = mpu401_read_mmio;
548	} else {
549		mpu->write = mpu401_write_port;
550		mpu->read = mpu401_read_port;
551	}
552	mpu->port = port;
553	if (hardware == MPU401_HW_PC98II)
554		mpu->cport = port + 2;
555	else
556		mpu->cport = port + 1;
557	if (irq >= 0) {
558		if (request_irq(irq, snd_mpu401_uart_interrupt, 0,
559				"MPU401 UART", (void *) mpu)) {
560			dev_err(rmidi->dev,
561				"mpu401_uart: unable to grab IRQ %d\n", irq);
562			err = -EBUSY;
563			goto free_device;
564		}
565	}
566	if (irq < 0 && !(info_flags & MPU401_INFO_IRQ_HOOK))
567		info_flags |= MPU401_INFO_USE_TIMER;
568	mpu->info_flags = info_flags;
569	mpu->irq = irq;
570	if (card->shortname[0])
571		snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI",
572			 card->shortname);
573	else
574		sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device);
575	if (out_enable) {
576		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
577				    &snd_mpu401_uart_output);
578		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
579	}
580	if (in_enable) {
581		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
582				    &snd_mpu401_uart_input);
583		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
584		if (out_enable)
585			rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
586	}
587	if (rrawmidi)
588		*rrawmidi = rmidi;
589	return 0;
590free_device:
591	snd_device_free(card, rmidi);
592	return err;
593}
594
595EXPORT_SYMBOL(snd_mpu401_uart_new);
~/ Read-only file preview.