Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   Copyright (c) 2006,2007 Daniel Mack
0004 */
0005 
0006 #include <linux/device.h>
0007 #include <linux/usb.h>
0008 #include <linux/gfp.h>
0009 #include <sound/rawmidi.h>
0010 #include <sound/core.h>
0011 #include <sound/pcm.h>
0012 
0013 #include "device.h"
0014 #include "midi.h"
0015 
0016 static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream)
0017 {
0018     return 0;
0019 }
0020 
0021 static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream)
0022 {
0023     return 0;
0024 }
0025 
0026 static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
0027 {
0028     struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
0029 
0030     if (!cdev)
0031         return;
0032 
0033     cdev->midi_receive_substream = up ? substream : NULL;
0034 }
0035 
0036 
0037 static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream)
0038 {
0039     return 0;
0040 }
0041 
0042 static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)
0043 {
0044     struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
0045     if (cdev->midi_out_active) {
0046         usb_kill_urb(&cdev->midi_out_urb);
0047         cdev->midi_out_active = 0;
0048     }
0049     return 0;
0050 }
0051 
0052 static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,
0053                     struct snd_rawmidi_substream *substream)
0054 {
0055     int len, ret;
0056     struct device *dev = caiaqdev_to_dev(cdev);
0057 
0058     cdev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
0059     cdev->midi_out_buf[1] = 0; /* port */
0060     len = snd_rawmidi_transmit(substream, cdev->midi_out_buf + 3,
0061                    EP1_BUFSIZE - 3);
0062 
0063     if (len <= 0)
0064         return;
0065 
0066     cdev->midi_out_buf[2] = len;
0067     cdev->midi_out_urb.transfer_buffer_length = len+3;
0068 
0069     ret = usb_submit_urb(&cdev->midi_out_urb, GFP_ATOMIC);
0070     if (ret < 0)
0071         dev_err(dev,
0072             "snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
0073             "ret=%d, len=%d\n", substream, ret, len);
0074     else
0075         cdev->midi_out_active = 1;
0076 }
0077 
0078 static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
0079 {
0080     struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
0081 
0082     if (up) {
0083         cdev->midi_out_substream = substream;
0084         if (!cdev->midi_out_active)
0085             snd_usb_caiaq_midi_send(cdev, substream);
0086     } else {
0087         cdev->midi_out_substream = NULL;
0088     }
0089 }
0090 
0091 
0092 static const struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
0093 {
0094     .open =     snd_usb_caiaq_midi_output_open,
0095     .close =    snd_usb_caiaq_midi_output_close,
0096     .trigger =      snd_usb_caiaq_midi_output_trigger,
0097 };
0098 
0099 static const struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
0100 {
0101     .open =     snd_usb_caiaq_midi_input_open,
0102     .close =    snd_usb_caiaq_midi_input_close,
0103     .trigger =      snd_usb_caiaq_midi_input_trigger,
0104 };
0105 
0106 void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,
0107                      int port, const char *buf, int len)
0108 {
0109     if (!cdev->midi_receive_substream)
0110         return;
0111 
0112     snd_rawmidi_receive(cdev->midi_receive_substream, buf, len);
0113 }
0114 
0115 int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
0116 {
0117     int ret;
0118     struct snd_rawmidi *rmidi;
0119 
0120     ret = snd_rawmidi_new(device->chip.card, device->product_name, 0,
0121                     device->spec.num_midi_out,
0122                     device->spec.num_midi_in,
0123                     &rmidi);
0124 
0125     if (ret < 0)
0126         return ret;
0127 
0128     strscpy(rmidi->name, device->product_name, sizeof(rmidi->name));
0129 
0130     rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
0131     rmidi->private_data = device;
0132 
0133     if (device->spec.num_midi_out > 0) {
0134         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
0135         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
0136                     &snd_usb_caiaq_midi_output);
0137     }
0138 
0139     if (device->spec.num_midi_in > 0) {
0140         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
0141         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
0142                     &snd_usb_caiaq_midi_input);
0143     }
0144 
0145     device->rmidi = rmidi;
0146 
0147     return 0;
0148 }
0149 
0150 void snd_usb_caiaq_midi_output_done(struct urb* urb)
0151 {
0152     struct snd_usb_caiaqdev *cdev = urb->context;
0153 
0154     cdev->midi_out_active = 0;
0155     if (urb->status != 0)
0156         return;
0157 
0158     if (!cdev->midi_out_substream)
0159         return;
0160 
0161     snd_usb_caiaq_midi_send(cdev, cdev->midi_out_substream);
0162 }