0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
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));
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);
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);
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);
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);
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
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
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 }