2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
3 * Routines for the GF1 MIDI interface - like UART 6850
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/delay.h>
23 #include <linux/interrupt.h>
24 #include <linux/time.h>
25 #include <sound/core.h>
26 #include <sound/gus.h>
28 static void snd_gf1_interrupt_midi_in(struct snd_gus_card
* gus
)
31 unsigned char stat
, data
, byte
;
36 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
37 stat
= snd_gf1_uart_stat(gus
);
38 if (!(stat
& 0x01)) { /* data in Rx FIFO? */
39 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
43 count
= 100; /* arm counter to new value */
44 data
= snd_gf1_uart_get(gus
);
45 if (!(gus
->gf1
.uart_cmd
& 0x80)) {
46 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
49 if (stat
& 0x10) { /* framing error */
50 gus
->gf1
.uart_framing
++;
51 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
54 byte
= snd_gf1_uart_get(gus
);
55 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
56 snd_rawmidi_receive(gus
->midi_substream_input
, &byte
, 1);
58 gus
->gf1
.uart_overrun
++;
63 static void snd_gf1_interrupt_midi_out(struct snd_gus_card
* gus
)
68 /* try unlock output */
69 if (snd_gf1_uart_stat(gus
) & 0x01)
70 snd_gf1_interrupt_midi_in(gus
);
72 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
73 if (snd_gf1_uart_stat(gus
) & 0x02) { /* Tx FIFO free? */
74 if (snd_rawmidi_transmit(gus
->midi_substream_output
, &byte
, 1) != 1) { /* no other bytes or error */
75 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x20); /* disable Tx interrupt */
77 snd_gf1_uart_put(gus
, byte
);
80 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
83 static void snd_gf1_uart_reset(struct snd_gus_card
* gus
, int close
)
85 snd_gf1_uart_cmd(gus
, 0x03); /* reset */
86 if (!close
&& gus
->uart_enable
) {
88 snd_gf1_uart_cmd(gus
, 0x00); /* normal operations */
92 static int snd_gf1_uart_output_open(struct snd_rawmidi_substream
*substream
)
95 struct snd_gus_card
*gus
;
97 gus
= substream
->rmidi
->private_data
;
98 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
99 if (!(gus
->gf1
.uart_cmd
& 0x80)) { /* input active? */
100 snd_gf1_uart_reset(gus
, 0);
102 gus
->gf1
.interrupt_handler_midi_out
= snd_gf1_interrupt_midi_out
;
103 gus
->midi_substream_output
= substream
;
104 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
106 snd_printk(KERN_DEBUG
"write init - cmd = 0x%x, stat = 0x%x\n", gus
->gf1
.uart_cmd
, snd_gf1_uart_stat(gus
));
111 static int snd_gf1_uart_input_open(struct snd_rawmidi_substream
*substream
)
114 struct snd_gus_card
*gus
;
117 gus
= substream
->rmidi
->private_data
;
118 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
119 if (gus
->gf1
.interrupt_handler_midi_out
!= snd_gf1_interrupt_midi_out
) {
120 snd_gf1_uart_reset(gus
, 0);
122 gus
->gf1
.interrupt_handler_midi_in
= snd_gf1_interrupt_midi_in
;
123 gus
->midi_substream_input
= substream
;
124 if (gus
->uart_enable
) {
125 for (i
= 0; i
< 1000 && (snd_gf1_uart_stat(gus
) & 0x01); i
++)
126 snd_gf1_uart_get(gus
); /* clean Rx */
128 snd_printk(KERN_ERR
"gus midi uart init read - cleanup error\n");
130 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
132 snd_printk("read init - enable = %i, cmd = 0x%x, stat = 0x%x\n", gus
->uart_enable
, gus
->gf1
.uart_cmd
, snd_gf1_uart_stat(gus
));
133 snd_printk("[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x (page = 0x%x)\n", gus
->gf1
.port
+ 0x100, inb(gus
->gf1
.port
+ 0x100), inb(gus
->gf1
.port
+ 0x101), inb(gus
->gf1
.port
+ 0x102));
138 static int snd_gf1_uart_output_close(struct snd_rawmidi_substream
*substream
)
141 struct snd_gus_card
*gus
;
143 gus
= substream
->rmidi
->private_data
;
144 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
145 if (gus
->gf1
.interrupt_handler_midi_in
!= snd_gf1_interrupt_midi_in
)
146 snd_gf1_uart_reset(gus
, 1);
147 snd_gf1_set_default_handlers(gus
, SNDRV_GF1_HANDLER_MIDI_OUT
);
148 gus
->midi_substream_output
= NULL
;
149 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
153 static int snd_gf1_uart_input_close(struct snd_rawmidi_substream
*substream
)
156 struct snd_gus_card
*gus
;
158 gus
= substream
->rmidi
->private_data
;
159 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
160 if (gus
->gf1
.interrupt_handler_midi_out
!= snd_gf1_interrupt_midi_out
)
161 snd_gf1_uart_reset(gus
, 1);
162 snd_gf1_set_default_handlers(gus
, SNDRV_GF1_HANDLER_MIDI_IN
);
163 gus
->midi_substream_input
= NULL
;
164 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
168 static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream
*substream
, int up
)
170 struct snd_gus_card
*gus
;
173 gus
= substream
->rmidi
->private_data
;
175 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
177 if ((gus
->gf1
.uart_cmd
& 0x80) == 0)
178 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
| 0x80); /* enable Rx interrupts */
180 if (gus
->gf1
.uart_cmd
& 0x80)
181 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x80); /* disable Rx interrupts */
183 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
186 static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream
*substream
, int up
)
189 struct snd_gus_card
*gus
;
193 gus
= substream
->rmidi
->private_data
;
195 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
197 if ((gus
->gf1
.uart_cmd
& 0x20) == 0) {
198 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
199 /* wait for empty Rx - Tx is probably unlocked */
201 while (timeout
-- > 0 && snd_gf1_uart_stat(gus
) & 0x01);
203 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
204 if (gus
->gf1
.uart_cmd
& 0x20) {
205 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
208 if (snd_gf1_uart_stat(gus
) & 0x02) {
209 if (snd_rawmidi_transmit(substream
, &byte
, 1) != 1) {
210 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
213 snd_gf1_uart_put(gus
, byte
);
215 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
| 0x20); /* enable Tx interrupt */
218 if (gus
->gf1
.uart_cmd
& 0x20)
219 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x20);
221 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
224 static struct snd_rawmidi_ops snd_gf1_uart_output
=
226 .open
= snd_gf1_uart_output_open
,
227 .close
= snd_gf1_uart_output_close
,
228 .trigger
= snd_gf1_uart_output_trigger
,
231 static struct snd_rawmidi_ops snd_gf1_uart_input
=
233 .open
= snd_gf1_uart_input_open
,
234 .close
= snd_gf1_uart_input_close
,
235 .trigger
= snd_gf1_uart_input_trigger
,
238 int snd_gf1_rawmidi_new(struct snd_gus_card
* gus
, int device
, struct snd_rawmidi
** rrawmidi
)
240 struct snd_rawmidi
*rmidi
;
245 if ((err
= snd_rawmidi_new(gus
->card
, "GF1", device
, 1, 1, &rmidi
)) < 0)
247 strcpy(rmidi
->name
, gus
->interwave
? "AMD InterWave" : "GF1");
248 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_OUTPUT
, &snd_gf1_uart_output
);
249 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_INPUT
, &snd_gf1_uart_input
);
250 rmidi
->info_flags
|= SNDRV_RAWMIDI_INFO_OUTPUT
| SNDRV_RAWMIDI_INFO_INPUT
| SNDRV_RAWMIDI_INFO_DUPLEX
;
251 rmidi
->private_data
= gus
;
252 gus
->midi_uart
= rmidi
;