Linux Audio

Check our new training course

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