root/sound/isa/msnd/msnd_midi.c

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

DEFINITIONS

This source file includes following definitions.
  1. snd_msndmidi_input_open
  2. snd_msndmidi_input_close
  3. snd_msndmidi_input_drop
  4. snd_msndmidi_input_trigger
  5. snd_msndmidi_input_read
  6. snd_msndmidi_free
  7. snd_msndmidi_new

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   4  *  Copyright (c) 2009 by Krzysztof Helt
   5  *  Routines for control of MPU-401 in UART mode
   6  *
   7  *  MPU-401 supports UART mode which is not capable generate transmit
   8  *  interrupts thus output is done via polling. Also, if irq < 0, then
   9  *  input is done also via polling. Do not expect good performance.
  10  */
  11 
  12 #include <linux/io.h>
  13 #include <linux/slab.h>
  14 #include <linux/delay.h>
  15 #include <linux/ioport.h>
  16 #include <linux/errno.h>
  17 #include <linux/export.h>
  18 #include <sound/core.h>
  19 #include <sound/rawmidi.h>
  20 
  21 #include "msnd.h"
  22 
  23 #define MSNDMIDI_MODE_BIT_INPUT         0
  24 #define MSNDMIDI_MODE_BIT_OUTPUT                1
  25 #define MSNDMIDI_MODE_BIT_INPUT_TRIGGER 2
  26 #define MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER        3
  27 
  28 struct snd_msndmidi {
  29         struct snd_msnd *dev;
  30 
  31         unsigned long mode;             /* MSNDMIDI_MODE_XXXX */
  32 
  33         struct snd_rawmidi_substream *substream_input;
  34 
  35         spinlock_t input_lock;
  36 };
  37 
  38 /*
  39  * input/output open/close - protected by open_mutex in rawmidi.c
  40  */
  41 static int snd_msndmidi_input_open(struct snd_rawmidi_substream *substream)
  42 {
  43         struct snd_msndmidi *mpu;
  44 
  45         snd_printdd("snd_msndmidi_input_open()\n");
  46 
  47         mpu = substream->rmidi->private_data;
  48 
  49         mpu->substream_input = substream;
  50 
  51         snd_msnd_enable_irq(mpu->dev);
  52 
  53         snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_START);
  54         set_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
  55         return 0;
  56 }
  57 
  58 static int snd_msndmidi_input_close(struct snd_rawmidi_substream *substream)
  59 {
  60         struct snd_msndmidi *mpu;
  61 
  62         mpu = substream->rmidi->private_data;
  63         snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_STOP);
  64         clear_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
  65         mpu->substream_input = NULL;
  66         snd_msnd_disable_irq(mpu->dev);
  67         return 0;
  68 }
  69 
  70 static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu)
  71 {
  72         u16 tail;
  73 
  74         tail = readw(mpu->dev->MIDQ + JQS_wTail);
  75         writew(tail, mpu->dev->MIDQ + JQS_wHead);
  76 }
  77 
  78 /*
  79  * trigger input
  80  */
  81 static void snd_msndmidi_input_trigger(struct snd_rawmidi_substream *substream,
  82                                         int up)
  83 {
  84         unsigned long flags;
  85         struct snd_msndmidi *mpu;
  86 
  87         snd_printdd("snd_msndmidi_input_trigger(, %i)\n", up);
  88 
  89         mpu = substream->rmidi->private_data;
  90         spin_lock_irqsave(&mpu->input_lock, flags);
  91         if (up) {
  92                 if (!test_and_set_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
  93                                       &mpu->mode))
  94                         snd_msndmidi_input_drop(mpu);
  95         } else {
  96                 clear_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
  97         }
  98         spin_unlock_irqrestore(&mpu->input_lock, flags);
  99         if (up)
 100                 snd_msndmidi_input_read(mpu);
 101 }
 102 
 103 void snd_msndmidi_input_read(void *mpuv)
 104 {
 105         unsigned long flags;
 106         struct snd_msndmidi *mpu = mpuv;
 107         void __iomem *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
 108         u16 head, tail, size;
 109 
 110         spin_lock_irqsave(&mpu->input_lock, flags);
 111         head = readw(mpu->dev->MIDQ + JQS_wHead);
 112         tail = readw(mpu->dev->MIDQ + JQS_wTail);
 113         size = readw(mpu->dev->MIDQ + JQS_wSize);
 114         if (head > size || tail > size)
 115                 goto out;
 116         while (head != tail) {
 117                 unsigned char val = readw(pwMIDQData + 2 * head);
 118 
 119                 if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
 120                         snd_rawmidi_receive(mpu->substream_input, &val, 1);
 121                 if (++head > size)
 122                         head = 0;
 123                 writew(head, mpu->dev->MIDQ + JQS_wHead);
 124         }
 125  out:
 126         spin_unlock_irqrestore(&mpu->input_lock, flags);
 127 }
 128 EXPORT_SYMBOL(snd_msndmidi_input_read);
 129 
 130 static const struct snd_rawmidi_ops snd_msndmidi_input = {
 131         .open =         snd_msndmidi_input_open,
 132         .close =        snd_msndmidi_input_close,
 133         .trigger =      snd_msndmidi_input_trigger,
 134 };
 135 
 136 static void snd_msndmidi_free(struct snd_rawmidi *rmidi)
 137 {
 138         struct snd_msndmidi *mpu = rmidi->private_data;
 139         kfree(mpu);
 140 }
 141 
 142 int snd_msndmidi_new(struct snd_card *card, int device)
 143 {
 144         struct snd_msnd *chip = card->private_data;
 145         struct snd_msndmidi *mpu;
 146         struct snd_rawmidi *rmidi;
 147         int err;
 148 
 149         err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi);
 150         if (err < 0)
 151                 return err;
 152         mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
 153         if (mpu == NULL) {
 154                 snd_device_free(card, rmidi);
 155                 return -ENOMEM;
 156         }
 157         mpu->dev = chip;
 158         chip->msndmidi_mpu = mpu;
 159         rmidi->private_data = mpu;
 160         rmidi->private_free = snd_msndmidi_free;
 161         spin_lock_init(&mpu->input_lock);
 162         strcpy(rmidi->name, "MSND MIDI");
 163         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
 164                             &snd_msndmidi_input);
 165         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
 166         return 0;
 167 }

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