18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * amdtp-motu.c - a part of driver for MOTU FireWire series 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <sound/pcm.h> 108c2ecf20Sopenharmony_ci#include "motu.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 138c2ecf20Sopenharmony_ci#include "amdtp-motu-trace.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define CIP_FMT_MOTU 0x02 168c2ecf20Sopenharmony_ci#define CIP_FMT_MOTU_TX_V3 0x22 178c2ecf20Sopenharmony_ci#define MOTU_FDF_AM824 0x22 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Nominally 3125 bytes/second, but the MIDI port's clock might be 218c2ecf20Sopenharmony_ci * 1% too slow, and the bus clock 100 ppm too fast. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci#define MIDI_BYTES_PER_SECOND 3093 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct amdtp_motu { 268c2ecf20Sopenharmony_ci /* For timestamp processing. */ 278c2ecf20Sopenharmony_ci unsigned int quotient_ticks_per_event; 288c2ecf20Sopenharmony_ci unsigned int remainder_ticks_per_event; 298c2ecf20Sopenharmony_ci unsigned int next_ticks; 308c2ecf20Sopenharmony_ci unsigned int next_accumulated; 318c2ecf20Sopenharmony_ci unsigned int next_cycles; 328c2ecf20Sopenharmony_ci unsigned int next_seconds; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci unsigned int pcm_chunks; 358c2ecf20Sopenharmony_ci unsigned int pcm_byte_offset; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *midi; 388c2ecf20Sopenharmony_ci unsigned int midi_ports; 398c2ecf20Sopenharmony_ci unsigned int midi_flag_offset; 408c2ecf20Sopenharmony_ci unsigned int midi_byte_offset; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci int midi_db_count; 438c2ecf20Sopenharmony_ci unsigned int midi_db_interval; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciint amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, 478c2ecf20Sopenharmony_ci unsigned int midi_ports, 488c2ecf20Sopenharmony_ci struct snd_motu_packet_format *formats) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci static const struct { 518c2ecf20Sopenharmony_ci unsigned int quotient_ticks_per_event; 528c2ecf20Sopenharmony_ci unsigned int remainder_ticks_per_event; 538c2ecf20Sopenharmony_ci } params[] = { 548c2ecf20Sopenharmony_ci [CIP_SFC_44100] = { 557, 123 }, 558c2ecf20Sopenharmony_ci [CIP_SFC_48000] = { 512, 0 }, 568c2ecf20Sopenharmony_ci [CIP_SFC_88200] = { 278, 282 }, 578c2ecf20Sopenharmony_ci [CIP_SFC_96000] = { 256, 0 }, 588c2ecf20Sopenharmony_ci [CIP_SFC_176400] = { 139, 141 }, 598c2ecf20Sopenharmony_ci [CIP_SFC_192000] = { 128, 0 }, 608c2ecf20Sopenharmony_ci }; 618c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 628c2ecf20Sopenharmony_ci unsigned int pcm_chunks, data_chunks, data_block_quadlets; 638c2ecf20Sopenharmony_ci unsigned int delay; 648c2ecf20Sopenharmony_ci unsigned int mode; 658c2ecf20Sopenharmony_ci int i, err; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (amdtp_stream_running(s)) 688c2ecf20Sopenharmony_ci return -EBUSY; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) { 718c2ecf20Sopenharmony_ci if (snd_motu_clock_rates[i] == rate) { 728c2ecf20Sopenharmony_ci mode = i >> 1; 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(snd_motu_clock_rates)) 778c2ecf20Sopenharmony_ci return -EINVAL; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci // Each data block includes SPH in its head. Data chunks follow with 808c2ecf20Sopenharmony_ci // 3 byte alignment. Padding follows with zero to conform to quadlet 818c2ecf20Sopenharmony_ci // alignment. 828c2ecf20Sopenharmony_ci pcm_chunks = formats->pcm_chunks[mode]; 838c2ecf20Sopenharmony_ci data_chunks = formats->msg_chunks + pcm_chunks; 848c2ecf20Sopenharmony_ci data_block_quadlets = 1 + DIV_ROUND_UP(data_chunks * 3, 4); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci err = amdtp_stream_set_parameters(s, rate, data_block_quadlets); 878c2ecf20Sopenharmony_ci if (err < 0) 888c2ecf20Sopenharmony_ci return err; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci p->pcm_chunks = pcm_chunks; 918c2ecf20Sopenharmony_ci p->pcm_byte_offset = formats->pcm_byte_offset; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci p->midi_ports = midi_ports; 948c2ecf20Sopenharmony_ci p->midi_flag_offset = formats->midi_flag_offset; 958c2ecf20Sopenharmony_ci p->midi_byte_offset = formats->midi_byte_offset; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci p->midi_db_count = 0; 988c2ecf20Sopenharmony_ci p->midi_db_interval = rate / MIDI_BYTES_PER_SECOND; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* IEEE 1394 bus requires. */ 1018c2ecf20Sopenharmony_ci delay = 0x2e00; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* For no-data or empty packets to adjust PCM sampling frequency. */ 1048c2ecf20Sopenharmony_ci delay += 8000 * 3072 * s->syt_interval / rate; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci p->next_seconds = 0; 1078c2ecf20Sopenharmony_ci p->next_cycles = delay / 3072; 1088c2ecf20Sopenharmony_ci p->quotient_ticks_per_event = params[s->sfc].quotient_ticks_per_event; 1098c2ecf20Sopenharmony_ci p->remainder_ticks_per_event = params[s->sfc].remainder_ticks_per_event; 1108c2ecf20Sopenharmony_ci p->next_ticks = delay % 3072; 1118c2ecf20Sopenharmony_ci p->next_accumulated = 0; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 1178c2ecf20Sopenharmony_ci __be32 *buffer, unsigned int data_blocks, 1188c2ecf20Sopenharmony_ci unsigned int pcm_frames) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 1218c2ecf20Sopenharmony_ci unsigned int channels = p->pcm_chunks; 1228c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = pcm->runtime; 1238c2ecf20Sopenharmony_ci unsigned int pcm_buffer_pointer; 1248c2ecf20Sopenharmony_ci int remaining_frames; 1258c2ecf20Sopenharmony_ci u8 *byte; 1268c2ecf20Sopenharmony_ci u32 *dst; 1278c2ecf20Sopenharmony_ci int i, c; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 1308c2ecf20Sopenharmony_ci pcm_buffer_pointer %= runtime->buffer_size; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci dst = (void *)runtime->dma_area + 1338c2ecf20Sopenharmony_ci frames_to_bytes(runtime, pcm_buffer_pointer); 1348c2ecf20Sopenharmony_ci remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; ++i) { 1378c2ecf20Sopenharmony_ci byte = (u8 *)buffer + p->pcm_byte_offset; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for (c = 0; c < channels; ++c) { 1408c2ecf20Sopenharmony_ci *dst = (byte[0] << 24) | 1418c2ecf20Sopenharmony_ci (byte[1] << 16) | 1428c2ecf20Sopenharmony_ci (byte[2] << 8); 1438c2ecf20Sopenharmony_ci byte += 3; 1448c2ecf20Sopenharmony_ci dst++; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 1478c2ecf20Sopenharmony_ci if (--remaining_frames == 0) 1488c2ecf20Sopenharmony_ci dst = (void *)runtime->dma_area; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 1538c2ecf20Sopenharmony_ci __be32 *buffer, unsigned int data_blocks, 1548c2ecf20Sopenharmony_ci unsigned int pcm_frames) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 1578c2ecf20Sopenharmony_ci unsigned int channels = p->pcm_chunks; 1588c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = pcm->runtime; 1598c2ecf20Sopenharmony_ci unsigned int pcm_buffer_pointer; 1608c2ecf20Sopenharmony_ci int remaining_frames; 1618c2ecf20Sopenharmony_ci u8 *byte; 1628c2ecf20Sopenharmony_ci const u32 *src; 1638c2ecf20Sopenharmony_ci int i, c; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 1668c2ecf20Sopenharmony_ci pcm_buffer_pointer %= runtime->buffer_size; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci src = (void *)runtime->dma_area + 1698c2ecf20Sopenharmony_ci frames_to_bytes(runtime, pcm_buffer_pointer); 1708c2ecf20Sopenharmony_ci remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; ++i) { 1738c2ecf20Sopenharmony_ci byte = (u8 *)buffer + p->pcm_byte_offset; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci for (c = 0; c < channels; ++c) { 1768c2ecf20Sopenharmony_ci byte[0] = (*src >> 24) & 0xff; 1778c2ecf20Sopenharmony_ci byte[1] = (*src >> 16) & 0xff; 1788c2ecf20Sopenharmony_ci byte[2] = (*src >> 8) & 0xff; 1798c2ecf20Sopenharmony_ci byte += 3; 1808c2ecf20Sopenharmony_ci src++; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 1848c2ecf20Sopenharmony_ci if (--remaining_frames == 0) 1858c2ecf20Sopenharmony_ci src = (void *)runtime->dma_area; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer, 1908c2ecf20Sopenharmony_ci unsigned int data_blocks) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 1938c2ecf20Sopenharmony_ci unsigned int channels, i, c; 1948c2ecf20Sopenharmony_ci u8 *byte; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci channels = p->pcm_chunks; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; ++i) { 1998c2ecf20Sopenharmony_ci byte = (u8 *)buffer + p->pcm_byte_offset; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci for (c = 0; c < channels; ++c) { 2028c2ecf20Sopenharmony_ci byte[0] = 0; 2038c2ecf20Sopenharmony_ci byte[1] = 0; 2048c2ecf20Sopenharmony_ci byte[2] = 0; 2058c2ecf20Sopenharmony_ci byte += 3; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ciint amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s, 2138c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci int err; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* TODO: how to set an constraint for exactly 24bit PCM sample? */ 2188c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 2198c2ecf20Sopenharmony_ci if (err < 0) 2208c2ecf20Sopenharmony_ci return err; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return amdtp_stream_add_pcm_hw_constraints(s, runtime); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_civoid amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port, 2268c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *midi) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (port < p->midi_ports) 2318c2ecf20Sopenharmony_ci WRITE_ONCE(p->midi, midi); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, 2358c2ecf20Sopenharmony_ci unsigned int data_blocks) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 2388c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *midi = READ_ONCE(p->midi); 2398c2ecf20Sopenharmony_ci u8 *b; 2408c2ecf20Sopenharmony_ci int i; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; i++) { 2438c2ecf20Sopenharmony_ci b = (u8 *)buffer; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (midi && p->midi_db_count == 0 && 2468c2ecf20Sopenharmony_ci snd_rawmidi_transmit(midi, b + p->midi_byte_offset, 1) == 1) { 2478c2ecf20Sopenharmony_ci b[p->midi_flag_offset] = 0x01; 2488c2ecf20Sopenharmony_ci } else { 2498c2ecf20Sopenharmony_ci b[p->midi_byte_offset] = 0x00; 2508c2ecf20Sopenharmony_ci b[p->midi_flag_offset] = 0x00; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (--p->midi_db_count < 0) 2568c2ecf20Sopenharmony_ci p->midi_db_count = p->midi_db_interval; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, 2618c2ecf20Sopenharmony_ci unsigned int data_blocks) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 2648c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *midi; 2658c2ecf20Sopenharmony_ci u8 *b; 2668c2ecf20Sopenharmony_ci int i; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; i++) { 2698c2ecf20Sopenharmony_ci b = (u8 *)buffer; 2708c2ecf20Sopenharmony_ci midi = READ_ONCE(p->midi); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (midi && (b[p->midi_flag_offset] & 0x01)) 2738c2ecf20Sopenharmony_ci snd_rawmidi_receive(midi, b + p->midi_byte_offset, 1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* For tracepoints. */ 2808c2ecf20Sopenharmony_cistatic void __maybe_unused copy_sph(u32 *frames, __be32 *buffer, 2818c2ecf20Sopenharmony_ci unsigned int data_blocks, 2828c2ecf20Sopenharmony_ci unsigned int data_block_quadlets) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci unsigned int i; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; ++i) { 2878c2ecf20Sopenharmony_ci *frames = be32_to_cpu(*buffer); 2888c2ecf20Sopenharmony_ci buffer += data_block_quadlets; 2898c2ecf20Sopenharmony_ci frames++; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* For tracepoints. */ 2948c2ecf20Sopenharmony_cistatic void __maybe_unused copy_message(u64 *frames, __be32 *buffer, 2958c2ecf20Sopenharmony_ci unsigned int data_blocks, 2968c2ecf20Sopenharmony_ci unsigned int data_block_quadlets) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci unsigned int i; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* This is just for v2/v3 protocol. */ 3018c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; ++i) { 3028c2ecf20Sopenharmony_ci *frames = (be32_to_cpu(buffer[1]) << 16) | 3038c2ecf20Sopenharmony_ci (be32_to_cpu(buffer[2]) >> 16); 3048c2ecf20Sopenharmony_ci buffer += data_block_quadlets; 3058c2ecf20Sopenharmony_ci frames++; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void probe_tracepoints_events(struct amdtp_stream *s, 3108c2ecf20Sopenharmony_ci const struct pkt_desc *descs, 3118c2ecf20Sopenharmony_ci unsigned int packets) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci int i; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci for (i = 0; i < packets; ++i) { 3168c2ecf20Sopenharmony_ci const struct pkt_desc *desc = descs + i; 3178c2ecf20Sopenharmony_ci __be32 *buf = desc->ctx_payload; 3188c2ecf20Sopenharmony_ci unsigned int data_blocks = desc->data_blocks; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci trace_data_block_sph(s, data_blocks, buf); 3218c2ecf20Sopenharmony_ci trace_data_block_message(s, data_blocks, buf); 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, 3268c2ecf20Sopenharmony_ci const struct pkt_desc *descs, 3278c2ecf20Sopenharmony_ci unsigned int packets, 3288c2ecf20Sopenharmony_ci struct snd_pcm_substream *pcm) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 3318c2ecf20Sopenharmony_ci unsigned int pcm_frames = 0; 3328c2ecf20Sopenharmony_ci int i; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci // For data block processing. 3358c2ecf20Sopenharmony_ci for (i = 0; i < packets; ++i) { 3368c2ecf20Sopenharmony_ci const struct pkt_desc *desc = descs + i; 3378c2ecf20Sopenharmony_ci __be32 *buf = desc->ctx_payload; 3388c2ecf20Sopenharmony_ci unsigned int data_blocks = desc->data_blocks; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (pcm) { 3418c2ecf20Sopenharmony_ci read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 3428c2ecf20Sopenharmony_ci pcm_frames += data_blocks; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (p->midi_ports) 3468c2ecf20Sopenharmony_ci read_midi_messages(s, buf, data_blocks); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci // For tracepoints. 3508c2ecf20Sopenharmony_ci if (trace_data_block_sph_enabled() || 3518c2ecf20Sopenharmony_ci trace_data_block_message_enabled()) 3528c2ecf20Sopenharmony_ci probe_tracepoints_events(s, descs, packets); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return pcm_frames; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic inline void compute_next_elapse_from_start(struct amdtp_motu *p) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci p->next_accumulated += p->remainder_ticks_per_event; 3608c2ecf20Sopenharmony_ci if (p->next_accumulated >= 441) { 3618c2ecf20Sopenharmony_ci p->next_accumulated -= 441; 3628c2ecf20Sopenharmony_ci p->next_ticks++; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci p->next_ticks += p->quotient_ticks_per_event; 3668c2ecf20Sopenharmony_ci if (p->next_ticks >= 3072) { 3678c2ecf20Sopenharmony_ci p->next_ticks -= 3072; 3688c2ecf20Sopenharmony_ci p->next_cycles++; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (p->next_cycles >= 8000) { 3728c2ecf20Sopenharmony_ci p->next_cycles -= 8000; 3738c2ecf20Sopenharmony_ci p->next_seconds++; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (p->next_seconds >= 128) 3778c2ecf20Sopenharmony_ci p->next_seconds -= 128; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void write_sph(struct amdtp_stream *s, __be32 *buffer, 3818c2ecf20Sopenharmony_ci unsigned int data_blocks) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 3848c2ecf20Sopenharmony_ci unsigned int next_cycles; 3858c2ecf20Sopenharmony_ci unsigned int i; 3868c2ecf20Sopenharmony_ci u32 sph; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; i++) { 3898c2ecf20Sopenharmony_ci next_cycles = (s->start_cycle + p->next_cycles) % 8000; 3908c2ecf20Sopenharmony_ci sph = ((next_cycles << 12) | p->next_ticks) & 0x01ffffff; 3918c2ecf20Sopenharmony_ci *buffer = cpu_to_be32(sph); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci compute_next_elapse_from_start(p); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic unsigned int process_it_ctx_payloads(struct amdtp_stream *s, 4008c2ecf20Sopenharmony_ci const struct pkt_desc *descs, 4018c2ecf20Sopenharmony_ci unsigned int packets, 4028c2ecf20Sopenharmony_ci struct snd_pcm_substream *pcm) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct amdtp_motu *p = s->protocol; 4058c2ecf20Sopenharmony_ci unsigned int pcm_frames = 0; 4068c2ecf20Sopenharmony_ci int i; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci // For data block processing. 4098c2ecf20Sopenharmony_ci for (i = 0; i < packets; ++i) { 4108c2ecf20Sopenharmony_ci const struct pkt_desc *desc = descs + i; 4118c2ecf20Sopenharmony_ci __be32 *buf = desc->ctx_payload; 4128c2ecf20Sopenharmony_ci unsigned int data_blocks = desc->data_blocks; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (pcm) { 4158c2ecf20Sopenharmony_ci write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 4168c2ecf20Sopenharmony_ci pcm_frames += data_blocks; 4178c2ecf20Sopenharmony_ci } else { 4188c2ecf20Sopenharmony_ci write_pcm_silence(s, buf, data_blocks); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (p->midi_ports) 4228c2ecf20Sopenharmony_ci write_midi_messages(s, buf, data_blocks); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci // TODO: how to interact control messages between userspace? 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci write_sph(s, buf, data_blocks); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci // For tracepoints. 4308c2ecf20Sopenharmony_ci if (trace_data_block_sph_enabled() || 4318c2ecf20Sopenharmony_ci trace_data_block_message_enabled()) 4328c2ecf20Sopenharmony_ci probe_tracepoints_events(s, descs, packets); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return pcm_frames; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ciint amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, 4388c2ecf20Sopenharmony_ci enum amdtp_stream_direction dir, 4398c2ecf20Sopenharmony_ci const struct snd_motu_spec *spec) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci amdtp_stream_process_ctx_payloads_t process_ctx_payloads; 4428c2ecf20Sopenharmony_ci int fmt = CIP_FMT_MOTU; 4438c2ecf20Sopenharmony_ci int flags = CIP_BLOCKING; 4448c2ecf20Sopenharmony_ci int err; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (dir == AMDTP_IN_STREAM) { 4478c2ecf20Sopenharmony_ci process_ctx_payloads = process_ir_ctx_payloads; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * Units of version 3 transmits packets with invalid CIP header 4518c2ecf20Sopenharmony_ci * against IEC 61883-1. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci if (spec->protocol_version == SND_MOTU_PROTOCOL_V3) { 4548c2ecf20Sopenharmony_ci flags |= CIP_WRONG_DBS | 4558c2ecf20Sopenharmony_ci CIP_SKIP_DBC_ZERO_CHECK | 4568c2ecf20Sopenharmony_ci CIP_HEADER_WITHOUT_EOH; 4578c2ecf20Sopenharmony_ci fmt = CIP_FMT_MOTU_TX_V3; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (spec == &snd_motu_spec_8pre || 4618c2ecf20Sopenharmony_ci spec == &snd_motu_spec_ultralite) { 4628c2ecf20Sopenharmony_ci // 8pre has some quirks. 4638c2ecf20Sopenharmony_ci flags |= CIP_WRONG_DBS | 4648c2ecf20Sopenharmony_ci CIP_SKIP_DBC_ZERO_CHECK; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci } else { 4678c2ecf20Sopenharmony_ci process_ctx_payloads = process_it_ctx_payloads; 4688c2ecf20Sopenharmony_ci flags |= CIP_DBC_IS_END_EVENT; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci err = amdtp_stream_init(s, unit, dir, flags, fmt, process_ctx_payloads, 4728c2ecf20Sopenharmony_ci sizeof(struct amdtp_motu)); 4738c2ecf20Sopenharmony_ci if (err < 0) 4748c2ecf20Sopenharmony_ci return err; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci s->sph = 1; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (dir == AMDTP_OUT_STREAM) { 4798c2ecf20Sopenharmony_ci // Use fixed value for FDF field. 4808c2ecf20Sopenharmony_ci s->ctx_data.rx.fdf = MOTU_FDF_AM824; 4818c2ecf20Sopenharmony_ci // Not used. 4828c2ecf20Sopenharmony_ci s->ctx_data.rx.syt_override = 0xffff; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci} 487