Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0004  *  Routines for control of SoundBlaster cards - MIDI interface
0005  *
0006  * --
0007  *
0008  * Sun May  9 22:54:38 BST 1999 George David Morrison <gdm@gedamo.demon.co.uk>
0009  *   Fixed typo in snd_sb8dsp_midi_new_device which prevented midi from 
0010  *   working.
0011  *
0012  * Sun May 11 12:34:56 UTC 2003 Clemens Ladisch <clemens@ladisch.de>
0013  *   Added full duplex UART mode for DSP version 2.0 and later.
0014  */
0015 
0016 #include <linux/io.h>
0017 #include <linux/time.h>
0018 #include <sound/core.h>
0019 #include <sound/sb.h>
0020 
0021 
0022 irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip)
0023 {
0024     struct snd_rawmidi *rmidi;
0025     int max = 64;
0026     char byte;
0027 
0028     if (!chip)
0029         return IRQ_NONE;
0030     
0031     rmidi = chip->rmidi;
0032     if (!rmidi) {
0033         inb(SBP(chip, DATA_AVAIL)); /* ack interrupt */
0034         return IRQ_NONE;
0035     }
0036 
0037     spin_lock(&chip->midi_input_lock);
0038     while (max-- > 0) {
0039         if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
0040             byte = inb(SBP(chip, READ));
0041             if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) {
0042                 snd_rawmidi_receive(chip->midi_substream_input, &byte, 1);
0043             }
0044         }
0045     }
0046     spin_unlock(&chip->midi_input_lock);
0047     return IRQ_HANDLED;
0048 }
0049 
0050 static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream)
0051 {
0052     unsigned long flags;
0053     struct snd_sb *chip;
0054     unsigned int valid_open_flags;
0055 
0056     chip = substream->rmidi->private_data;
0057     valid_open_flags = chip->hardware >= SB_HW_20
0058         ? SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER : 0;
0059     spin_lock_irqsave(&chip->open_lock, flags);
0060     if (chip->open & ~valid_open_flags) {
0061         spin_unlock_irqrestore(&chip->open_lock, flags);
0062         return -EAGAIN;
0063     }
0064     chip->open |= SB_OPEN_MIDI_INPUT;
0065     chip->midi_substream_input = substream;
0066     if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) {
0067         spin_unlock_irqrestore(&chip->open_lock, flags);
0068         snd_sbdsp_reset(chip);      /* reset DSP */
0069         if (chip->hardware >= SB_HW_20)
0070             snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);
0071     } else {
0072         spin_unlock_irqrestore(&chip->open_lock, flags);
0073     }
0074     return 0;
0075 }
0076 
0077 static int snd_sb8dsp_midi_output_open(struct snd_rawmidi_substream *substream)
0078 {
0079     unsigned long flags;
0080     struct snd_sb *chip;
0081     unsigned int valid_open_flags;
0082 
0083     chip = substream->rmidi->private_data;
0084     valid_open_flags = chip->hardware >= SB_HW_20
0085         ? SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER : 0;
0086     spin_lock_irqsave(&chip->open_lock, flags);
0087     if (chip->open & ~valid_open_flags) {
0088         spin_unlock_irqrestore(&chip->open_lock, flags);
0089         return -EAGAIN;
0090     }
0091     chip->open |= SB_OPEN_MIDI_OUTPUT;
0092     chip->midi_substream_output = substream;
0093     if (!(chip->open & SB_OPEN_MIDI_INPUT)) {
0094         spin_unlock_irqrestore(&chip->open_lock, flags);
0095         snd_sbdsp_reset(chip);      /* reset DSP */
0096         if (chip->hardware >= SB_HW_20)
0097             snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);
0098     } else {
0099         spin_unlock_irqrestore(&chip->open_lock, flags);
0100     }
0101     return 0;
0102 }
0103 
0104 static int snd_sb8dsp_midi_input_close(struct snd_rawmidi_substream *substream)
0105 {
0106     unsigned long flags;
0107     struct snd_sb *chip;
0108 
0109     chip = substream->rmidi->private_data;
0110     spin_lock_irqsave(&chip->open_lock, flags);
0111     chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER);
0112     chip->midi_substream_input = NULL;
0113     if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) {
0114         spin_unlock_irqrestore(&chip->open_lock, flags);
0115         snd_sbdsp_reset(chip);      /* reset DSP */
0116     } else {
0117         spin_unlock_irqrestore(&chip->open_lock, flags);
0118     }
0119     return 0;
0120 }
0121 
0122 static int snd_sb8dsp_midi_output_close(struct snd_rawmidi_substream *substream)
0123 {
0124     unsigned long flags;
0125     struct snd_sb *chip;
0126 
0127     chip = substream->rmidi->private_data;
0128     del_timer_sync(&chip->midi_timer);
0129     spin_lock_irqsave(&chip->open_lock, flags);
0130     chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER);
0131     chip->midi_substream_output = NULL;
0132     if (!(chip->open & SB_OPEN_MIDI_INPUT)) {
0133         spin_unlock_irqrestore(&chip->open_lock, flags);
0134         snd_sbdsp_reset(chip);      /* reset DSP */
0135     } else {
0136         spin_unlock_irqrestore(&chip->open_lock, flags);
0137     }
0138     return 0;
0139 }
0140 
0141 static void snd_sb8dsp_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
0142 {
0143     unsigned long flags;
0144     struct snd_sb *chip;
0145 
0146     chip = substream->rmidi->private_data;
0147     spin_lock_irqsave(&chip->open_lock, flags);
0148     if (up) {
0149         if (!(chip->open & SB_OPEN_MIDI_INPUT_TRIGGER)) {
0150             if (chip->hardware < SB_HW_20)
0151                 snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ);
0152             chip->open |= SB_OPEN_MIDI_INPUT_TRIGGER;
0153         }
0154     } else {
0155         if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) {
0156             if (chip->hardware < SB_HW_20)
0157                 snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ);
0158             chip->open &= ~SB_OPEN_MIDI_INPUT_TRIGGER;
0159         }
0160     }
0161     spin_unlock_irqrestore(&chip->open_lock, flags);
0162 }
0163 
0164 static void snd_sb8dsp_midi_output_write(struct snd_rawmidi_substream *substream)
0165 {
0166     unsigned long flags;
0167     struct snd_sb *chip;
0168     char byte;
0169     int max = 32;
0170 
0171     /* how big is Tx FIFO? */
0172     chip = substream->rmidi->private_data;
0173     while (max-- > 0) {
0174         spin_lock_irqsave(&chip->open_lock, flags);
0175         if (snd_rawmidi_transmit_peek(substream, &byte, 1) != 1) {
0176             chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;
0177             del_timer(&chip->midi_timer);
0178             spin_unlock_irqrestore(&chip->open_lock, flags);
0179             break;
0180         }
0181         if (chip->hardware >= SB_HW_20) {
0182             int timeout = 8;
0183             while ((inb(SBP(chip, STATUS)) & 0x80) != 0 && --timeout > 0)
0184                 ;
0185             if (timeout == 0) {
0186                 /* Tx FIFO full - try again later */
0187                 spin_unlock_irqrestore(&chip->open_lock, flags);
0188                 break;
0189             }
0190             outb(byte, SBP(chip, WRITE));
0191         } else {
0192             snd_sbdsp_command(chip, SB_DSP_MIDI_OUTPUT);
0193             snd_sbdsp_command(chip, byte);
0194         }
0195         snd_rawmidi_transmit_ack(substream, 1);
0196         spin_unlock_irqrestore(&chip->open_lock, flags);
0197     }
0198 }
0199 
0200 static void snd_sb8dsp_midi_output_timer(struct timer_list *t)
0201 {
0202     struct snd_sb *chip = from_timer(chip, t, midi_timer);
0203     struct snd_rawmidi_substream *substream = chip->midi_substream_output;
0204     unsigned long flags;
0205 
0206     spin_lock_irqsave(&chip->open_lock, flags);
0207     mod_timer(&chip->midi_timer, 1 + jiffies);
0208     spin_unlock_irqrestore(&chip->open_lock, flags);    
0209     snd_sb8dsp_midi_output_write(substream);
0210 }
0211 
0212 static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
0213 {
0214     unsigned long flags;
0215     struct snd_sb *chip;
0216 
0217     chip = substream->rmidi->private_data;
0218     spin_lock_irqsave(&chip->open_lock, flags);
0219     if (up) {
0220         if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) {
0221             mod_timer(&chip->midi_timer, 1 + jiffies);
0222             chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER;
0223         }
0224     } else {
0225         if (chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER) {
0226             chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;
0227         }
0228     }
0229     spin_unlock_irqrestore(&chip->open_lock, flags);
0230 
0231     if (up)
0232         snd_sb8dsp_midi_output_write(substream);
0233 }
0234 
0235 static const struct snd_rawmidi_ops snd_sb8dsp_midi_output =
0236 {
0237     .open =     snd_sb8dsp_midi_output_open,
0238     .close =    snd_sb8dsp_midi_output_close,
0239     .trigger =  snd_sb8dsp_midi_output_trigger,
0240 };
0241 
0242 static const struct snd_rawmidi_ops snd_sb8dsp_midi_input =
0243 {
0244     .open =     snd_sb8dsp_midi_input_open,
0245     .close =    snd_sb8dsp_midi_input_close,
0246     .trigger =  snd_sb8dsp_midi_input_trigger,
0247 };
0248 
0249 int snd_sb8dsp_midi(struct snd_sb *chip, int device)
0250 {
0251     struct snd_rawmidi *rmidi;
0252     int err;
0253 
0254     err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi);
0255     if (err < 0)
0256         return err;
0257     strcpy(rmidi->name, "SB8 MIDI");
0258     snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_sb8dsp_midi_output);
0259     snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_sb8dsp_midi_input);
0260     rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT;
0261     if (chip->hardware >= SB_HW_20)
0262         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
0263     rmidi->private_data = chip;
0264     timer_setup(&chip->midi_timer, snd_sb8dsp_midi_output_timer, 0);
0265     chip->rmidi = rmidi;
0266     return 0;
0267 }