brintos

brintos / linux-shallow public Read only

0
0
Text · 7.5 KiB · 618366d Raw
268 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>4 *  Routines for control of SoundBlaster cards - MIDI interface5 *6 * --7 *8 * Sun May  9 22:54:38 BST 1999 George David Morrison <gdm@gedamo.demon.co.uk>9 *   Fixed typo in snd_sb8dsp_midi_new_device which prevented midi from 10 *   working.11 *12 * Sun May 11 12:34:56 UTC 2003 Clemens Ladisch <clemens@ladisch.de>13 *   Added full duplex UART mode for DSP version 2.0 and later.14 */15 16#include <linux/io.h>17#include <linux/time.h>18#include <sound/core.h>19#include <sound/sb.h>20 21 22irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip)23{24	struct snd_rawmidi *rmidi;25	int max = 64;26	char byte;27 28	if (!chip)29		return IRQ_NONE;30	31	rmidi = chip->rmidi;32	if (!rmidi) {33		inb(SBP(chip, DATA_AVAIL));	/* ack interrupt */34		return IRQ_NONE;35	}36 37	spin_lock(&chip->midi_input_lock);38	while (max-- > 0) {39		if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {40			byte = inb(SBP(chip, READ));41			if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) {42				snd_rawmidi_receive(chip->midi_substream_input, &byte, 1);43			}44		}45	}46	spin_unlock(&chip->midi_input_lock);47	return IRQ_HANDLED;48}49 50static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream)51{52	unsigned long flags;53	struct snd_sb *chip;54	unsigned int valid_open_flags;55 56	chip = substream->rmidi->private_data;57	valid_open_flags = chip->hardware >= SB_HW_2058		? SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER : 0;59	spin_lock_irqsave(&chip->open_lock, flags);60	if (chip->open & ~valid_open_flags) {61		spin_unlock_irqrestore(&chip->open_lock, flags);62		return -EAGAIN;63	}64	chip->open |= SB_OPEN_MIDI_INPUT;65	chip->midi_substream_input = substream;66	if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) {67		spin_unlock_irqrestore(&chip->open_lock, flags);68		snd_sbdsp_reset(chip);		/* reset DSP */69		if (chip->hardware >= SB_HW_20)70			snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);71	} else {72		spin_unlock_irqrestore(&chip->open_lock, flags);73	}74	return 0;75}76 77static int snd_sb8dsp_midi_output_open(struct snd_rawmidi_substream *substream)78{79	unsigned long flags;80	struct snd_sb *chip;81	unsigned int valid_open_flags;82 83	chip = substream->rmidi->private_data;84	valid_open_flags = chip->hardware >= SB_HW_2085		? SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER : 0;86	spin_lock_irqsave(&chip->open_lock, flags);87	if (chip->open & ~valid_open_flags) {88		spin_unlock_irqrestore(&chip->open_lock, flags);89		return -EAGAIN;90	}91	chip->open |= SB_OPEN_MIDI_OUTPUT;92	chip->midi_substream_output = substream;93	if (!(chip->open & SB_OPEN_MIDI_INPUT)) {94		spin_unlock_irqrestore(&chip->open_lock, flags);95		snd_sbdsp_reset(chip);		/* reset DSP */96		if (chip->hardware >= SB_HW_20)97			snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);98	} else {99		spin_unlock_irqrestore(&chip->open_lock, flags);100	}101	return 0;102}103 104static int snd_sb8dsp_midi_input_close(struct snd_rawmidi_substream *substream)105{106	unsigned long flags;107	struct snd_sb *chip;108 109	chip = substream->rmidi->private_data;110	spin_lock_irqsave(&chip->open_lock, flags);111	chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER);112	chip->midi_substream_input = NULL;113	if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) {114		spin_unlock_irqrestore(&chip->open_lock, flags);115		snd_sbdsp_reset(chip);		/* reset DSP */116	} else {117		spin_unlock_irqrestore(&chip->open_lock, flags);118	}119	return 0;120}121 122static int snd_sb8dsp_midi_output_close(struct snd_rawmidi_substream *substream)123{124	unsigned long flags;125	struct snd_sb *chip;126 127	chip = substream->rmidi->private_data;128	del_timer_sync(&chip->midi_timer);129	spin_lock_irqsave(&chip->open_lock, flags);130	chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER);131	chip->midi_substream_output = NULL;132	if (!(chip->open & SB_OPEN_MIDI_INPUT)) {133		spin_unlock_irqrestore(&chip->open_lock, flags);134		snd_sbdsp_reset(chip);		/* reset DSP */135	} else {136		spin_unlock_irqrestore(&chip->open_lock, flags);137	}138	return 0;139}140 141static void snd_sb8dsp_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)142{143	unsigned long flags;144	struct snd_sb *chip;145 146	chip = substream->rmidi->private_data;147	spin_lock_irqsave(&chip->open_lock, flags);148	if (up) {149		if (!(chip->open & SB_OPEN_MIDI_INPUT_TRIGGER)) {150			if (chip->hardware < SB_HW_20)151				snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ);152			chip->open |= SB_OPEN_MIDI_INPUT_TRIGGER;153		}154	} else {155		if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) {156			if (chip->hardware < SB_HW_20)157				snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ);158			chip->open &= ~SB_OPEN_MIDI_INPUT_TRIGGER;159		}160	}161	spin_unlock_irqrestore(&chip->open_lock, flags);162}163 164static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream)165{166	unsigned long flags;167	struct snd_sb *chip;168	char byte;169	int max = 32;170 171	/* how big is Tx FIFO? */172	chip = substream->rmidi->private_data;173	while (max-- > 0) {174		spin_lock_irqsave(&chip->open_lock, flags);175		if (snd_rawmidi_transmit_peek(substream, &byte, 1) != 1) {176			chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;177			del_timer(&chip->midi_timer);178			spin_unlock_irqrestore(&chip->open_lock, flags);179			break;180		}181		if (chip->hardware >= SB_HW_20) {182			int timeout = 8;183			while ((inb(SBP(chip, STATUS)) & 0x80) != 0 && --timeout > 0)184				;185			if (timeout == 0) {186				/* Tx FIFO full - try again later */187				spin_unlock_irqrestore(&chip->open_lock, flags);188				break;189			}190			outb(byte, SBP(chip, WRITE));191		} else {192			snd_sbdsp_command(chip, SB_DSP_MIDI_OUTPUT);193			snd_sbdsp_command(chip, byte);194		}195		snd_rawmidi_transmit_ack(substream, 1);196		spin_unlock_irqrestore(&chip->open_lock, flags);197	}198}199 200static void snd_sb8dsp_midi_output_timer(struct timer_list *t)201{202	struct snd_sb *chip = from_timer(chip, t, midi_timer);203	struct snd_rawmidi_substream *substream = chip->midi_substream_output;204	unsigned long flags;205 206	spin_lock_irqsave(&chip->open_lock, flags);207	mod_timer(&chip->midi_timer, 1 + jiffies);208	spin_unlock_irqrestore(&chip->open_lock, flags);	209	snd_sb8dsp_midi_output_write(substream);210}211 212static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)213{214	unsigned long flags;215	struct snd_sb *chip;216 217	chip = substream->rmidi->private_data;218	spin_lock_irqsave(&chip->open_lock, flags);219	if (up) {220		if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) {221			mod_timer(&chip->midi_timer, 1 + jiffies);222			chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER;223		}224	} else {225		if (chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER) {226			chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;227		}228	}229	spin_unlock_irqrestore(&chip->open_lock, flags);230 231	if (up)232		snd_sb8dsp_midi_output_write(substream);233}234 235static const struct snd_rawmidi_ops snd_sb8dsp_midi_output =236{237	.open =		snd_sb8dsp_midi_output_open,238	.close =	snd_sb8dsp_midi_output_close,239	.trigger =	snd_sb8dsp_midi_output_trigger,240};241 242static const struct snd_rawmidi_ops snd_sb8dsp_midi_input =243{244	.open =		snd_sb8dsp_midi_input_open,245	.close =	snd_sb8dsp_midi_input_close,246	.trigger =	snd_sb8dsp_midi_input_trigger,247};248 249int snd_sb8dsp_midi(struct snd_sb *chip, int device)250{251	struct snd_rawmidi *rmidi;252	int err;253 254	err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi);255	if (err < 0)256		return err;257	strcpy(rmidi->name, "SB8 MIDI");258	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_sb8dsp_midi_output);259	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_sb8dsp_midi_input);260	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT;261	if (chip->hardware >= SB_HW_20)262		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;263	rmidi->private_data = chip;264	timer_setup(&chip->midi_timer, snd_sb8dsp_midi_output_timer, 0);265	chip->rmidi = rmidi;266	return 0;267}268