gus_uart.c 7.9 KB

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