1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4 * Routines for the GF1 MIDI interface - like UART 6850
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>
13 static void snd_gf1_interrupt_midi_in(struct snd_gus_card
* gus
)
16 unsigned char stat
, byte
;
17 __always_unused
unsigned char data
;
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
);
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
);
35 if (stat
& 0x10) { /* framing error */
36 gus
->gf1
.uart_framing
++;
37 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
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);
44 gus
->gf1
.uart_overrun
++;
49 static void snd_gf1_interrupt_midi_out(struct snd_gus_card
* gus
)
54 /* try unlock output */
55 if (snd_gf1_uart_stat(gus
) & 0x01)
56 snd_gf1_interrupt_midi_in(gus
);
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 */
63 snd_gf1_uart_put(gus
, byte
);
66 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
69 static void snd_gf1_uart_reset(struct snd_gus_card
* gus
, int close
)
71 snd_gf1_uart_cmd(gus
, 0x03); /* reset */
72 if (!close
&& gus
->uart_enable
) {
74 snd_gf1_uart_cmd(gus
, 0x00); /* normal operations */
78 static int snd_gf1_uart_output_open(struct snd_rawmidi_substream
*substream
)
81 struct snd_gus_card
*gus
;
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);
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
);
92 snd_printk(KERN_DEBUG
"write init - cmd = 0x%x, stat = 0x%x\n", gus
->gf1
.uart_cmd
, snd_gf1_uart_stat(gus
));
97 static int snd_gf1_uart_input_open(struct snd_rawmidi_substream
*substream
)
100 struct snd_gus_card
*gus
;
103 gus
= substream
->rmidi
->private_data
;
104 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
105 if (gus
->gf1
.interrupt_handler_midi_out
!= snd_gf1_interrupt_midi_out
) {
106 snd_gf1_uart_reset(gus
, 0);
108 gus
->gf1
.interrupt_handler_midi_in
= snd_gf1_interrupt_midi_in
;
109 gus
->midi_substream_input
= substream
;
110 if (gus
->uart_enable
) {
111 for (i
= 0; i
< 1000 && (snd_gf1_uart_stat(gus
) & 0x01); i
++)
112 snd_gf1_uart_get(gus
); /* clean Rx */
114 snd_printk(KERN_ERR
"gus midi uart init read - cleanup error\n");
116 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
118 snd_printk(KERN_DEBUG
119 "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
120 gus
->uart_enable
, gus
->gf1
.uart_cmd
, snd_gf1_uart_stat(gus
));
121 snd_printk(KERN_DEBUG
122 "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x "
124 gus
->gf1
.port
+ 0x100, inb(gus
->gf1
.port
+ 0x100),
125 inb(gus
->gf1
.port
+ 0x101), inb(gus
->gf1
.port
+ 0x102));
130 static int snd_gf1_uart_output_close(struct snd_rawmidi_substream
*substream
)
133 struct snd_gus_card
*gus
;
135 gus
= substream
->rmidi
->private_data
;
136 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
137 if (gus
->gf1
.interrupt_handler_midi_in
!= snd_gf1_interrupt_midi_in
)
138 snd_gf1_uart_reset(gus
, 1);
139 snd_gf1_set_default_handlers(gus
, SNDRV_GF1_HANDLER_MIDI_OUT
);
140 gus
->midi_substream_output
= NULL
;
141 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
145 static int snd_gf1_uart_input_close(struct snd_rawmidi_substream
*substream
)
148 struct snd_gus_card
*gus
;
150 gus
= substream
->rmidi
->private_data
;
151 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
152 if (gus
->gf1
.interrupt_handler_midi_out
!= snd_gf1_interrupt_midi_out
)
153 snd_gf1_uart_reset(gus
, 1);
154 snd_gf1_set_default_handlers(gus
, SNDRV_GF1_HANDLER_MIDI_IN
);
155 gus
->midi_substream_input
= NULL
;
156 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
160 static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream
*substream
, int up
)
162 struct snd_gus_card
*gus
;
165 gus
= substream
->rmidi
->private_data
;
167 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
169 if ((gus
->gf1
.uart_cmd
& 0x80) == 0)
170 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
| 0x80); /* enable Rx interrupts */
172 if (gus
->gf1
.uart_cmd
& 0x80)
173 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x80); /* disable Rx interrupts */
175 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
178 static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream
*substream
, int up
)
181 struct snd_gus_card
*gus
;
185 gus
= substream
->rmidi
->private_data
;
187 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
189 if ((gus
->gf1
.uart_cmd
& 0x20) == 0) {
190 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
191 /* wait for empty Rx - Tx is probably unlocked */
193 while (timeout
-- > 0 && snd_gf1_uart_stat(gus
) & 0x01);
195 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
196 if (gus
->gf1
.uart_cmd
& 0x20) {
197 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
200 if (snd_gf1_uart_stat(gus
) & 0x02) {
201 if (snd_rawmidi_transmit(substream
, &byte
, 1) != 1) {
202 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
205 snd_gf1_uart_put(gus
, byte
);
207 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
| 0x20); /* enable Tx interrupt */
210 if (gus
->gf1
.uart_cmd
& 0x20)
211 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x20);
213 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
216 static const struct snd_rawmidi_ops snd_gf1_uart_output
=
218 .open
= snd_gf1_uart_output_open
,
219 .close
= snd_gf1_uart_output_close
,
220 .trigger
= snd_gf1_uart_output_trigger
,
223 static const struct snd_rawmidi_ops snd_gf1_uart_input
=
225 .open
= snd_gf1_uart_input_open
,
226 .close
= snd_gf1_uart_input_close
,
227 .trigger
= snd_gf1_uart_input_trigger
,
230 int snd_gf1_rawmidi_new(struct snd_gus_card
*gus
, int device
)
232 struct snd_rawmidi
*rmidi
;
235 if ((err
= snd_rawmidi_new(gus
->card
, "GF1", device
, 1, 1, &rmidi
)) < 0)
237 strcpy(rmidi
->name
, gus
->interwave
? "AMD InterWave" : "GF1");
238 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_OUTPUT
, &snd_gf1_uart_output
);
239 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_INPUT
, &snd_gf1_uart_input
);
240 rmidi
->info_flags
|= SNDRV_RAWMIDI_INFO_OUTPUT
| SNDRV_RAWMIDI_INFO_INPUT
| SNDRV_RAWMIDI_INFO_DUPLEX
;
241 rmidi
->private_data
= gus
;
242 gus
->midi_uart
= rmidi
;