root/sound/isa/gus/gus_uart.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_gf1_interrupt_midi_in
  2. snd_gf1_interrupt_midi_out
  3. snd_gf1_uart_reset
  4. snd_gf1_uart_output_open
  5. snd_gf1_uart_input_open
  6. snd_gf1_uart_output_close
  7. snd_gf1_uart_input_close
  8. snd_gf1_uart_input_trigger
  9. snd_gf1_uart_output_trigger
  10. snd_gf1_rawmidi_new

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

/* [<][>][^][v][top][bottom][index][help] */