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
);
108 static int snd_gf1_uart_input_open(struct snd_rawmidi_substream
*substream
)
111 struct snd_gus_card
*gus
;
114 gus
= substream
->rmidi
->private_data
;
115 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
116 if (gus
->gf1
.interrupt_handler_midi_out
!= snd_gf1_interrupt_midi_out
) {
117 snd_gf1_uart_reset(gus
, 0);
119 gus
->gf1
.interrupt_handler_midi_in
= snd_gf1_interrupt_midi_in
;
120 gus
->midi_substream_input
= substream
;
121 if (gus
->uart_enable
) {
122 for (i
= 0; i
< 1000 && (snd_gf1_uart_stat(gus
) & 0x01); i
++)
123 snd_gf1_uart_get(gus
); /* clean Rx */
125 snd_printk(KERN_ERR
"gus midi uart init read - cleanup error\n");
127 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
131 static int snd_gf1_uart_output_close(struct snd_rawmidi_substream
*substream
)
134 struct snd_gus_card
*gus
;
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
);
146 static int snd_gf1_uart_input_close(struct snd_rawmidi_substream
*substream
)
149 struct snd_gus_card
*gus
;
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
);
161 static void snd_gf1_uart_input_trigger(struct snd_rawmidi_substream
*substream
, int up
)
163 struct snd_gus_card
*gus
;
166 gus
= substream
->rmidi
->private_data
;
168 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
170 if ((gus
->gf1
.uart_cmd
& 0x80) == 0)
171 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
| 0x80); /* enable Rx interrupts */
173 if (gus
->gf1
.uart_cmd
& 0x80)
174 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x80); /* disable Rx interrupts */
176 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
179 static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream
*substream
, int up
)
182 struct snd_gus_card
*gus
;
186 gus
= substream
->rmidi
->private_data
;
188 spin_lock_irqsave(&gus
->uart_cmd_lock
, flags
);
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 */
194 while (timeout
-- > 0 && snd_gf1_uart_stat(gus
) & 0x01);
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
);
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
);
206 snd_gf1_uart_put(gus
, byte
);
208 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
| 0x20); /* enable Tx interrupt */
211 if (gus
->gf1
.uart_cmd
& 0x20)
212 snd_gf1_uart_cmd(gus
, gus
->gf1
.uart_cmd
& ~0x20);
214 spin_unlock_irqrestore(&gus
->uart_cmd_lock
, flags
);
217 static struct snd_rawmidi_ops snd_gf1_uart_output
=
219 .open
= snd_gf1_uart_output_open
,
220 .close
= snd_gf1_uart_output_close
,
221 .trigger
= snd_gf1_uart_output_trigger
,
224 static struct snd_rawmidi_ops snd_gf1_uart_input
=
226 .open
= snd_gf1_uart_input_open
,
227 .close
= snd_gf1_uart_input_close
,
228 .trigger
= snd_gf1_uart_input_trigger
,
231 int snd_gf1_rawmidi_new(struct snd_gus_card
* gus
, int device
, struct snd_rawmidi
** rrawmidi
)
233 struct snd_rawmidi
*rmidi
;
238 if ((err
= snd_rawmidi_new(gus
->card
, "GF1", device
, 1, 1, &rmidi
)) < 0)
240 strcpy(rmidi
->name
, gus
->interwave
? "AMD InterWave" : "GF1");
241 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_OUTPUT
, &snd_gf1_uart_output
);
242 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_INPUT
, &snd_gf1_uart_input
);
243 rmidi
->info_flags
|= SNDRV_RAWMIDI_INFO_OUTPUT
| SNDRV_RAWMIDI_INFO_INPUT
| SNDRV_RAWMIDI_INFO_DUPLEX
;
244 rmidi
->private_data
= gus
;
245 gus
->midi_uart
= rmidi
;