~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/isa/sb/sb8_midi.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 22 irqreturn_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 
 50 static 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 
 77 static 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 
104 static 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 
122 static 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 
141 static 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 
164 static 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 
200 static 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 
212 static 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 
235 static 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 
242 static 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 
249 int 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php