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