aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/amdtp.c
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-04-25 09:44:47 -0400
committerTakashi Iwai <tiwai@suse.de>2014-05-26 08:12:44 -0400
commit83d8d72dffa87a6dcecce229617273be62ec5bc0 (patch)
tree3eb795a28972593f9da2d4f81c05e538553551cb /sound/firewire/amdtp.c
parent2b3fc456febf540cd9bbf4c8cb4fba0dd0648df3 (diff)
ALSA: firewire-lib: Add support for MIDI capture/playback
For capturing/playbacking MIDI messages, this commit adds one MIDI conformant data channel. This data channel has multiplexed 8 MIDI data streams. So this data channel can transfer messages from/to 8 MIDI ports. And this commit allows to set PCM format even if AMDTP streams already start. I suppose the case that PCM substreams are going to be joined into AMDTP streams when AMDTP streams are already started for MIDI substreams. Each driver must count how many PCM/MIDI substreams use AMDTP streams to stop AMDTP streams. There are differences between specifications about MIDI conformant data. About the multiplexing, IEC 61883-6:2002, itself, has no information. It describes labels and bytes for MIDI messages and refers to MMA/AMEI RP-027 for 'successfull implementation'. MMA/AMEI RP-027 describes 8 MPX-MIDI data streams for one MIDI conformant data channel. IEC 61883-6:2005 adds 'sequence multiplexing' and apply this way and describe incompatibility between 2002 and 2005. So this commit applies IEC 61883-6:2005. When we find some devices compliant to IEC 61883-6:2002, then this difference should be handles as device quirk in additional work. About the number of bytes in an MIDI conformant data, IEC 61883-6:2002 describe 0,1,2,3 bytes. MMA/AMEI RP-027 describes 'MIDI1.0-1x-SPEED', 'MIDI1.0-2x-SPEED', 'MIDI1.0-3x-SPEED' modes and the maximum bytes for each mode corresponds to 1, 2, 3 bytes. The 'MIDI1.0-2x/3x-SPEED' modes are accompanied with 'negotiation procedure' and 'encapsulation details' but there is no specifications for them. So this commit implements 'MIDI1.0-1x-SPEED' mode for playback, but allows to pick up 1-3 bytes for capturing. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/amdtp.c')
-rw-r--r--sound/firewire/amdtp.c53
1 files changed, 45 insertions, 8 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index be1aabcda0d2..a4553ec1b63e 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -12,6 +12,7 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <sound/pcm.h> 14#include <sound/pcm.h>
15#include <sound/rawmidi.h>
15#include "amdtp.h" 16#include "amdtp.h"
16 17
17#define TICKS_PER_CYCLE 3072 18#define TICKS_PER_CYCLE 3072
@@ -123,9 +124,12 @@ void amdtp_stream_set_parameters(struct amdtp_stream *s,
123 [CIP_SFC_176400] = 176400, 124 [CIP_SFC_176400] = 176400,
124 [CIP_SFC_192000] = 192000, 125 [CIP_SFC_192000] = 192000,
125 }; 126 };
126 unsigned int sfc; 127 unsigned int sfc, midi_channels;
127 128
128 if (WARN_ON(amdtp_stream_running(s))) 129 midi_channels = DIV_ROUND_UP(midi_ports, 8);
130
131 if (WARN_ON(amdtp_stream_running(s)) ||
132 WARN_ON(midi_channels > AMDTP_MAX_CHANNELS_FOR_MIDI))
129 return; 133 return;
130 134
131 for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc) 135 for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc)
@@ -142,7 +146,7 @@ sfc_found:
142 pcm_channels *= 2; 146 pcm_channels *= 2;
143 } 147 }
144 s->sfc = sfc; 148 s->sfc = sfc;
145 s->data_block_quadlets = pcm_channels + DIV_ROUND_UP(midi_ports, 8); 149 s->data_block_quadlets = pcm_channels + midi_channels;
146 s->pcm_channels = pcm_channels; 150 s->pcm_channels = pcm_channels;
147 s->midi_ports = midi_ports; 151 s->midi_ports = midi_ports;
148 152
@@ -200,7 +204,7 @@ static void amdtp_read_s32_dualwire(struct amdtp_stream *s,
200void amdtp_stream_set_pcm_format(struct amdtp_stream *s, 204void amdtp_stream_set_pcm_format(struct amdtp_stream *s,
201 snd_pcm_format_t format) 205 snd_pcm_format_t format)
202{ 206{
203 if (WARN_ON(amdtp_stream_running(s))) 207 if (WARN_ON(amdtp_stream_pcm_running(s)))
204 return; 208 return;
205 209
206 switch (format) { 210 switch (format) {
@@ -507,11 +511,41 @@ static void amdtp_fill_pcm_silence(struct amdtp_stream *s,
507static void amdtp_fill_midi(struct amdtp_stream *s, 511static void amdtp_fill_midi(struct amdtp_stream *s,
508 __be32 *buffer, unsigned int frames) 512 __be32 *buffer, unsigned int frames)
509{ 513{
510 unsigned int i; 514 unsigned int f, port;
515 u8 *b;
516
517 for (f = 0; f < frames; f++) {
518 buffer[s->pcm_channels + 1] = 0;
519 b = (u8 *)&buffer[s->pcm_channels + 1];
520
521 port = (s->data_block_counter + f) % 8;
522 if ((s->midi[port] == NULL) ||
523 (snd_rawmidi_transmit(s->midi[port], b + 1, 1) <= 0))
524 b[0] = 0x80;
525 else
526 b[0] = 0x81;
527
528 buffer += s->data_block_quadlets;
529 }
530}
531
532static void amdtp_pull_midi(struct amdtp_stream *s,
533 __be32 *buffer, unsigned int frames)
534{
535 unsigned int f, port;
536 int len;
537 u8 *b;
538
539 for (f = 0; f < frames; f++) {
540 port = (s->data_block_counter + f) % 8;
541 b = (u8 *)&buffer[s->pcm_channels + 1];
511 542
512 for (i = 0; i < frames; ++i) 543 len = b[0] - 0x80;
513 buffer[s->pcm_channels + i * s->data_block_quadlets] = 544 if ((1 <= len) && (len <= 3) && (s->midi[port]))
514 cpu_to_be32(0x80000000); 545 snd_rawmidi_receive(s->midi[port], b + 1, len);
546
547 buffer += s->data_block_quadlets;
548 }
515} 549}
516 550
517static void update_pcm_pointers(struct amdtp_stream *s, 551static void update_pcm_pointers(struct amdtp_stream *s,
@@ -688,6 +722,9 @@ static void handle_in_packet(struct amdtp_stream *s,
688 pcm = ACCESS_ONCE(s->pcm); 722 pcm = ACCESS_ONCE(s->pcm);
689 if (pcm) 723 if (pcm)
690 s->transfer_samples(s, pcm, buffer, data_blocks); 724 s->transfer_samples(s, pcm, buffer, data_blocks);
725
726 if (s->midi_ports)
727 amdtp_pull_midi(s, buffer, data_blocks);
691 } 728 }
692 729
693 s->data_block_counter = (data_block_counter + data_blocks) & 0xff; 730 s->data_block_counter = (data_block_counter + data_blocks) & 0xff;