1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * Routines for the GF1 MIDI interface - like UART 6850 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/interrupt.h> 9 #include <linux/time.h> 10 #include <sound/core.h> 11 #include <sound/gus.h> 12 13 static void snd_gf1_interrupt_midi_in(struct snd_gus_card * gus) 14 { 15 int count; 16 unsigned char stat, byte; 17 __always_unused unsigned char data; 18 unsigned long flags; 19 20 count = 10; 21 while (count) { 22 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 23 stat = snd_gf1_uart_stat(gus); 24 if (!(stat & 0x01)) { /* data in Rx FIFO? */ 25 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 26 count--; 27 continue; 28 } 29 count = 100; /* arm counter to new value */ 30 data = snd_gf1_uart_get(gus); 31 if (!(gus->gf1.uart_cmd & 0x80)) { 32 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 33 continue; 34 } 35 if (stat & 0x10) { /* framing error */ 36 gus->gf1.uart_framing++; 37 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 38 continue; 39 } 40 byte = snd_gf1_uart_get(gus); 41 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 42 snd_rawmidi_receive(gus->midi_substream_input, &byte, 1); 43 if (stat & 0x20) { 44 gus->gf1.uart_overrun++; 45 } 46 } 47 } 48 49 static void snd_gf1_interrupt_midi_out(struct snd_gus_card * gus) 50 { 51 char byte; 52 unsigned long flags; 53 54 /* try unlock output */ 55 if (snd_gf1_uart_stat(gus) & 0x01) 56 snd_gf1_interrupt_midi_in(gus); 57 58 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 59 if (snd_gf1_uart_stat(gus) & 0x02) { /* Tx FIFO free? */ 60 if (snd_rawmidi_transmit(gus->midi_substream_output, &byte, 1) != 1) { /* no other bytes or error */ 61 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x20); /* disable Tx interrupt */ 62 } else { 63 snd_gf1_uart_put(gus, byte); 64 } 65 } 66 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 67 } 68 69 static void snd_gf1_uart_reset(struct snd_gus_card * gus, int close) 70 { 71 snd_gf1_uart_cmd(gus, 0x03); /* reset */ 72 if (!close && gus->uart_enable) { 73 udelay(160); 74 snd_gf1_uart_cmd(gus, 0x00); /* normal operations */ 75 } 76 } 77 78 static int snd_gf1_uart_output_open(struct snd_rawmidi_substream *substream) 79 { 80 unsigned long flags; 81 struct snd_gus_card *gus; 82 83 gus = substream->rmidi->private_data; 84 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 85 if (!(gus->gf1.uart_cmd & 0x80)) { /* input active? */ 86 snd_gf1_uart_reset(gus, 0); 87 } 88 gus->gf1.interrupt_handler_midi_out = snd_gf1_interrupt_midi_out; 89 gus->midi_substream_output = substream; 90 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 91 #if 0 92 dev_dbg(gus->card->dev, 93 "write init - cmd = 0x%x, stat = 0x%x\n", 94 gus->gf1.uart_cmd, snd_gf1_uart_stat(gus)); 95 #endif 96 return 0; 97 } 98 99 static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream) 100 { 101 unsigned long flags; 102 struct snd_gus_card *gus; 103 int i; 104 105 gus = substream->rmidi->private_data; 106 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 107 if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) { 108 snd_gf1_uart_reset(gus, 0); 109 } 110 gus->gf1.interrupt_handler_midi_in = snd_gf1_interrupt_midi_in; 111 gus->midi_substream_input = substream; 112 if (gus->uart_enable) { 113 for (i = 0; i < 1000 && (snd_gf1_uart_stat(gus) & 0x01); i++) 114 snd_gf1_uart_get(gus); /* clean Rx */ 115 if (i >= 1000) 116 dev_err(gus->card->dev, "gus midi uart init read - cleanup error\n"); 117 } 118 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 119 #if 0 120 dev_dbg(gus->card->dev, 121 "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n", 122 gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus)); 123 dev_dbg(gus->card->dev, 124 "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x (page = 0x%x)\n", 125 gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100), 126 inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102)); 127 #endif 128 return 0; 129 } 130 131 static int snd_gf1_uart_output_close(struct snd_rawmidi_substream *substream) 132 { 133 unsigned long flags; 134 struct snd_gus_card *gus; 135 136 gus = substream->rmidi->private_data; 137 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 138 if (gus->gf1.interrupt_handler_midi_in != snd_gf1_interrupt_midi_in) 139 snd_gf1_uart_reset(gus, 1); 140 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_OUT); 141 gus->midi_substream_output = NULL; 142 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 143 return 0; 144 } 145 146 static int snd_gf1_uart_input_close(struct snd_rawmidi_substream *substream) 147 { 148 unsigned long flags; 149 struct snd_gus_card *gus; 150 151 gus = substream->rmidi->private_data; 152 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 153 if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) 154 snd_gf1_uart_reset(gus, 1); 155 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_MIDI_IN); 156 gus->midi_substream_input = NULL; 157 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 158 return 0; 159 } 160 161 static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) 162 { 163 struct snd_gus_card *gus; 164 unsigned long flags; 165 166 gus = substream->rmidi->private_data; 167 168 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 169 if (up) { 170 if ((gus->gf1.uart_cmd & 0x80) == 0) 171 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd | 0x80); /* enable Rx interrupts */ 172 } else { 173 if (gus->gf1.uart_cmd & 0x80) 174 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x80); /* disable Rx interrupts */ 175 } 176 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 177 } 178 179 static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) 180 { 181 unsigned long flags; 182 struct snd_gus_card *gus; 183 char byte; 184 int timeout; 185 186 gus = substream->rmidi->private_data; 187 188 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 189 if (up) { 190 if ((gus->gf1.uart_cmd & 0x20) == 0) { 191 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 192 /* wait for empty Rx - Tx is probably unlocked */ 193 timeout = 10000; 194 while (timeout-- > 0 && snd_gf1_uart_stat(gus) & 0x01); 195 /* Tx FIFO free? */ 196 spin_lock_irqsave(&gus->uart_cmd_lock, flags); 197 if (gus->gf1.uart_cmd & 0x20) { 198 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 199 return; 200 } 201 if (snd_gf1_uart_stat(gus) & 0x02) { 202 if (snd_rawmidi_transmit(substream, &byte, 1) != 1) { 203 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 204 return; 205 } 206 snd_gf1_uart_put(gus, byte); 207 } 208 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd | 0x20); /* enable Tx interrupt */ 209 } 210 } else { 211 if (gus->gf1.uart_cmd & 0x20) 212 snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd & ~0x20); 213 } 214 spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); 215 } 216 217 static const struct snd_rawmidi_ops snd_gf1_uart_output = 218 { 219 .open = snd_gf1_uart_output_open, 220 .close = snd_gf1_uart_output_close, 221 .trigger = snd_gf1_uart_output_trigger, 222 }; 223 224 static const struct snd_rawmidi_ops snd_gf1_uart_input = 225 { 226 .open = snd_gf1_uart_input_open, 227 .close = snd_gf1_uart_input_close, 228 .trigger = snd_gf1_uart_input_trigger, 229 }; 230 231 int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device) 232 { 233 struct snd_rawmidi *rmidi; 234 int err; 235 236 err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi); 237 if (err < 0) 238 return err; 239 strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1"); 240 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_gf1_uart_output); 241 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_gf1_uart_input); 242 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; 243 rmidi->private_data = gus; 244 gus->midi_uart = rmidi; 245 return err; 246 } 247