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(KERN_DEBUG
133 "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
134 gus
->uart_enable
, gus
->gf1
.uart_cmd
, snd_gf1_uart_stat(gus
));
135 snd_printk(KERN_DEBUG
136 "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x "
138 gus
->gf1
.port
+ 0x100, inb(gus
->gf1
.port
+ 0x100),
139 inb(gus
->gf1
.port
+ 0x101), inb(gus
->gf1
.port
+ 0x102));
144 static int snd_gf1_uart_output_close(struct snd_rawmidi_substream
*substream
)
147 struct snd_gus_card
*gus
;
149 gus
= substream
->rmidi
->private_data
;
150 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
151 if (gus
->gf1
.interrupt_handler_midi_in
!= snd_gf1_interrupt_midi_in
)
152 snd_gf1_uart_reset(gus
, 1);
153 snd_gf1_set_default_handlers(gus
, SNDRV_GF1_HANDLER_MIDI_OUT
);
154 gus
->midi_substream_output
= NULL
;
155 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
159 static int snd_gf1_uart_input_close(struct snd_rawmidi_substream
*substream
)
162 struct snd_gus_card
*gus
;
164 gus
= substream
->rmidi
->private_data
;
165 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
166 if (gus
->gf1
.interrupt_handler_midi_out
!= snd_gf1_interrupt_midi_out
)
167 snd_gf1_uart_reset(gus
, 1);
168 snd_gf1_set_default_handlers(gus
, SNDRV_GF1_HANDLER_MIDI_IN
);
169 gus
->midi_substream_input
= NULL
;
170 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
174 static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream
*substream
, int up
)
176 struct snd_gus_card
*gus
;
179 gus
= substream
->rmidi
->private_data
;
181 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
183 if ((gus
->gf1
.uart_cmd
& 0x80) == 0)
184 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
| 0x80); /* enable Rx interrupts */
186 if (gus
->gf1
.uart_cmd
& 0x80)
187 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x80); /* disable Rx interrupts */
189 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
192 static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream
*substream
, int up
)
195 struct snd_gus_card
*gus
;
199 gus
= substream
->rmidi
->private_data
;
201 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
203 if ((gus
->gf1
.uart_cmd
& 0x20) == 0) {
204 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
205 /* wait for empty Rx - Tx is probably unlocked */
207 while (timeout
-- > 0 && snd_gf1_uart_stat(gus
) & 0x01);
209 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
210 if (gus
->gf1
.uart_cmd
& 0x20) {
211 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
214 if (snd_gf1_uart_stat(gus
) & 0x02) {
215 if (snd_rawmidi_transmit(substream
, &byte
, 1) != 1) {
216 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
219 snd_gf1_uart_put(gus
, byte
);
221 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
| 0x20); /* enable Tx interrupt */
224 if (gus
->gf1
.uart_cmd
& 0x20)
225 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x20);
227 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
230 static struct snd_rawmidi_ops snd_gf1_uart_output
=
232 .open
= snd_gf1_uart_output_open
,
233 .close
= snd_gf1_uart_output_close
,
234 .trigger
= snd_gf1_uart_output_trigger
,
237 static struct snd_rawmidi_ops snd_gf1_uart_input
=
239 .open
= snd_gf1_uart_input_open
,
240 .close
= snd_gf1_uart_input_close
,
241 .trigger
= snd_gf1_uart_input_trigger
,
244 int snd_gf1_rawmidi_new(struct snd_gus_card
* gus
, int device
, struct snd_rawmidi
** rrawmidi
)
246 struct snd_rawmidi
*rmidi
;
251 if ((err
= snd_rawmidi_new(gus
->card
, "GF1", device
, 1, 1, &rmidi
)) < 0)
253 strcpy(rmidi
->name
, gus
->interwave
? "AMD InterWave" : "GF1");
254 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_OUTPUT
, &snd_gf1_uart_output
);
255 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_INPUT
, &snd_gf1_uart_input
);
256 rmidi
->info_flags
|= SNDRV_RAWMIDI_INFO_OUTPUT
| SNDRV_RAWMIDI_INFO_INPUT
| SNDRV_RAWMIDI_INFO_DUPLEX
;
257 rmidi
->private_data
= gus
;
258 gus
->midi_uart
= rmidi
;