brintos

brintos / linux-shallow public Read only

0
0
Text · 6.5 KiB · 6b89e39 Raw
236 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ff-transaction.c - a part of driver for RME Fireface series4 *5 * Copyright (c) 2015-2017 Takashi Sakamoto6 */7 8#include "ff.h"9 10static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port,11				     int rcode)12{13	struct snd_rawmidi_substream *substream =14				READ_ONCE(ff->rx_midi_substreams[port]);15 16	if (rcode_is_permanent_error(rcode)) {17		ff->rx_midi_error[port] = true;18		return;19	}20 21	if (rcode != RCODE_COMPLETE) {22		/* Transfer the message again, immediately. */23		ff->next_ktime[port] = 0;24		schedule_work(&ff->rx_midi_work[port]);25		return;26	}27 28	snd_rawmidi_transmit_ack(substream, ff->rx_bytes[port]);29	ff->rx_bytes[port] = 0;30 31	if (!snd_rawmidi_transmit_empty(substream))32		schedule_work(&ff->rx_midi_work[port]);33}34 35static void finish_transmit_midi0_msg(struct fw_card *card, int rcode,36				      void *data, size_t length,37				      void *callback_data)38{39	struct snd_ff *ff =40		container_of(callback_data, struct snd_ff, transactions[0]);41	finish_transmit_midi_msg(ff, 0, rcode);42}43 44static void finish_transmit_midi1_msg(struct fw_card *card, int rcode,45				      void *data, size_t length,46				      void *callback_data)47{48	struct snd_ff *ff =49		container_of(callback_data, struct snd_ff, transactions[1]);50	finish_transmit_midi_msg(ff, 1, rcode);51}52 53static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)54{55	struct snd_rawmidi_substream *substream =56			READ_ONCE(ff->rx_midi_substreams[port]);57	int quad_count;58 59	struct fw_device *fw_dev = fw_parent_device(ff->unit);60	unsigned long long addr;61	int generation;62	fw_transaction_callback_t callback;63	int tcode;64 65	if (substream == NULL || snd_rawmidi_transmit_empty(substream))66		return;67 68	if (ff->rx_bytes[port] > 0 || ff->rx_midi_error[port])69		return;70 71	/* Do it in next chance. */72	if (ktime_after(ff->next_ktime[port], ktime_get())) {73		schedule_work(&ff->rx_midi_work[port]);74		return;75	}76 77	quad_count = ff->spec->protocol->fill_midi_msg(ff, substream, port);78	if (quad_count <= 0)79		return;80 81	if (port == 0) {82		addr = ff->spec->midi_rx_addrs[0];83		callback = finish_transmit_midi0_msg;84	} else {85		addr = ff->spec->midi_rx_addrs[1];86		callback = finish_transmit_midi1_msg;87	}88 89	/* Set interval to next transaction. */90	ff->next_ktime[port] = ktime_add_ns(ktime_get(),91			ff->rx_bytes[port] * 8 * (NSEC_PER_SEC / 31250));92 93	if (quad_count == 1)94		tcode = TCODE_WRITE_QUADLET_REQUEST;95	else96		tcode = TCODE_WRITE_BLOCK_REQUEST;97 98	/*99	 * In Linux FireWire core, when generation is updated with memory100	 * barrier, node id has already been updated. In this module, After101	 * this smp_rmb(), load/store instructions to memory are completed.102	 * Thus, both of generation and node id are available with recent103	 * values. This is a light-serialization solution to handle bus reset104	 * events on IEEE 1394 bus.105	 */106	generation = fw_dev->generation;107	smp_rmb();108	fw_send_request(fw_dev->card, &ff->transactions[port], tcode,109			fw_dev->node_id, generation, fw_dev->max_speed,110			addr, &ff->msg_buf[port], quad_count * 4,111			callback, &ff->transactions[port]);112}113 114static void transmit_midi0_msg(struct work_struct *work)115{116	struct snd_ff *ff = container_of(work, struct snd_ff, rx_midi_work[0]);117 118	transmit_midi_msg(ff, 0);119}120 121static void transmit_midi1_msg(struct work_struct *work)122{123	struct snd_ff *ff = container_of(work, struct snd_ff, rx_midi_work[1]);124 125	transmit_midi_msg(ff, 1);126}127 128static void handle_msg(struct fw_card *card, struct fw_request *request, int tcode,129		       int destination, int source, int generation, unsigned long long offset,130		       void *data, size_t length, void *callback_data)131{132	struct snd_ff *ff = callback_data;133	__le32 *buf = data;134	u32 tstamp = fw_request_get_timestamp(request);135	unsigned long flag;136 137	fw_send_response(card, request, RCODE_COMPLETE);138 139	offset -= ff->async_handler.offset;140 141	spin_lock_irqsave(&ff->lock, flag);142	ff->spec->protocol->handle_msg(ff, (unsigned int)offset, buf, length, tstamp);143	spin_unlock_irqrestore(&ff->lock, flag);144}145 146static int allocate_own_address(struct snd_ff *ff, int i)147{148	struct fw_address_region midi_msg_region;149	int err;150 151	ff->async_handler.length = ff->spec->midi_addr_range;152	ff->async_handler.address_callback = handle_msg;153	ff->async_handler.callback_data = ff;154 155	midi_msg_region.start = 0x000100000000ull * i;156	midi_msg_region.end = midi_msg_region.start + ff->async_handler.length;157 158	err = fw_core_add_address_handler(&ff->async_handler, &midi_msg_region);159	if (err >= 0) {160		/* Controllers are allowed to register this region. */161		if (ff->async_handler.offset & 0x0000ffffffff) {162			fw_core_remove_address_handler(&ff->async_handler);163			err = -EAGAIN;164		}165	}166 167	return err;168}169 170// Controllers are allowed to register higher 4 bytes of destination address to171// receive asynchronous transactions for MIDI messages, while the way to172// register lower 4 bytes of address is different depending on protocols. For173// details, please refer to comments in protocol implementations.174//175// This driver expects userspace applications to configure registers for the176// lower address because in most cases such registers has the other settings.177int snd_ff_transaction_reregister(struct snd_ff *ff)178{179	struct fw_card *fw_card = fw_parent_device(ff->unit)->card;180	u32 addr;181	__le32 reg;182 183	/*184	 * Controllers are allowed to register its node ID and upper 2 byte of185	 * local address to listen asynchronous transactions.186	 */187	addr = (fw_card->node_id << 16) | (ff->async_handler.offset >> 32);188	reg = cpu_to_le32(addr);189	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,190				  ff->spec->midi_high_addr,191				  &reg, sizeof(reg), 0);192}193 194int snd_ff_transaction_register(struct snd_ff *ff)195{196	int i, err;197 198	/*199	 * Allocate in Memory Space of IEC 13213, but lower 4 byte in LSB should200	 * be zero due to device specification.201	 */202	for (i = 0; i < 0xffff; i++) {203		err = allocate_own_address(ff, i);204		if (err != -EBUSY && err != -EAGAIN)205			break;206	}207	if (err < 0)208		return err;209 210	err = snd_ff_transaction_reregister(ff);211	if (err < 0)212		return err;213 214	INIT_WORK(&ff->rx_midi_work[0], transmit_midi0_msg);215	INIT_WORK(&ff->rx_midi_work[1], transmit_midi1_msg);216 217	return 0;218}219 220void snd_ff_transaction_unregister(struct snd_ff *ff)221{222	__le32 reg;223 224	if (ff->async_handler.callback_data == NULL)225		return;226	ff->async_handler.callback_data = NULL;227 228	/* Release higher 4 bytes of address. */229	reg = cpu_to_le32(0x00000000);230	snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,231			   ff->spec->midi_high_addr,232			   &reg, sizeof(reg), 0);233 234	fw_core_remove_address_handler(&ff->async_handler);235}236