1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25955815eSTakashi Sakamoto /* 35955815eSTakashi Sakamoto * AM824 format in Audio and Music Data Transmission Protocol (IEC 61883-6) 45955815eSTakashi Sakamoto * 5df075feeSTakashi Sakamoto * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 65955815eSTakashi Sakamoto * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp> 75955815eSTakashi Sakamoto */ 85955815eSTakashi Sakamoto 9df075feeSTakashi Sakamoto #include <linux/slab.h> 10df075feeSTakashi Sakamoto 115955815eSTakashi Sakamoto #include "amdtp-am824.h" 125955815eSTakashi Sakamoto 135955815eSTakashi Sakamoto #define CIP_FMT_AM 0x10 145955815eSTakashi Sakamoto 1551c29fd2STakashi Sakamoto /* "Clock-based rate control mode" is just supported. */ 1651c29fd2STakashi Sakamoto #define AMDTP_FDF_AM824 0x00 1751c29fd2STakashi Sakamoto 18df075feeSTakashi Sakamoto /* 19df075feeSTakashi Sakamoto * Nominally 3125 bytes/second, but the MIDI port's clock might be 20df075feeSTakashi Sakamoto * 1% too slow, and the bus clock 100 ppm too fast. 21df075feeSTakashi Sakamoto */ 22df075feeSTakashi Sakamoto #define MIDI_BYTES_PER_SECOND 3093 23df075feeSTakashi Sakamoto 24df075feeSTakashi Sakamoto /* 25df075feeSTakashi Sakamoto * Several devices look only at the first eight data blocks. 26df075feeSTakashi Sakamoto * In any case, this is more than enough for the MIDI data rate. 27df075feeSTakashi Sakamoto */ 28df075feeSTakashi Sakamoto #define MAX_MIDI_RX_BLOCKS 8 29df075feeSTakashi Sakamoto 30df075feeSTakashi Sakamoto struct amdtp_am824 { 31df075feeSTakashi Sakamoto struct snd_rawmidi_substream *midi[AM824_MAX_CHANNELS_FOR_MIDI * 8]; 32df075feeSTakashi Sakamoto int midi_fifo_limit; 33df075feeSTakashi Sakamoto int midi_fifo_used[AM824_MAX_CHANNELS_FOR_MIDI * 8]; 34df075feeSTakashi Sakamoto unsigned int pcm_channels; 35df075feeSTakashi Sakamoto unsigned int midi_ports; 36df075feeSTakashi Sakamoto 37df075feeSTakashi Sakamoto u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM]; 38df075feeSTakashi Sakamoto u8 midi_position; 39df075feeSTakashi Sakamoto 40df075feeSTakashi Sakamoto unsigned int frame_multiplier; 41df075feeSTakashi Sakamoto }; 42df075feeSTakashi Sakamoto 4351c29fd2STakashi Sakamoto /** 4451c29fd2STakashi Sakamoto * amdtp_am824_set_parameters - set stream parameters 4551c29fd2STakashi Sakamoto * @s: the AMDTP stream to configure 4651c29fd2STakashi Sakamoto * @rate: the sample rate 4751c29fd2STakashi Sakamoto * @pcm_channels: the number of PCM samples in each data block, to be encoded 4851c29fd2STakashi Sakamoto * as AM824 multi-bit linear audio 4951c29fd2STakashi Sakamoto * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels) 5051c29fd2STakashi Sakamoto * @double_pcm_frames: one data block transfers two PCM frames 5151c29fd2STakashi Sakamoto * 5251c29fd2STakashi Sakamoto * The parameters must be set before the stream is started, and must not be 5351c29fd2STakashi Sakamoto * changed while the stream is running. 5451c29fd2STakashi Sakamoto */ 5551c29fd2STakashi Sakamoto int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate, 5651c29fd2STakashi Sakamoto unsigned int pcm_channels, 5751c29fd2STakashi Sakamoto unsigned int midi_ports, 5851c29fd2STakashi Sakamoto bool double_pcm_frames) 5951c29fd2STakashi Sakamoto { 60df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 61df075feeSTakashi Sakamoto unsigned int midi_channels; 62df075feeSTakashi Sakamoto unsigned int i; 6351c29fd2STakashi Sakamoto int err; 6451c29fd2STakashi Sakamoto 65df075feeSTakashi Sakamoto if (amdtp_stream_running(s)) 66df075feeSTakashi Sakamoto return -EINVAL; 67df075feeSTakashi Sakamoto 68df075feeSTakashi Sakamoto if (pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) 69df075feeSTakashi Sakamoto return -EINVAL; 70df075feeSTakashi Sakamoto 71df075feeSTakashi Sakamoto midi_channels = DIV_ROUND_UP(midi_ports, 8); 72df075feeSTakashi Sakamoto if (midi_channels > AM824_MAX_CHANNELS_FOR_MIDI) 73df075feeSTakashi Sakamoto return -EINVAL; 74df075feeSTakashi Sakamoto 75df075feeSTakashi Sakamoto if (WARN_ON(amdtp_stream_running(s)) || 76df075feeSTakashi Sakamoto WARN_ON(pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) || 77df075feeSTakashi Sakamoto WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)) 78df075feeSTakashi Sakamoto return -EINVAL; 79df075feeSTakashi Sakamoto 80df075feeSTakashi Sakamoto err = amdtp_stream_set_parameters(s, rate, 81df075feeSTakashi Sakamoto pcm_channels + midi_channels); 8251c29fd2STakashi Sakamoto if (err < 0) 8351c29fd2STakashi Sakamoto return err; 8451c29fd2STakashi Sakamoto 85d3d10a4aSTakashi Sakamoto s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc; 8651c29fd2STakashi Sakamoto 87df075feeSTakashi Sakamoto p->pcm_channels = pcm_channels; 88df075feeSTakashi Sakamoto p->midi_ports = midi_ports; 89df075feeSTakashi Sakamoto 9051c29fd2STakashi Sakamoto /* 9151c29fd2STakashi Sakamoto * In IEC 61883-6, one data block represents one event. In ALSA, one 9251c29fd2STakashi Sakamoto * event equals to one PCM frame. But Dice has a quirk at higher 9351c29fd2STakashi Sakamoto * sampling rate to transfer two PCM frames in one data block. 9451c29fd2STakashi Sakamoto */ 9551c29fd2STakashi Sakamoto if (double_pcm_frames) 96df075feeSTakashi Sakamoto p->frame_multiplier = 2; 9751c29fd2STakashi Sakamoto else 98df075feeSTakashi Sakamoto p->frame_multiplier = 1; 99df075feeSTakashi Sakamoto 100df075feeSTakashi Sakamoto /* init the position map for PCM and MIDI channels */ 101df075feeSTakashi Sakamoto for (i = 0; i < pcm_channels; i++) 102df075feeSTakashi Sakamoto p->pcm_positions[i] = i; 103df075feeSTakashi Sakamoto p->midi_position = p->pcm_channels; 104df075feeSTakashi Sakamoto 105df075feeSTakashi Sakamoto /* 106df075feeSTakashi Sakamoto * We do not know the actual MIDI FIFO size of most devices. Just 107df075feeSTakashi Sakamoto * assume two bytes, i.e., one byte can be received over the bus while 108df075feeSTakashi Sakamoto * the previous one is transmitted over MIDI. 109df075feeSTakashi Sakamoto * (The value here is adjusted for midi_ratelimit_per_packet().) 110df075feeSTakashi Sakamoto */ 111df075feeSTakashi Sakamoto p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1; 11251c29fd2STakashi Sakamoto 11351c29fd2STakashi Sakamoto return 0; 11451c29fd2STakashi Sakamoto } 11551c29fd2STakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters); 11651c29fd2STakashi Sakamoto 1175955815eSTakashi Sakamoto /** 118f65be911STakashi Sakamoto * amdtp_am824_set_pcm_position - set an index of data channel for a channel 119f65be911STakashi Sakamoto * of PCM frame 120f65be911STakashi Sakamoto * @s: the AMDTP stream 121f65be911STakashi Sakamoto * @index: the index of data channel in an data block 122f65be911STakashi Sakamoto * @position: the channel of PCM frame 123f65be911STakashi Sakamoto */ 124f65be911STakashi Sakamoto void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index, 125f65be911STakashi Sakamoto unsigned int position) 126f65be911STakashi Sakamoto { 127df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 128df075feeSTakashi Sakamoto 129df075feeSTakashi Sakamoto if (index < p->pcm_channels) 130df075feeSTakashi Sakamoto p->pcm_positions[index] = position; 131f65be911STakashi Sakamoto } 132f65be911STakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_position); 133f65be911STakashi Sakamoto 134f65be911STakashi Sakamoto /** 135f65be911STakashi Sakamoto * amdtp_am824_set_midi_position - set a index of data channel for MIDI 136f65be911STakashi Sakamoto * conformant data channel 137f65be911STakashi Sakamoto * @s: the AMDTP stream 138f65be911STakashi Sakamoto * @position: the index of data channel in an data block 139f65be911STakashi Sakamoto */ 140f65be911STakashi Sakamoto void amdtp_am824_set_midi_position(struct amdtp_stream *s, 141f65be911STakashi Sakamoto unsigned int position) 142f65be911STakashi Sakamoto { 143df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 144df075feeSTakashi Sakamoto 145df075feeSTakashi Sakamoto p->midi_position = position; 146f65be911STakashi Sakamoto } 147f65be911STakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position); 148f65be911STakashi Sakamoto 1499fc90644STakashi Sakamoto static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 1509fc90644STakashi Sakamoto __be32 *buffer, unsigned int frames, 1519fc90644STakashi Sakamoto unsigned int pcm_frames) 152df075feeSTakashi Sakamoto { 153df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 1549fc90644STakashi Sakamoto unsigned int channels = p->pcm_channels; 155df075feeSTakashi Sakamoto struct snd_pcm_runtime *runtime = pcm->runtime; 1569fc90644STakashi Sakamoto unsigned int pcm_buffer_pointer; 1579fc90644STakashi Sakamoto int remaining_frames; 158df075feeSTakashi Sakamoto const u32 *src; 1599fc90644STakashi Sakamoto int i, c; 160df075feeSTakashi Sakamoto 1619fc90644STakashi Sakamoto pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 1629fc90644STakashi Sakamoto pcm_buffer_pointer %= runtime->buffer_size; 1639fc90644STakashi Sakamoto 164df075feeSTakashi Sakamoto src = (void *)runtime->dma_area + 1659fc90644STakashi Sakamoto frames_to_bytes(runtime, pcm_buffer_pointer); 1669fc90644STakashi Sakamoto remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 167df075feeSTakashi Sakamoto 168df075feeSTakashi Sakamoto for (i = 0; i < frames; ++i) { 169df075feeSTakashi Sakamoto for (c = 0; c < channels; ++c) { 170df075feeSTakashi Sakamoto buffer[p->pcm_positions[c]] = 171df075feeSTakashi Sakamoto cpu_to_be32((*src >> 8) | 0x40000000); 172df075feeSTakashi Sakamoto src++; 173df075feeSTakashi Sakamoto } 174df075feeSTakashi Sakamoto buffer += s->data_block_quadlets; 175df075feeSTakashi Sakamoto if (--remaining_frames == 0) 176df075feeSTakashi Sakamoto src = (void *)runtime->dma_area; 177df075feeSTakashi Sakamoto } 178df075feeSTakashi Sakamoto } 179df075feeSTakashi Sakamoto 1809fc90644STakashi Sakamoto static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 1819fc90644STakashi Sakamoto __be32 *buffer, unsigned int frames, 1829fc90644STakashi Sakamoto unsigned int pcm_frames) 183df075feeSTakashi Sakamoto { 184df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 1859fc90644STakashi Sakamoto unsigned int channels = p->pcm_channels; 186df075feeSTakashi Sakamoto struct snd_pcm_runtime *runtime = pcm->runtime; 1879fc90644STakashi Sakamoto unsigned int pcm_buffer_pointer; 1889fc90644STakashi Sakamoto int remaining_frames; 189df075feeSTakashi Sakamoto u32 *dst; 1909fc90644STakashi Sakamoto int i, c; 191df075feeSTakashi Sakamoto 1929fc90644STakashi Sakamoto pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 1939fc90644STakashi Sakamoto pcm_buffer_pointer %= runtime->buffer_size; 1949fc90644STakashi Sakamoto 195df075feeSTakashi Sakamoto dst = (void *)runtime->dma_area + 1969fc90644STakashi Sakamoto frames_to_bytes(runtime, pcm_buffer_pointer); 1979fc90644STakashi Sakamoto remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 198df075feeSTakashi Sakamoto 199df075feeSTakashi Sakamoto for (i = 0; i < frames; ++i) { 200df075feeSTakashi Sakamoto for (c = 0; c < channels; ++c) { 201df075feeSTakashi Sakamoto *dst = be32_to_cpu(buffer[p->pcm_positions[c]]) << 8; 202df075feeSTakashi Sakamoto dst++; 203df075feeSTakashi Sakamoto } 204df075feeSTakashi Sakamoto buffer += s->data_block_quadlets; 205df075feeSTakashi Sakamoto if (--remaining_frames == 0) 206df075feeSTakashi Sakamoto dst = (void *)runtime->dma_area; 207df075feeSTakashi Sakamoto } 208df075feeSTakashi Sakamoto } 209df075feeSTakashi Sakamoto 210df075feeSTakashi Sakamoto static void write_pcm_silence(struct amdtp_stream *s, 211df075feeSTakashi Sakamoto __be32 *buffer, unsigned int frames) 212df075feeSTakashi Sakamoto { 213df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 214df075feeSTakashi Sakamoto unsigned int i, c, channels = p->pcm_channels; 215df075feeSTakashi Sakamoto 216df075feeSTakashi Sakamoto for (i = 0; i < frames; ++i) { 217df075feeSTakashi Sakamoto for (c = 0; c < channels; ++c) 218df075feeSTakashi Sakamoto buffer[p->pcm_positions[c]] = cpu_to_be32(0x40000000); 219df075feeSTakashi Sakamoto buffer += s->data_block_quadlets; 220df075feeSTakashi Sakamoto } 221df075feeSTakashi Sakamoto } 222df075feeSTakashi Sakamoto 223df075feeSTakashi Sakamoto /** 224bc8500daSTakashi Sakamoto * amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream 225bc8500daSTakashi Sakamoto * @s: the AMDTP stream for AM824 data block, must be initialized. 226bc8500daSTakashi Sakamoto * @runtime: the PCM substream runtime 227bc8500daSTakashi Sakamoto * 228bc8500daSTakashi Sakamoto */ 229bc8500daSTakashi Sakamoto int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s, 230bc8500daSTakashi Sakamoto struct snd_pcm_runtime *runtime) 231bc8500daSTakashi Sakamoto { 232bc8500daSTakashi Sakamoto int err; 233bc8500daSTakashi Sakamoto 234bc8500daSTakashi Sakamoto err = amdtp_stream_add_pcm_hw_constraints(s, runtime); 235bc8500daSTakashi Sakamoto if (err < 0) 236bc8500daSTakashi Sakamoto return err; 237bc8500daSTakashi Sakamoto 238bc8500daSTakashi Sakamoto /* AM824 in IEC 61883-6 can deliver 24bit data. */ 239bc8500daSTakashi Sakamoto return snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 240bc8500daSTakashi Sakamoto } 241bc8500daSTakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_add_pcm_hw_constraints); 242bc8500daSTakashi Sakamoto 243bc8500daSTakashi Sakamoto /** 24403e2a67eSTakashi Sakamoto * amdtp_am824_midi_trigger - start/stop playback/capture with a MIDI device 24503e2a67eSTakashi Sakamoto * @s: the AMDTP stream 24603e2a67eSTakashi Sakamoto * @port: index of MIDI port 24703e2a67eSTakashi Sakamoto * @midi: the MIDI device to be started, or %NULL to stop the current device 24803e2a67eSTakashi Sakamoto * 24903e2a67eSTakashi Sakamoto * Call this function on a running isochronous stream to enable the actual 25003e2a67eSTakashi Sakamoto * transmission of MIDI data. This function should be called from the MIDI 25103e2a67eSTakashi Sakamoto * device's .trigger callback. 25203e2a67eSTakashi Sakamoto */ 25303e2a67eSTakashi Sakamoto void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port, 25403e2a67eSTakashi Sakamoto struct snd_rawmidi_substream *midi) 25503e2a67eSTakashi Sakamoto { 256df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 257df075feeSTakashi Sakamoto 258df075feeSTakashi Sakamoto if (port < p->midi_ports) 2596aa7de05SMark Rutland WRITE_ONCE(p->midi[port], midi); 26003e2a67eSTakashi Sakamoto } 26103e2a67eSTakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger); 26203e2a67eSTakashi Sakamoto 263df075feeSTakashi Sakamoto /* 264df075feeSTakashi Sakamoto * To avoid sending MIDI bytes at too high a rate, assume that the receiving 265df075feeSTakashi Sakamoto * device has a FIFO, and track how much it is filled. This values increases 266df075feeSTakashi Sakamoto * by one whenever we send one byte in a packet, but the FIFO empties at 267df075feeSTakashi Sakamoto * a constant rate independent of our packet rate. One packet has syt_interval 268df075feeSTakashi Sakamoto * samples, so the number of bytes that empty out of the FIFO, per packet(!), 269df075feeSTakashi Sakamoto * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate. To avoid storing 270df075feeSTakashi Sakamoto * fractional values, the values in midi_fifo_used[] are measured in bytes 271df075feeSTakashi Sakamoto * multiplied by the sample rate. 272df075feeSTakashi Sakamoto */ 273df075feeSTakashi Sakamoto static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port) 274df075feeSTakashi Sakamoto { 275df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 276df075feeSTakashi Sakamoto int used; 277df075feeSTakashi Sakamoto 278df075feeSTakashi Sakamoto used = p->midi_fifo_used[port]; 279df075feeSTakashi Sakamoto if (used == 0) /* common shortcut */ 280df075feeSTakashi Sakamoto return true; 281df075feeSTakashi Sakamoto 282df075feeSTakashi Sakamoto used -= MIDI_BYTES_PER_SECOND * s->syt_interval; 283df075feeSTakashi Sakamoto used = max(used, 0); 284df075feeSTakashi Sakamoto p->midi_fifo_used[port] = used; 285df075feeSTakashi Sakamoto 286df075feeSTakashi Sakamoto return used < p->midi_fifo_limit; 287df075feeSTakashi Sakamoto } 288df075feeSTakashi Sakamoto 289df075feeSTakashi Sakamoto static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port) 290df075feeSTakashi Sakamoto { 291df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 292df075feeSTakashi Sakamoto 293df075feeSTakashi Sakamoto p->midi_fifo_used[port] += amdtp_rate_table[s->sfc]; 294df075feeSTakashi Sakamoto } 295df075feeSTakashi Sakamoto 296df075feeSTakashi Sakamoto static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, 297ab754812STakashi Sakamoto unsigned int frames, unsigned int data_block_counter) 298df075feeSTakashi Sakamoto { 299df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 300df075feeSTakashi Sakamoto unsigned int f, port; 301df075feeSTakashi Sakamoto u8 *b; 302df075feeSTakashi Sakamoto 303df075feeSTakashi Sakamoto for (f = 0; f < frames; f++) { 304df075feeSTakashi Sakamoto b = (u8 *)&buffer[p->midi_position]; 305df075feeSTakashi Sakamoto 306ab754812STakashi Sakamoto port = (data_block_counter + f) % 8; 307df075feeSTakashi Sakamoto if (f < MAX_MIDI_RX_BLOCKS && 308df075feeSTakashi Sakamoto midi_ratelimit_per_packet(s, port) && 309df075feeSTakashi Sakamoto p->midi[port] != NULL && 310df075feeSTakashi Sakamoto snd_rawmidi_transmit(p->midi[port], &b[1], 1) == 1) { 311df075feeSTakashi Sakamoto midi_rate_use_one_byte(s, port); 312df075feeSTakashi Sakamoto b[0] = 0x81; 313df075feeSTakashi Sakamoto } else { 314df075feeSTakashi Sakamoto b[0] = 0x80; 315df075feeSTakashi Sakamoto b[1] = 0; 316df075feeSTakashi Sakamoto } 317df075feeSTakashi Sakamoto b[2] = 0; 318df075feeSTakashi Sakamoto b[3] = 0; 319df075feeSTakashi Sakamoto 320df075feeSTakashi Sakamoto buffer += s->data_block_quadlets; 321df075feeSTakashi Sakamoto } 322df075feeSTakashi Sakamoto } 323df075feeSTakashi Sakamoto 324ab754812STakashi Sakamoto static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, 325ab754812STakashi Sakamoto unsigned int frames, unsigned int data_block_counter) 326df075feeSTakashi Sakamoto { 327df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 328df075feeSTakashi Sakamoto int len; 329df075feeSTakashi Sakamoto u8 *b; 330588f2e2cSTakashi Sakamoto int f; 331df075feeSTakashi Sakamoto 332df075feeSTakashi Sakamoto for (f = 0; f < frames; f++) { 333588f2e2cSTakashi Sakamoto unsigned int port = f; 334588f2e2cSTakashi Sakamoto 335588f2e2cSTakashi Sakamoto if (!(s->flags & CIP_UNALIGHED_DBC)) 336ab754812STakashi Sakamoto port += data_block_counter; 337588f2e2cSTakashi Sakamoto port %= 8; 338df075feeSTakashi Sakamoto b = (u8 *)&buffer[p->midi_position]; 339df075feeSTakashi Sakamoto 340df075feeSTakashi Sakamoto len = b[0] - 0x80; 341df075feeSTakashi Sakamoto if ((1 <= len) && (len <= 3) && (p->midi[port])) 342df075feeSTakashi Sakamoto snd_rawmidi_receive(p->midi[port], b + 1, len); 343df075feeSTakashi Sakamoto 344df075feeSTakashi Sakamoto buffer += s->data_block_quadlets; 345df075feeSTakashi Sakamoto } 346df075feeSTakashi Sakamoto } 347df075feeSTakashi Sakamoto 348*9a738ad1STakashi Sakamoto static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, 349*9a738ad1STakashi Sakamoto const struct pkt_desc *descs, 350*9a738ad1STakashi Sakamoto unsigned int packets, 351d2c104a3STakashi Sakamoto struct snd_pcm_substream *pcm) 352df075feeSTakashi Sakamoto { 353df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 3549fc90644STakashi Sakamoto unsigned int pcm_frames = 0; 355*9a738ad1STakashi Sakamoto int i; 356*9a738ad1STakashi Sakamoto 357*9a738ad1STakashi Sakamoto for (i = 0; i < packets; ++i) { 358*9a738ad1STakashi Sakamoto const struct pkt_desc *desc = descs + i; 359*9a738ad1STakashi Sakamoto __be32 *buf = desc->ctx_payload; 360*9a738ad1STakashi Sakamoto unsigned int data_blocks = desc->data_blocks; 361df075feeSTakashi Sakamoto 362df075feeSTakashi Sakamoto if (pcm) { 363*9a738ad1STakashi Sakamoto write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 364*9a738ad1STakashi Sakamoto pcm_frames += data_blocks * p->frame_multiplier; 365df075feeSTakashi Sakamoto } else { 366*9a738ad1STakashi Sakamoto write_pcm_silence(s, buf, data_blocks); 367df075feeSTakashi Sakamoto } 368df075feeSTakashi Sakamoto 369d2c104a3STakashi Sakamoto if (p->midi_ports) { 370*9a738ad1STakashi Sakamoto write_midi_messages(s, buf, data_blocks, 371d2c104a3STakashi Sakamoto desc->data_block_counter); 372d2c104a3STakashi Sakamoto } 373*9a738ad1STakashi Sakamoto } 374df075feeSTakashi Sakamoto 375df075feeSTakashi Sakamoto return pcm_frames; 376df075feeSTakashi Sakamoto } 377df075feeSTakashi Sakamoto 378*9a738ad1STakashi Sakamoto static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, 379*9a738ad1STakashi Sakamoto const struct pkt_desc *descs, 380*9a738ad1STakashi Sakamoto unsigned int packets, 381d2c104a3STakashi Sakamoto struct snd_pcm_substream *pcm) 382df075feeSTakashi Sakamoto { 383df075feeSTakashi Sakamoto struct amdtp_am824 *p = s->protocol; 3849fc90644STakashi Sakamoto unsigned int pcm_frames = 0; 385*9a738ad1STakashi Sakamoto int i; 386*9a738ad1STakashi Sakamoto 387*9a738ad1STakashi Sakamoto for (i = 0; i < packets; ++i) { 388*9a738ad1STakashi Sakamoto const struct pkt_desc *desc = descs + i; 389*9a738ad1STakashi Sakamoto __be32 *buf = desc->ctx_payload; 390*9a738ad1STakashi Sakamoto unsigned int data_blocks = desc->data_blocks; 391df075feeSTakashi Sakamoto 392df075feeSTakashi Sakamoto if (pcm) { 393*9a738ad1STakashi Sakamoto read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 394*9a738ad1STakashi Sakamoto pcm_frames += data_blocks * p->frame_multiplier; 395df075feeSTakashi Sakamoto } 396df075feeSTakashi Sakamoto 397d2c104a3STakashi Sakamoto if (p->midi_ports) { 398*9a738ad1STakashi Sakamoto read_midi_messages(s, buf, data_blocks, 399d2c104a3STakashi Sakamoto desc->data_block_counter); 400d2c104a3STakashi Sakamoto } 401*9a738ad1STakashi Sakamoto } 402df075feeSTakashi Sakamoto 403df075feeSTakashi Sakamoto return pcm_frames; 404df075feeSTakashi Sakamoto } 405df075feeSTakashi Sakamoto 40603e2a67eSTakashi Sakamoto /** 4075955815eSTakashi Sakamoto * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824 4085955815eSTakashi Sakamoto * data block 4095955815eSTakashi Sakamoto * @s: the AMDTP stream to initialize 4105955815eSTakashi Sakamoto * @unit: the target of the stream 4115955815eSTakashi Sakamoto * @dir: the direction of stream 4125955815eSTakashi Sakamoto * @flags: the packet transmission method to use 4135955815eSTakashi Sakamoto */ 4145955815eSTakashi Sakamoto int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit, 4155955815eSTakashi Sakamoto enum amdtp_stream_direction dir, enum cip_flags flags) 4165955815eSTakashi Sakamoto { 417*9a738ad1STakashi Sakamoto amdtp_stream_process_ctx_payloads_t process_ctx_payloads; 418df075feeSTakashi Sakamoto 419df075feeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) 420*9a738ad1STakashi Sakamoto process_ctx_payloads = process_ir_ctx_payloads; 421df075feeSTakashi Sakamoto else 422*9a738ad1STakashi Sakamoto process_ctx_payloads = process_it_ctx_payloads; 423df075feeSTakashi Sakamoto 424df075feeSTakashi Sakamoto return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, 425*9a738ad1STakashi Sakamoto process_ctx_payloads, sizeof(struct amdtp_am824)); 4265955815eSTakashi Sakamoto } 4275955815eSTakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_init); 428