2019-05-30 02:57:59 +03:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2017-03-31 16:06:04 +03:00
|
|
|
/*
|
|
|
|
* ff-midi.c - a part of driver for RME Fireface series
|
|
|
|
*
|
|
|
|
* Copyright (c) 2015-2017 Takashi Sakamoto
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ff.h"
|
|
|
|
|
|
|
|
static int midi_capture_open(struct snd_rawmidi_substream *substream)
|
|
|
|
{
|
|
|
|
/* Do nothing. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int midi_playback_open(struct snd_rawmidi_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_ff *ff = substream->rmidi->private_data;
|
|
|
|
|
|
|
|
/* Initialize internal status. */
|
ALSA: fireface: support rx MIDI functionality for Fireface UCX
In latter model of Fireface series, asynchronous transaction includes
a prefix byte to indicate the way to decode included MIDI bytes.
Upper 4 bits of the prefix byte indicates port number, and the rest 4
bits indicate the way to decode rest of bytes for MIDI messages.
Basically the rest bits indicates the number of bytes for MIDI message.
However, if the last byte of each MIDi message is included, the rest
bits are 0xf. For example:
message: f0 00 00 66 14 20 00 00 f7
offset: content (big endian, port 0)
'0030: 0x02f00000
'0030: 0x03006614
'0030: 0x03200000
'0030: 0x0ff70000
This commit supports encoding scheme for the above and allows
applications to transfer MIDI messages via ALSA rawmidi interface.
An unused member (running_status) is reused to keep state of
transmission of system exclusive messages.
For your information, this is a dump of config rom.
$ sudo ./hinawa-config-rom-printer /dev/fw1
{ 'bus-info': { 'bmc': False,
'chip_ID': 13225063715,
'cmc': False,
'cyc_clk_acc': 0,
'imc': False,
'isc': True,
'max_rec': 512,
'name': '1394',
'node_vendor_ID': 2613},
'root-directory': [ [ 'NODE_CAPABILITIES',
{ 'addressing': {'64': True, 'fix': True, 'prv': False},
'misc': {'int': False, 'ms': False, 'spt': True},
'state': { 'atn': False,
'ded': False,
'drq': True,
'elo': False,
'init': False,
'lst': True,
'off': False},
'testing': {'bas': False, 'ext': False}}],
['VENDOR', 2613],
['DESCRIPTOR', 'RME!'],
['EUI_64', 2873037108442403],
[ 'UNIT',
[ ['SPECIFIER_ID', 2613],
['VERSION', 4],
['MODEL', 1054720],
['DESCRIPTOR', 'Fireface UCX']]]]}
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2019-01-22 16:17:05 +03:00
|
|
|
ff->on_sysex[substream->number] = 0;
|
2017-03-31 16:06:04 +03:00
|
|
|
ff->rx_midi_error[substream->number] = false;
|
|
|
|
|
locking/atomics: COCCINELLE/treewide: Convert trivial ACCESS_ONCE() patterns to READ_ONCE()/WRITE_ONCE()
Please do not apply this to mainline directly, instead please re-run the
coccinelle script shown below and apply its output.
For several reasons, it is desirable to use {READ,WRITE}_ONCE() in
preference to ACCESS_ONCE(), and new code is expected to use one of the
former. So far, there's been no reason to change most existing uses of
ACCESS_ONCE(), as these aren't harmful, and changing them results in
churn.
However, for some features, the read/write distinction is critical to
correct operation. To distinguish these cases, separate read/write
accessors must be used. This patch migrates (most) remaining
ACCESS_ONCE() instances to {READ,WRITE}_ONCE(), using the following
coccinelle script:
----
// Convert trivial ACCESS_ONCE() uses to equivalent READ_ONCE() and
// WRITE_ONCE()
// $ make coccicheck COCCI=/home/mark/once.cocci SPFLAGS="--include-headers" MODE=patch
virtual patch
@ depends on patch @
expression E1, E2;
@@
- ACCESS_ONCE(E1) = E2
+ WRITE_ONCE(E1, E2)
@ depends on patch @
expression E;
@@
- ACCESS_ONCE(E)
+ READ_ONCE(E)
----
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: davem@davemloft.net
Cc: linux-arch@vger.kernel.org
Cc: mpe@ellerman.id.au
Cc: shuah@kernel.org
Cc: snitzer@redhat.com
Cc: thor.thayer@linux.intel.com
Cc: tj@kernel.org
Cc: viro@zeniv.linux.org.uk
Cc: will.deacon@arm.com
Link: http://lkml.kernel.org/r/1508792849-3115-19-git-send-email-paulmck@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-10-24 00:07:29 +03:00
|
|
|
WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream);
|
2017-03-31 16:06:04 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int midi_capture_close(struct snd_rawmidi_substream *substream)
|
|
|
|
{
|
|
|
|
/* Do nothing. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int midi_playback_close(struct snd_rawmidi_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_ff *ff = substream->rmidi->private_data;
|
|
|
|
|
|
|
|
cancel_work_sync(&ff->rx_midi_work[substream->number]);
|
locking/atomics: COCCINELLE/treewide: Convert trivial ACCESS_ONCE() patterns to READ_ONCE()/WRITE_ONCE()
Please do not apply this to mainline directly, instead please re-run the
coccinelle script shown below and apply its output.
For several reasons, it is desirable to use {READ,WRITE}_ONCE() in
preference to ACCESS_ONCE(), and new code is expected to use one of the
former. So far, there's been no reason to change most existing uses of
ACCESS_ONCE(), as these aren't harmful, and changing them results in
churn.
However, for some features, the read/write distinction is critical to
correct operation. To distinguish these cases, separate read/write
accessors must be used. This patch migrates (most) remaining
ACCESS_ONCE() instances to {READ,WRITE}_ONCE(), using the following
coccinelle script:
----
// Convert trivial ACCESS_ONCE() uses to equivalent READ_ONCE() and
// WRITE_ONCE()
// $ make coccicheck COCCI=/home/mark/once.cocci SPFLAGS="--include-headers" MODE=patch
virtual patch
@ depends on patch @
expression E1, E2;
@@
- ACCESS_ONCE(E1) = E2
+ WRITE_ONCE(E1, E2)
@ depends on patch @
expression E;
@@
- ACCESS_ONCE(E)
+ READ_ONCE(E)
----
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: davem@davemloft.net
Cc: linux-arch@vger.kernel.org
Cc: mpe@ellerman.id.au
Cc: shuah@kernel.org
Cc: snitzer@redhat.com
Cc: thor.thayer@linux.intel.com
Cc: tj@kernel.org
Cc: viro@zeniv.linux.org.uk
Cc: will.deacon@arm.com
Link: http://lkml.kernel.org/r/1508792849-3115-19-git-send-email-paulmck@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-10-24 00:07:29 +03:00
|
|
|
WRITE_ONCE(ff->rx_midi_substreams[substream->number], NULL);
|
2017-03-31 16:06:04 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
|
|
|
|
int up)
|
|
|
|
{
|
|
|
|
struct snd_ff *ff = substream->rmidi->private_data;
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ff->lock, flags);
|
|
|
|
|
|
|
|
if (up)
|
locking/atomics: COCCINELLE/treewide: Convert trivial ACCESS_ONCE() patterns to READ_ONCE()/WRITE_ONCE()
Please do not apply this to mainline directly, instead please re-run the
coccinelle script shown below and apply its output.
For several reasons, it is desirable to use {READ,WRITE}_ONCE() in
preference to ACCESS_ONCE(), and new code is expected to use one of the
former. So far, there's been no reason to change most existing uses of
ACCESS_ONCE(), as these aren't harmful, and changing them results in
churn.
However, for some features, the read/write distinction is critical to
correct operation. To distinguish these cases, separate read/write
accessors must be used. This patch migrates (most) remaining
ACCESS_ONCE() instances to {READ,WRITE}_ONCE(), using the following
coccinelle script:
----
// Convert trivial ACCESS_ONCE() uses to equivalent READ_ONCE() and
// WRITE_ONCE()
// $ make coccicheck COCCI=/home/mark/once.cocci SPFLAGS="--include-headers" MODE=patch
virtual patch
@ depends on patch @
expression E1, E2;
@@
- ACCESS_ONCE(E1) = E2
+ WRITE_ONCE(E1, E2)
@ depends on patch @
expression E;
@@
- ACCESS_ONCE(E)
+ READ_ONCE(E)
----
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: davem@davemloft.net
Cc: linux-arch@vger.kernel.org
Cc: mpe@ellerman.id.au
Cc: shuah@kernel.org
Cc: snitzer@redhat.com
Cc: thor.thayer@linux.intel.com
Cc: tj@kernel.org
Cc: viro@zeniv.linux.org.uk
Cc: will.deacon@arm.com
Link: http://lkml.kernel.org/r/1508792849-3115-19-git-send-email-paulmck@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-10-24 00:07:29 +03:00
|
|
|
WRITE_ONCE(ff->tx_midi_substreams[substream->number],
|
|
|
|
substream);
|
2017-03-31 16:06:04 +03:00
|
|
|
else
|
locking/atomics: COCCINELLE/treewide: Convert trivial ACCESS_ONCE() patterns to READ_ONCE()/WRITE_ONCE()
Please do not apply this to mainline directly, instead please re-run the
coccinelle script shown below and apply its output.
For several reasons, it is desirable to use {READ,WRITE}_ONCE() in
preference to ACCESS_ONCE(), and new code is expected to use one of the
former. So far, there's been no reason to change most existing uses of
ACCESS_ONCE(), as these aren't harmful, and changing them results in
churn.
However, for some features, the read/write distinction is critical to
correct operation. To distinguish these cases, separate read/write
accessors must be used. This patch migrates (most) remaining
ACCESS_ONCE() instances to {READ,WRITE}_ONCE(), using the following
coccinelle script:
----
// Convert trivial ACCESS_ONCE() uses to equivalent READ_ONCE() and
// WRITE_ONCE()
// $ make coccicheck COCCI=/home/mark/once.cocci SPFLAGS="--include-headers" MODE=patch
virtual patch
@ depends on patch @
expression E1, E2;
@@
- ACCESS_ONCE(E1) = E2
+ WRITE_ONCE(E1, E2)
@ depends on patch @
expression E;
@@
- ACCESS_ONCE(E)
+ READ_ONCE(E)
----
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: davem@davemloft.net
Cc: linux-arch@vger.kernel.org
Cc: mpe@ellerman.id.au
Cc: shuah@kernel.org
Cc: snitzer@redhat.com
Cc: thor.thayer@linux.intel.com
Cc: tj@kernel.org
Cc: viro@zeniv.linux.org.uk
Cc: will.deacon@arm.com
Link: http://lkml.kernel.org/r/1508792849-3115-19-git-send-email-paulmck@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-10-24 00:07:29 +03:00
|
|
|
WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL);
|
2017-03-31 16:06:04 +03:00
|
|
|
|
|
|
|
spin_unlock_irqrestore(&ff->lock, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
|
|
|
|
int up)
|
|
|
|
{
|
|
|
|
struct snd_ff *ff = substream->rmidi->private_data;
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ff->lock, flags);
|
|
|
|
|
|
|
|
if (up || !ff->rx_midi_error[substream->number])
|
|
|
|
schedule_work(&ff->rx_midi_work[substream->number]);
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&ff->lock, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_midi_substream_names(struct snd_rawmidi_str *stream,
|
|
|
|
const char *const name)
|
|
|
|
{
|
|
|
|
struct snd_rawmidi_substream *substream;
|
|
|
|
|
|
|
|
list_for_each_entry(substream, &stream->substreams, list) {
|
|
|
|
snprintf(substream->name, sizeof(substream->name),
|
|
|
|
"%s MIDI %d", name, substream->number + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int snd_ff_create_midi_devices(struct snd_ff *ff)
|
|
|
|
{
|
2017-06-07 03:38:06 +03:00
|
|
|
static const struct snd_rawmidi_ops midi_capture_ops = {
|
|
|
|
.open = midi_capture_open,
|
|
|
|
.close = midi_capture_close,
|
|
|
|
.trigger = midi_capture_trigger,
|
|
|
|
};
|
|
|
|
static const struct snd_rawmidi_ops midi_playback_ops = {
|
|
|
|
.open = midi_playback_open,
|
|
|
|
.close = midi_playback_close,
|
|
|
|
.trigger = midi_playback_trigger,
|
|
|
|
};
|
2017-03-31 16:06:04 +03:00
|
|
|
struct snd_rawmidi *rmidi;
|
|
|
|
struct snd_rawmidi_str *stream;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = snd_rawmidi_new(ff->card, ff->card->driver, 0,
|
|
|
|
ff->spec->midi_out_ports, ff->spec->midi_in_ports,
|
|
|
|
&rmidi);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
snprintf(rmidi->name, sizeof(rmidi->name),
|
|
|
|
"%s MIDI", ff->card->shortname);
|
|
|
|
rmidi->private_data = ff;
|
|
|
|
|
|
|
|
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
|
|
|
|
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
|
|
|
|
&midi_capture_ops);
|
|
|
|
stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
|
|
|
|
set_midi_substream_names(stream, ff->card->shortname);
|
|
|
|
|
|
|
|
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
|
|
|
|
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
|
|
|
|
&midi_playback_ops);
|
|
|
|
stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
|
|
|
|
set_midi_substream_names(stream, ff->card->shortname);
|
|
|
|
|
|
|
|
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|