Lines Matching +full:first +full:- +full:generation

1 // SPDX-License-Identifier: GPL-2.0-only
3 * tascam-transaction.c - a part of driver for TASCAM FireWire series
57 return -EINVAL; in calculate_message_bytes()
67 /* The first byte is used for label, the rest for MIDI bytes. */ in fill_message()
68 label = port->buf; in fill_message()
69 msg = port->buf + 1; in fill_message()
76 if (port->on_sysex) { in fill_message()
80 port->on_sysex = false; in fill_message()
86 if (!port->on_sysex) { in fill_message()
88 *label = (substream->number << 4) | 0x07; in fill_message()
91 *label = (substream->number << 4) | 0x04; in fill_message()
102 port->on_sysex = true; in fill_message()
105 /* On running-status. */ in fill_message()
107 status = port->running_status; in fill_message()
116 /* On running-status. */ in fill_message()
119 if (consume < len - 1) in fill_message()
121 consume = len - 1; in fill_message()
125 msg[0] = port->running_status; in fill_message()
132 port->running_status = msg[0]; in fill_message()
136 *label = (substream->number << 4) | (msg[0] >> 4); in fill_message()
140 memset(msg + len, 0, 3 - len); in fill_message()
150 struct snd_rawmidi_substream *substream = READ_ONCE(port->substream); in async_midi_port_callback()
157 snd_rawmidi_transmit_ack(substream, port->consume_bytes); in async_midi_port_callback()
160 port->next_ktime = 0; in async_midi_port_callback()
163 port->error = true; in async_midi_port_callback()
165 port->idling = true; in async_midi_port_callback()
168 schedule_work(&port->work); in async_midi_port_callback()
175 struct snd_rawmidi_substream *substream = READ_ONCE(port->substream); in midi_port_work()
176 int generation; in midi_port_work() local
179 if (!port->idling || port->error) in midi_port_work()
187 if (ktime_after(port->next_ktime, ktime_get())) { in midi_port_work()
188 schedule_work(&port->work); in midi_port_work()
196 memset(port->buf, 0, 4); in midi_port_work()
197 port->consume_bytes = fill_message(port, substream); in midi_port_work()
198 if (port->consume_bytes <= 0) { in midi_port_work()
200 if (port->consume_bytes == 0) { in midi_port_work()
201 port->next_ktime = 0; in midi_port_work()
202 schedule_work(&port->work); in midi_port_work()
205 port->error = true; in midi_port_work()
211 port->next_ktime = ktime_add_ns(ktime_get(), in midi_port_work()
212 port->consume_bytes * 8 * (NSEC_PER_SEC / 31250)); in midi_port_work()
215 port->idling = false; in midi_port_work()
218 * In Linux FireWire core, when generation is updated with memory in midi_port_work()
221 * Thus, both of generation and node id are available with recent in midi_port_work()
222 * values. This is a light-serialization solution to handle bus reset in midi_port_work()
225 generation = port->parent->generation; in midi_port_work()
228 fw_send_request(port->parent->card, &port->transaction, in midi_port_work()
230 port->parent->node_id, generation, in midi_port_work()
231 port->parent->max_speed, in midi_port_work()
233 port->buf, 4, async_midi_port_callback, in midi_port_work()
239 port->idling = true; in snd_fw_async_midi_port_init()
240 port->error = false; in snd_fw_async_midi_port_init()
241 port->running_status = 0; in snd_fw_async_midi_port_init()
242 port->on_sysex = false; in snd_fw_async_midi_port_init()
247 int generation, unsigned long long offset, in handle_midi_tx() argument
259 if (offset != tscm->async_handler.offset) in handle_midi_tx()
268 if (port >= tscm->spec->midi_capture_ports) in handle_midi_tx()
284 substream = READ_ONCE(tscm->tx_midi_substreams[port]); in handle_midi_tx()
302 * Usually, two quadlets are transferred by one transaction. The first in snd_tscm_transaction_register()
306 tscm->async_handler.length = 8 * 8; in snd_tscm_transaction_register()
307 tscm->async_handler.address_callback = handle_midi_tx; in snd_tscm_transaction_register()
308 tscm->async_handler.callback_data = tscm; in snd_tscm_transaction_register()
310 err = fw_core_add_address_handler(&tscm->async_handler, in snd_tscm_transaction_register()
320 tscm->out_ports[i].parent = fw_parent_device(tscm->unit); in snd_tscm_transaction_register()
321 tscm->out_ports[i].next_ktime = 0; in snd_tscm_transaction_register()
322 INIT_WORK(&tscm->out_ports[i].work, midi_port_work); in snd_tscm_transaction_register()
327 fw_core_remove_address_handler(&tscm->async_handler); in snd_tscm_transaction_register()
328 tscm->async_handler.callback_data = NULL; in snd_tscm_transaction_register()
335 struct fw_device *device = fw_parent_device(tscm->unit); in snd_tscm_transaction_reregister()
340 reg = cpu_to_be32((device->card->node_id << 16) | in snd_tscm_transaction_reregister()
341 (tscm->async_handler.offset >> 32)); in snd_tscm_transaction_reregister()
342 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, in snd_tscm_transaction_reregister()
348 reg = cpu_to_be32(tscm->async_handler.offset); in snd_tscm_transaction_reregister()
349 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, in snd_tscm_transaction_reregister()
357 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, in snd_tscm_transaction_reregister()
365 return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, in snd_tscm_transaction_reregister()
374 if (tscm->async_handler.callback_data == NULL) in snd_tscm_transaction_unregister()
379 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, in snd_tscm_transaction_unregister()
385 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, in snd_tscm_transaction_unregister()
390 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, in snd_tscm_transaction_unregister()
393 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, in snd_tscm_transaction_unregister()
397 fw_core_remove_address_handler(&tscm->async_handler); in snd_tscm_transaction_unregister()
398 tscm->async_handler.callback_data = NULL; in snd_tscm_transaction_unregister()