xref: /kernel/linux/linux-6.6/sound/usb/caiaq/midi.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Copyright (c) 2006,2007 Daniel Mack
462306a36Sopenharmony_ci*/
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/device.h>
762306a36Sopenharmony_ci#include <linux/usb.h>
862306a36Sopenharmony_ci#include <linux/gfp.h>
962306a36Sopenharmony_ci#include <sound/rawmidi.h>
1062306a36Sopenharmony_ci#include <sound/core.h>
1162306a36Sopenharmony_ci#include <sound/pcm.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "device.h"
1462306a36Sopenharmony_ci#include "midi.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	return 0;
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	return 0;
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (!cdev)
3162306a36Sopenharmony_ci		return;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	cdev->midi_receive_substream = up ? substream : NULL;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	return 0;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
4562306a36Sopenharmony_ci	if (cdev->midi_out_active) {
4662306a36Sopenharmony_ci		usb_kill_urb(&cdev->midi_out_urb);
4762306a36Sopenharmony_ci		cdev->midi_out_active = 0;
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci	return 0;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,
5362306a36Sopenharmony_ci				    struct snd_rawmidi_substream *substream)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	int len, ret;
5662306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	cdev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
5962306a36Sopenharmony_ci	cdev->midi_out_buf[1] = 0; /* port */
6062306a36Sopenharmony_ci	len = snd_rawmidi_transmit(substream, cdev->midi_out_buf + 3,
6162306a36Sopenharmony_ci				   EP1_BUFSIZE - 3);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (len <= 0)
6462306a36Sopenharmony_ci		return;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	cdev->midi_out_buf[2] = len;
6762306a36Sopenharmony_ci	cdev->midi_out_urb.transfer_buffer_length = len+3;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	ret = usb_submit_urb(&cdev->midi_out_urb, GFP_ATOMIC);
7062306a36Sopenharmony_ci	if (ret < 0)
7162306a36Sopenharmony_ci		dev_err(dev,
7262306a36Sopenharmony_ci			"snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
7362306a36Sopenharmony_ci			"ret=%d, len=%d\n", substream, ret, len);
7462306a36Sopenharmony_ci	else
7562306a36Sopenharmony_ci		cdev->midi_out_active = 1;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (up) {
8362306a36Sopenharmony_ci		cdev->midi_out_substream = substream;
8462306a36Sopenharmony_ci		if (!cdev->midi_out_active)
8562306a36Sopenharmony_ci			snd_usb_caiaq_midi_send(cdev, substream);
8662306a36Sopenharmony_ci	} else {
8762306a36Sopenharmony_ci		cdev->midi_out_substream = NULL;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	.open =		snd_usb_caiaq_midi_output_open,
9562306a36Sopenharmony_ci	.close =	snd_usb_caiaq_midi_output_close,
9662306a36Sopenharmony_ci	.trigger =      snd_usb_caiaq_midi_output_trigger,
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	.open =		snd_usb_caiaq_midi_input_open,
10262306a36Sopenharmony_ci	.close =	snd_usb_caiaq_midi_input_close,
10362306a36Sopenharmony_ci	.trigger =      snd_usb_caiaq_midi_input_trigger,
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_civoid snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,
10762306a36Sopenharmony_ci				     int port, const char *buf, int len)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	if (!cdev->midi_receive_substream)
11062306a36Sopenharmony_ci		return;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	snd_rawmidi_receive(cdev->midi_receive_substream, buf, len);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciint snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	int ret;
11862306a36Sopenharmony_ci	struct snd_rawmidi *rmidi;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	ret = snd_rawmidi_new(device->chip.card, device->product_name, 0,
12162306a36Sopenharmony_ci					device->spec.num_midi_out,
12262306a36Sopenharmony_ci					device->spec.num_midi_in,
12362306a36Sopenharmony_ci					&rmidi);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (ret < 0)
12662306a36Sopenharmony_ci		return ret;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	strscpy(rmidi->name, device->product_name, sizeof(rmidi->name));
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
13162306a36Sopenharmony_ci	rmidi->private_data = device;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (device->spec.num_midi_out > 0) {
13462306a36Sopenharmony_ci		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
13562306a36Sopenharmony_ci		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
13662306a36Sopenharmony_ci				    &snd_usb_caiaq_midi_output);
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (device->spec.num_midi_in > 0) {
14062306a36Sopenharmony_ci		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
14162306a36Sopenharmony_ci		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
14262306a36Sopenharmony_ci				    &snd_usb_caiaq_midi_input);
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	device->rmidi = rmidi;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_civoid snd_usb_caiaq_midi_output_done(struct urb* urb)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = urb->context;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	cdev->midi_out_active = 0;
15562306a36Sopenharmony_ci	if (urb->status != 0)
15662306a36Sopenharmony_ci		return;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (!cdev->midi_out_substream)
15962306a36Sopenharmony_ci		return;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	snd_usb_caiaq_midi_send(cdev, cdev->midi_out_substream);
16262306a36Sopenharmony_ci}
163