18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * amdtp-dot.c - a part of driver for Digidesign Digi 002/003 family 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014-2015 Takashi Sakamoto 68c2ecf20Sopenharmony_ci * Copyright (C) 2012 Robin Gareus <robin@gareus.org> 78c2ecf20Sopenharmony_ci * Copyright (C) 2012 Damien Zammit <damien@zamaudio.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <sound/pcm.h> 118c2ecf20Sopenharmony_ci#include "digi00x.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define CIP_FMT_AM 0x10 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 'Clock-based rate control mode' is just supported. */ 168c2ecf20Sopenharmony_ci#define AMDTP_FDF_AM824 0x00 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* 198c2ecf20Sopenharmony_ci * Nominally 3125 bytes/second, but the MIDI port's clock might be 208c2ecf20Sopenharmony_ci * 1% too slow, and the bus clock 100 ppm too fast. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci#define MIDI_BYTES_PER_SECOND 3093 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * Several devices look only at the first eight data blocks. 268c2ecf20Sopenharmony_ci * In any case, this is more than enough for the MIDI data rate. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci#define MAX_MIDI_RX_BLOCKS 8 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 3 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) + 1. */ 318c2ecf20Sopenharmony_ci#define MAX_MIDI_PORTS 3 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * The double-oh-three algorithm was discovered by Robin Gareus and Damien 358c2ecf20Sopenharmony_ci * Zammit in 2012, with reverse-engineering for Digi 003 Rack. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistruct dot_state { 388c2ecf20Sopenharmony_ci u8 carry; 398c2ecf20Sopenharmony_ci u8 idx; 408c2ecf20Sopenharmony_ci unsigned int off; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct amdtp_dot { 448c2ecf20Sopenharmony_ci unsigned int pcm_channels; 458c2ecf20Sopenharmony_ci struct dot_state state; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *midi[MAX_MIDI_PORTS]; 488c2ecf20Sopenharmony_ci int midi_fifo_used[MAX_MIDI_PORTS]; 498c2ecf20Sopenharmony_ci int midi_fifo_limit; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * double-oh-three look up table 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * @param idx index byte (audio-sample data) 0x00..0xff 568c2ecf20Sopenharmony_ci * @param off channel offset shift 578c2ecf20Sopenharmony_ci * @return salt to XOR with given data 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci#define BYTE_PER_SAMPLE (4) 608c2ecf20Sopenharmony_ci#define MAGIC_DOT_BYTE (2) 618c2ecf20Sopenharmony_ci#define MAGIC_BYTE_OFF(x) (((x) * BYTE_PER_SAMPLE) + MAGIC_DOT_BYTE) 628c2ecf20Sopenharmony_cistatic u8 dot_scrt(const u8 idx, const unsigned int off) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * the length of the added pattern only depends on the lower nibble 668c2ecf20Sopenharmony_ci * of the last non-zero data 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci static const u8 len[16] = {0, 1, 3, 5, 7, 9, 11, 13, 14, 698c2ecf20Sopenharmony_ci 12, 10, 8, 6, 4, 2, 0}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * the lower nibble of the salt. Interleaved sequence. 738c2ecf20Sopenharmony_ci * this is walked backwards according to len[] 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci static const u8 nib[15] = {0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4, 768c2ecf20Sopenharmony_ci 0xc, 0x3, 0xd, 0x2, 0xe, 0x1, 0xf}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* circular list for the salt's hi nibble. */ 798c2ecf20Sopenharmony_ci static const u8 hir[15] = {0x0, 0x6, 0xf, 0x8, 0x7, 0x5, 0x3, 0x4, 808c2ecf20Sopenharmony_ci 0xc, 0xd, 0xe, 0x1, 0x2, 0xb, 0xa}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * start offset for upper nibble mapping. 848c2ecf20Sopenharmony_ci * note: 9 is /special/. In the case where the high nibble == 0x9, 858c2ecf20Sopenharmony_ci * hir[] is not used and - coincidentally - the salt's hi nibble is 868c2ecf20Sopenharmony_ci * 0x09 regardless of the offset. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci static const u8 hio[16] = {0, 11, 12, 6, 7, 5, 1, 4, 898c2ecf20Sopenharmony_ci 3, 0x00, 14, 13, 8, 9, 10, 2}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci const u8 ln = idx & 0xf; 928c2ecf20Sopenharmony_ci const u8 hn = (idx >> 4) & 0xf; 938c2ecf20Sopenharmony_ci const u8 hr = (hn == 0x9) ? 0x9 : hir[(hio[hn] + off) % 15]; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (len[ln] < off) 968c2ecf20Sopenharmony_ci return 0x00; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return ((nib[14 + off - len[ln]]) | (hr << 4)); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void dot_encode_step(struct dot_state *state, __be32 *const buffer) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci u8 * const data = (u8 *) buffer; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (data[MAGIC_DOT_BYTE] != 0x00) { 1068c2ecf20Sopenharmony_ci state->off = 0; 1078c2ecf20Sopenharmony_ci state->idx = data[MAGIC_DOT_BYTE] ^ state->carry; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci data[MAGIC_DOT_BYTE] ^= state->carry; 1108c2ecf20Sopenharmony_ci state->carry = dot_scrt(state->idx, ++(state->off)); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciint amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate, 1148c2ecf20Sopenharmony_ci unsigned int pcm_channels) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 1178c2ecf20Sopenharmony_ci int err; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (amdtp_stream_running(s)) 1208c2ecf20Sopenharmony_ci return -EBUSY; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * A first data channel is for MIDI messages, the rest is Multi Bit 1248c2ecf20Sopenharmony_ci * Linear Audio data channel. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1); 1278c2ecf20Sopenharmony_ci if (err < 0) 1288c2ecf20Sopenharmony_ci return err; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci p->pcm_channels = pcm_channels; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * We do not know the actual MIDI FIFO size of most devices. Just 1368c2ecf20Sopenharmony_ci * assume two bytes, i.e., one byte can be received over the bus while 1378c2ecf20Sopenharmony_ci * the previous one is transmitted over MIDI. 1388c2ecf20Sopenharmony_ci * (The value here is adjusted for midi_ratelimit_per_packet().) 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 1468c2ecf20Sopenharmony_ci __be32 *buffer, unsigned int frames, 1478c2ecf20Sopenharmony_ci unsigned int pcm_frames) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 1508c2ecf20Sopenharmony_ci unsigned int channels = p->pcm_channels; 1518c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = pcm->runtime; 1528c2ecf20Sopenharmony_ci unsigned int pcm_buffer_pointer; 1538c2ecf20Sopenharmony_ci int remaining_frames; 1548c2ecf20Sopenharmony_ci const u32 *src; 1558c2ecf20Sopenharmony_ci int i, c; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 1588c2ecf20Sopenharmony_ci pcm_buffer_pointer %= runtime->buffer_size; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci src = (void *)runtime->dma_area + 1618c2ecf20Sopenharmony_ci frames_to_bytes(runtime, pcm_buffer_pointer); 1628c2ecf20Sopenharmony_ci remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci buffer++; 1658c2ecf20Sopenharmony_ci for (i = 0; i < frames; ++i) { 1668c2ecf20Sopenharmony_ci for (c = 0; c < channels; ++c) { 1678c2ecf20Sopenharmony_ci buffer[c] = cpu_to_be32((*src >> 8) | 0x40000000); 1688c2ecf20Sopenharmony_ci dot_encode_step(&p->state, &buffer[c]); 1698c2ecf20Sopenharmony_ci src++; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 1728c2ecf20Sopenharmony_ci if (--remaining_frames == 0) 1738c2ecf20Sopenharmony_ci src = (void *)runtime->dma_area; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 1788c2ecf20Sopenharmony_ci __be32 *buffer, unsigned int frames, 1798c2ecf20Sopenharmony_ci unsigned int pcm_frames) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 1828c2ecf20Sopenharmony_ci unsigned int channels = p->pcm_channels; 1838c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = pcm->runtime; 1848c2ecf20Sopenharmony_ci unsigned int pcm_buffer_pointer; 1858c2ecf20Sopenharmony_ci int remaining_frames; 1868c2ecf20Sopenharmony_ci u32 *dst; 1878c2ecf20Sopenharmony_ci int i, c; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 1908c2ecf20Sopenharmony_ci pcm_buffer_pointer %= runtime->buffer_size; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci dst = (void *)runtime->dma_area + 1938c2ecf20Sopenharmony_ci frames_to_bytes(runtime, pcm_buffer_pointer); 1948c2ecf20Sopenharmony_ci remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci buffer++; 1978c2ecf20Sopenharmony_ci for (i = 0; i < frames; ++i) { 1988c2ecf20Sopenharmony_ci for (c = 0; c < channels; ++c) { 1998c2ecf20Sopenharmony_ci *dst = be32_to_cpu(buffer[c]) << 8; 2008c2ecf20Sopenharmony_ci dst++; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 2038c2ecf20Sopenharmony_ci if (--remaining_frames == 0) 2048c2ecf20Sopenharmony_ci dst = (void *)runtime->dma_area; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer, 2098c2ecf20Sopenharmony_ci unsigned int data_blocks) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 2128c2ecf20Sopenharmony_ci unsigned int channels, i, c; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci channels = p->pcm_channels; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci buffer++; 2178c2ecf20Sopenharmony_ci for (i = 0; i < data_blocks; ++i) { 2188c2ecf20Sopenharmony_ci for (c = 0; c < channels; ++c) 2198c2ecf20Sopenharmony_ci buffer[c] = cpu_to_be32(0x40000000); 2208c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 2278c2ecf20Sopenharmony_ci int used; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci used = p->midi_fifo_used[port]; 2308c2ecf20Sopenharmony_ci if (used == 0) 2318c2ecf20Sopenharmony_ci return true; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci used -= MIDI_BYTES_PER_SECOND * s->syt_interval; 2348c2ecf20Sopenharmony_ci used = max(used, 0); 2358c2ecf20Sopenharmony_ci p->midi_fifo_used[port] = used; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return used < p->midi_fifo_limit; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic inline void midi_use_bytes(struct amdtp_stream *s, 2418c2ecf20Sopenharmony_ci unsigned int port, unsigned int count) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci p->midi_fifo_used[port] += amdtp_rate_table[s->sfc] * count; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, 2498c2ecf20Sopenharmony_ci unsigned int data_blocks, unsigned int data_block_counter) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 2528c2ecf20Sopenharmony_ci unsigned int f, port; 2538c2ecf20Sopenharmony_ci int len; 2548c2ecf20Sopenharmony_ci u8 *b; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci for (f = 0; f < data_blocks; f++) { 2578c2ecf20Sopenharmony_ci port = (data_block_counter + f) % 8; 2588c2ecf20Sopenharmony_ci b = (u8 *)&buffer[0]; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci len = 0; 2618c2ecf20Sopenharmony_ci if (port < MAX_MIDI_PORTS && 2628c2ecf20Sopenharmony_ci midi_ratelimit_per_packet(s, port) && 2638c2ecf20Sopenharmony_ci p->midi[port] != NULL) 2648c2ecf20Sopenharmony_ci len = snd_rawmidi_transmit(p->midi[port], b + 1, 2); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (len > 0) { 2678c2ecf20Sopenharmony_ci /* 2688c2ecf20Sopenharmony_ci * Upper 4 bits of LSB represent port number. 2698c2ecf20Sopenharmony_ci * - 0000b: physical MIDI port 1. 2708c2ecf20Sopenharmony_ci * - 0010b: physical MIDI port 2. 2718c2ecf20Sopenharmony_ci * - 1110b: console MIDI port. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci if (port == 2) 2748c2ecf20Sopenharmony_ci b[3] = 0xe0; 2758c2ecf20Sopenharmony_ci else if (port == 1) 2768c2ecf20Sopenharmony_ci b[3] = 0x20; 2778c2ecf20Sopenharmony_ci else 2788c2ecf20Sopenharmony_ci b[3] = 0x00; 2798c2ecf20Sopenharmony_ci b[3] |= len; 2808c2ecf20Sopenharmony_ci midi_use_bytes(s, port, len); 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci b[1] = 0; 2838c2ecf20Sopenharmony_ci b[2] = 0; 2848c2ecf20Sopenharmony_ci b[3] = 0; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci b[0] = 0x80; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, 2938c2ecf20Sopenharmony_ci unsigned int data_blocks) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 2968c2ecf20Sopenharmony_ci unsigned int f, port, len; 2978c2ecf20Sopenharmony_ci u8 *b; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci for (f = 0; f < data_blocks; f++) { 3008c2ecf20Sopenharmony_ci b = (u8 *)&buffer[0]; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci len = b[3] & 0x0f; 3038c2ecf20Sopenharmony_ci if (len > 0) { 3048c2ecf20Sopenharmony_ci /* 3058c2ecf20Sopenharmony_ci * Upper 4 bits of LSB represent port number. 3068c2ecf20Sopenharmony_ci * - 0000b: physical MIDI port 1. Use port 0. 3078c2ecf20Sopenharmony_ci * - 1110b: console MIDI port. Use port 2. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci if (b[3] >> 4 > 0) 3108c2ecf20Sopenharmony_ci port = 2; 3118c2ecf20Sopenharmony_ci else 3128c2ecf20Sopenharmony_ci port = 0; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (port < MAX_MIDI_PORTS && p->midi[port]) 3158c2ecf20Sopenharmony_ci snd_rawmidi_receive(p->midi[port], b + 1, len); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci buffer += s->data_block_quadlets; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciint amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s, 3238c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci int err; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* This protocol delivers 24 bit data in 32bit data channel. */ 3288c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 3298c2ecf20Sopenharmony_ci if (err < 0) 3308c2ecf20Sopenharmony_ci return err; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return amdtp_stream_add_pcm_hw_constraints(s, runtime); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_civoid amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, 3368c2ecf20Sopenharmony_ci struct snd_rawmidi_substream *midi) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (port < MAX_MIDI_PORTS) 3418c2ecf20Sopenharmony_ci WRITE_ONCE(p->midi[port], midi); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, 3458c2ecf20Sopenharmony_ci const struct pkt_desc *descs, 3468c2ecf20Sopenharmony_ci unsigned int packets, 3478c2ecf20Sopenharmony_ci struct snd_pcm_substream *pcm) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci unsigned int pcm_frames = 0; 3508c2ecf20Sopenharmony_ci int i; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci for (i = 0; i < packets; ++i) { 3538c2ecf20Sopenharmony_ci const struct pkt_desc *desc = descs + i; 3548c2ecf20Sopenharmony_ci __be32 *buf = desc->ctx_payload; 3558c2ecf20Sopenharmony_ci unsigned int data_blocks = desc->data_blocks; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (pcm) { 3588c2ecf20Sopenharmony_ci read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 3598c2ecf20Sopenharmony_ci pcm_frames += data_blocks; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci read_midi_messages(s, buf, data_blocks); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return pcm_frames; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic unsigned int process_it_ctx_payloads(struct amdtp_stream *s, 3698c2ecf20Sopenharmony_ci const struct pkt_desc *descs, 3708c2ecf20Sopenharmony_ci unsigned int packets, 3718c2ecf20Sopenharmony_ci struct snd_pcm_substream *pcm) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci unsigned int pcm_frames = 0; 3748c2ecf20Sopenharmony_ci int i; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci for (i = 0; i < packets; ++i) { 3778c2ecf20Sopenharmony_ci const struct pkt_desc *desc = descs + i; 3788c2ecf20Sopenharmony_ci __be32 *buf = desc->ctx_payload; 3798c2ecf20Sopenharmony_ci unsigned int data_blocks = desc->data_blocks; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (pcm) { 3828c2ecf20Sopenharmony_ci write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 3838c2ecf20Sopenharmony_ci pcm_frames += data_blocks; 3848c2ecf20Sopenharmony_ci } else { 3858c2ecf20Sopenharmony_ci write_pcm_silence(s, buf, data_blocks); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci write_midi_messages(s, buf, data_blocks, 3898c2ecf20Sopenharmony_ci desc->data_block_counter); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return pcm_frames; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ciint amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit, 3968c2ecf20Sopenharmony_ci enum amdtp_stream_direction dir) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci amdtp_stream_process_ctx_payloads_t process_ctx_payloads; 3998c2ecf20Sopenharmony_ci enum cip_flags flags; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci // Use different mode between incoming/outgoing. 4028c2ecf20Sopenharmony_ci if (dir == AMDTP_IN_STREAM) { 4038c2ecf20Sopenharmony_ci flags = CIP_NONBLOCKING; 4048c2ecf20Sopenharmony_ci process_ctx_payloads = process_ir_ctx_payloads; 4058c2ecf20Sopenharmony_ci } else { 4068c2ecf20Sopenharmony_ci flags = CIP_BLOCKING; 4078c2ecf20Sopenharmony_ci process_ctx_payloads = process_it_ctx_payloads; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, 4118c2ecf20Sopenharmony_ci process_ctx_payloads, sizeof(struct amdtp_dot)); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_civoid amdtp_dot_reset(struct amdtp_stream *s) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct amdtp_dot *p = s->protocol; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci p->state.carry = 0x00; 4198c2ecf20Sopenharmony_ci p->state.idx = 0x00; 4208c2ecf20Sopenharmony_ci p->state.off = 0; 4218c2ecf20Sopenharmony_ci} 422