gus_uart.c 7.2 KB

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