162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * amdtp-dot.c - a part of driver for Digidesign Digi 002/003 family 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014-2015 Takashi Sakamoto 662306a36Sopenharmony_ci * Copyright (C) 2012 Robin Gareus <robin@gareus.org> 762306a36Sopenharmony_ci * Copyright (C) 2012 Damien Zammit <damien@zamaudio.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <sound/pcm.h> 1162306a36Sopenharmony_ci#include "digi00x.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define CIP_FMT_AM 0x10 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 'Clock-based rate control mode' is just supported. */ 1662306a36Sopenharmony_ci#define AMDTP_FDF_AM824 0x00 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 1962306a36Sopenharmony_ci * Nominally 3125 bytes/second, but the MIDI port's clock might be 2062306a36Sopenharmony_ci * 1% too slow, and the bus clock 100 ppm too fast. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci#define MIDI_BYTES_PER_SECOND 3093 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Several devices look only at the first eight data blocks. 2662306a36Sopenharmony_ci * In any case, this is more than enough for the MIDI data rate. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci#define MAX_MIDI_RX_BLOCKS 8 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) + 1. */ 3162306a36Sopenharmony_ci#define MAX_MIDI_PORTS 3 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * The double-oh-three algorithm was discovered by Robin Gareus and Damien 3562306a36Sopenharmony_ci * Zammit in 2012, with reverse-engineering for Digi 003 Rack. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistruct dot_state { 3862306a36Sopenharmony_ci u8 carry; 3962306a36Sopenharmony_ci u8 idx; 4062306a36Sopenharmony_ci unsigned int off; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct amdtp_dot { 4462306a36Sopenharmony_ci unsigned int pcm_channels; 4562306a36Sopenharmony_ci struct dot_state state; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci struct snd_rawmidi_substream *midi[MAX_MIDI_PORTS]; 4862306a36Sopenharmony_ci int midi_fifo_used[MAX_MIDI_PORTS]; 4962306a36Sopenharmony_ci int midi_fifo_limit; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * double-oh-three look up table 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * @param idx index byte (audio-sample data) 0x00..0xff 5662306a36Sopenharmony_ci * @param off channel offset shift 5762306a36Sopenharmony_ci * @return salt to XOR with given data 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci#define BYTE_PER_SAMPLE (4) 6062306a36Sopenharmony_ci#define MAGIC_DOT_BYTE (2) 6162306a36Sopenharmony_ci#define MAGIC_BYTE_OFF(x) (((x) * BYTE_PER_SAMPLE) + MAGIC_DOT_BYTE) 6262306a36Sopenharmony_cistatic u8 dot_scrt(const u8 idx, const unsigned int off) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * the length of the added pattern only depends on the lower nibble 6662306a36Sopenharmony_ci * of the last non-zero data 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci static const u8 len[16] = {0, 1, 3, 5, 7, 9, 11, 13, 14, 6962306a36Sopenharmony_ci 12, 10, 8, 6, 4, 2, 0}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * the lower nibble of the salt. Interleaved sequence. 7362306a36Sopenharmony_ci * this is walked backwards according to len[] 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci static const u8 nib[15] = {0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4, 7662306a36Sopenharmony_ci 0xc, 0x3, 0xd, 0x2, 0xe, 0x1, 0xf}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* circular list for the salt's hi nibble. */ 7962306a36Sopenharmony_ci static const u8 hir[15] = {0x0, 0x6, 0xf, 0x8, 0x7, 0x5, 0x3, 0x4, 8062306a36Sopenharmony_ci 0xc, 0xd, 0xe, 0x1, 0x2, 0xb, 0xa}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* 8362306a36Sopenharmony_ci * start offset for upper nibble mapping. 8462306a36Sopenharmony_ci * note: 9 is /special/. In the case where the high nibble == 0x9, 8562306a36Sopenharmony_ci * hir[] is not used and - coincidentally - the salt's hi nibble is 8662306a36Sopenharmony_ci * 0x09 regardless of the offset. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci static const u8 hio[16] = {0, 11, 12, 6, 7, 5, 1, 4, 8962306a36Sopenharmony_ci 3, 0x00, 14, 13, 8, 9, 10, 2}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci const u8 ln = idx & 0xf; 9262306a36Sopenharmony_ci const u8 hn = (idx >> 4) & 0xf; 9362306a36Sopenharmony_ci const u8 hr = (hn == 0x9) ? 0x9 : hir[(hio[hn] + off) % 15]; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (len[ln] < off) 9662306a36Sopenharmony_ci return 0x00; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return ((nib[14 + off - len[ln]]) | (hr << 4)); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic void dot_encode_step(struct dot_state *state, __be32 *const buffer) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci u8 * const data = (u8 *) buffer; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (data[MAGIC_DOT_BYTE] != 0x00) { 10662306a36Sopenharmony_ci state->off = 0; 10762306a36Sopenharmony_ci state->idx = data[MAGIC_DOT_BYTE] ^ state->carry; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci data[MAGIC_DOT_BYTE] ^= state->carry; 11062306a36Sopenharmony_ci state->carry = dot_scrt(state->idx, ++(state->off)); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciint amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate, 11462306a36Sopenharmony_ci unsigned int pcm_channels) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 11762306a36Sopenharmony_ci int err; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (amdtp_stream_running(s)) 12062306a36Sopenharmony_ci return -EBUSY; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * A first data channel is for MIDI messages, the rest is Multi Bit 12462306a36Sopenharmony_ci * Linear Audio data channel. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1, 1); 12762306a36Sopenharmony_ci if (err < 0) 12862306a36Sopenharmony_ci return err; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci p->pcm_channels = pcm_channels; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci * We do not know the actual MIDI FIFO size of most devices. Just 13662306a36Sopenharmony_ci * assume two bytes, i.e., one byte can be received over the bus while 13762306a36Sopenharmony_ci * the previous one is transmitted over MIDI. 13862306a36Sopenharmony_ci * (The value here is adjusted for midi_ratelimit_per_packet().) 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 14662306a36Sopenharmony_ci __be32 *buffer, unsigned int frames, 14762306a36Sopenharmony_ci unsigned int pcm_frames) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 15062306a36Sopenharmony_ci unsigned int channels = p->pcm_channels; 15162306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = pcm->runtime; 15262306a36Sopenharmony_ci unsigned int pcm_buffer_pointer; 15362306a36Sopenharmony_ci int remaining_frames; 15462306a36Sopenharmony_ci const u32 *src; 15562306a36Sopenharmony_ci int i, c; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 15862306a36Sopenharmony_ci pcm_buffer_pointer %= runtime->buffer_size; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci src = (void *)runtime->dma_area + 16162306a36Sopenharmony_ci frames_to_bytes(runtime, pcm_buffer_pointer); 16262306a36Sopenharmony_ci remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci buffer++; 16562306a36Sopenharmony_ci for (i = 0; i < frames; ++i) { 16662306a36Sopenharmony_ci for (c = 0; c < channels; ++c) { 16762306a36Sopenharmony_ci buffer[c] = cpu_to_be32((*src >> 8) | 0x40000000); 16862306a36Sopenharmony_ci dot_encode_step(&p->state, &buffer[c]); 16962306a36Sopenharmony_ci src++; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci buffer += s->data_block_quadlets; 17262306a36Sopenharmony_ci if (--remaining_frames == 0) 17362306a36Sopenharmony_ci src = (void *)runtime->dma_area; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm, 17862306a36Sopenharmony_ci __be32 *buffer, unsigned int frames, 17962306a36Sopenharmony_ci unsigned int pcm_frames) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 18262306a36Sopenharmony_ci unsigned int channels = p->pcm_channels; 18362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = pcm->runtime; 18462306a36Sopenharmony_ci unsigned int pcm_buffer_pointer; 18562306a36Sopenharmony_ci int remaining_frames; 18662306a36Sopenharmony_ci u32 *dst; 18762306a36Sopenharmony_ci int i, c; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames; 19062306a36Sopenharmony_ci pcm_buffer_pointer %= runtime->buffer_size; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci dst = (void *)runtime->dma_area + 19362306a36Sopenharmony_ci frames_to_bytes(runtime, pcm_buffer_pointer); 19462306a36Sopenharmony_ci remaining_frames = runtime->buffer_size - pcm_buffer_pointer; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci buffer++; 19762306a36Sopenharmony_ci for (i = 0; i < frames; ++i) { 19862306a36Sopenharmony_ci for (c = 0; c < channels; ++c) { 19962306a36Sopenharmony_ci *dst = be32_to_cpu(buffer[c]) << 8; 20062306a36Sopenharmony_ci dst++; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci buffer += s->data_block_quadlets; 20362306a36Sopenharmony_ci if (--remaining_frames == 0) 20462306a36Sopenharmony_ci dst = (void *)runtime->dma_area; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer, 20962306a36Sopenharmony_ci unsigned int data_blocks) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 21262306a36Sopenharmony_ci unsigned int channels, i, c; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci channels = p->pcm_channels; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci buffer++; 21762306a36Sopenharmony_ci for (i = 0; i < data_blocks; ++i) { 21862306a36Sopenharmony_ci for (c = 0; c < channels; ++c) 21962306a36Sopenharmony_ci buffer[c] = cpu_to_be32(0x40000000); 22062306a36Sopenharmony_ci buffer += s->data_block_quadlets; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 22762306a36Sopenharmony_ci int used; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci used = p->midi_fifo_used[port]; 23062306a36Sopenharmony_ci if (used == 0) 23162306a36Sopenharmony_ci return true; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci used -= MIDI_BYTES_PER_SECOND * s->syt_interval; 23462306a36Sopenharmony_ci used = max(used, 0); 23562306a36Sopenharmony_ci p->midi_fifo_used[port] = used; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return used < p->midi_fifo_limit; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic inline void midi_use_bytes(struct amdtp_stream *s, 24162306a36Sopenharmony_ci unsigned int port, unsigned int count) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci p->midi_fifo_used[port] += amdtp_rate_table[s->sfc] * count; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, 24962306a36Sopenharmony_ci unsigned int data_blocks, unsigned int data_block_counter) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 25262306a36Sopenharmony_ci unsigned int f, port; 25362306a36Sopenharmony_ci int len; 25462306a36Sopenharmony_ci u8 *b; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci for (f = 0; f < data_blocks; f++) { 25762306a36Sopenharmony_ci port = (data_block_counter + f) % 8; 25862306a36Sopenharmony_ci b = (u8 *)&buffer[0]; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci len = 0; 26162306a36Sopenharmony_ci if (port < MAX_MIDI_PORTS && 26262306a36Sopenharmony_ci midi_ratelimit_per_packet(s, port) && 26362306a36Sopenharmony_ci p->midi[port] != NULL) 26462306a36Sopenharmony_ci len = snd_rawmidi_transmit(p->midi[port], b + 1, 2); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (len > 0) { 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * Upper 4 bits of LSB represent port number. 26962306a36Sopenharmony_ci * - 0000b: physical MIDI port 1. 27062306a36Sopenharmony_ci * - 0010b: physical MIDI port 2. 27162306a36Sopenharmony_ci * - 1110b: console MIDI port. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci if (port == 2) 27462306a36Sopenharmony_ci b[3] = 0xe0; 27562306a36Sopenharmony_ci else if (port == 1) 27662306a36Sopenharmony_ci b[3] = 0x20; 27762306a36Sopenharmony_ci else 27862306a36Sopenharmony_ci b[3] = 0x00; 27962306a36Sopenharmony_ci b[3] |= len; 28062306a36Sopenharmony_ci midi_use_bytes(s, port, len); 28162306a36Sopenharmony_ci } else { 28262306a36Sopenharmony_ci b[1] = 0; 28362306a36Sopenharmony_ci b[2] = 0; 28462306a36Sopenharmony_ci b[3] = 0; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci b[0] = 0x80; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci buffer += s->data_block_quadlets; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, 29362306a36Sopenharmony_ci unsigned int data_blocks) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 29662306a36Sopenharmony_ci unsigned int f, port, len; 29762306a36Sopenharmony_ci u8 *b; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci for (f = 0; f < data_blocks; f++) { 30062306a36Sopenharmony_ci b = (u8 *)&buffer[0]; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci len = b[3] & 0x0f; 30362306a36Sopenharmony_ci if (len > 0) { 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * Upper 4 bits of LSB represent port number. 30662306a36Sopenharmony_ci * - 0000b: physical MIDI port 1. Use port 0. 30762306a36Sopenharmony_ci * - 1110b: console MIDI port. Use port 2. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci if (b[3] >> 4 > 0) 31062306a36Sopenharmony_ci port = 2; 31162306a36Sopenharmony_ci else 31262306a36Sopenharmony_ci port = 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (port < MAX_MIDI_PORTS && p->midi[port]) 31562306a36Sopenharmony_ci snd_rawmidi_receive(p->midi[port], b + 1, len); 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci buffer += s->data_block_quadlets; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ciint amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s, 32362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci int err; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* This protocol delivers 24 bit data in 32bit data channel. */ 32862306a36Sopenharmony_ci err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 32962306a36Sopenharmony_ci if (err < 0) 33062306a36Sopenharmony_ci return err; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return amdtp_stream_add_pcm_hw_constraints(s, runtime); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_civoid amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, 33662306a36Sopenharmony_ci struct snd_rawmidi_substream *midi) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (port < MAX_MIDI_PORTS) 34162306a36Sopenharmony_ci WRITE_ONCE(p->midi[port], midi); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic void process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, 34562306a36Sopenharmony_ci unsigned int count, struct snd_pcm_substream *pcm) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci unsigned int pcm_frames = 0; 34862306a36Sopenharmony_ci int i; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 35162306a36Sopenharmony_ci __be32 *buf = desc->ctx_payload; 35262306a36Sopenharmony_ci unsigned int data_blocks = desc->data_blocks; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (pcm) { 35562306a36Sopenharmony_ci read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 35662306a36Sopenharmony_ci pcm_frames += data_blocks; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci read_midi_messages(s, buf, data_blocks); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci desc = amdtp_stream_next_packet_desc(s, desc); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic void process_it_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, 36662306a36Sopenharmony_ci unsigned int count, struct snd_pcm_substream *pcm) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci unsigned int pcm_frames = 0; 36962306a36Sopenharmony_ci int i; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 37262306a36Sopenharmony_ci __be32 *buf = desc->ctx_payload; 37362306a36Sopenharmony_ci unsigned int data_blocks = desc->data_blocks; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (pcm) { 37662306a36Sopenharmony_ci write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); 37762306a36Sopenharmony_ci pcm_frames += data_blocks; 37862306a36Sopenharmony_ci } else { 37962306a36Sopenharmony_ci write_pcm_silence(s, buf, data_blocks); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci write_midi_messages(s, buf, data_blocks, 38362306a36Sopenharmony_ci desc->data_block_counter); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci desc = amdtp_stream_next_packet_desc(s, desc); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ciint amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit, 39062306a36Sopenharmony_ci enum amdtp_stream_direction dir) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci amdtp_stream_process_ctx_payloads_t process_ctx_payloads; 39362306a36Sopenharmony_ci unsigned int flags = CIP_NONBLOCKING | CIP_UNAWARE_SYT; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci // Use different mode between incoming/outgoing. 39662306a36Sopenharmony_ci if (dir == AMDTP_IN_STREAM) 39762306a36Sopenharmony_ci process_ctx_payloads = process_ir_ctx_payloads; 39862306a36Sopenharmony_ci else 39962306a36Sopenharmony_ci process_ctx_payloads = process_it_ctx_payloads; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM, 40262306a36Sopenharmony_ci process_ctx_payloads, sizeof(struct amdtp_dot)); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_civoid amdtp_dot_reset(struct amdtp_stream *s) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct amdtp_dot *p = s->protocol; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci p->state.carry = 0x00; 41062306a36Sopenharmony_ci p->state.idx = 0x00; 41162306a36Sopenharmony_ci p->state.off = 0; 41262306a36Sopenharmony_ci} 413