sound/firewire/motu/motu-command-dsp-message-parser.c

Source file repositories/reference/linux-study-clean/sound/firewire/motu/motu-command-dsp-message-parser.c

File Facts

System
Linux kernel
Corpus path
sound/firewire/motu/motu-command-dsp-message-parser.c
Extension
.c
Size
4440 bytes
Lines
180
Domain
Driver Families
Bucket
sound/firewire
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct msg_parser {
	spinlock_t lock;
	enum msg_parser_state state;
	unsigned int interval;
	unsigned int message_count;
	unsigned int fragment_pos;
	unsigned int value_index;
	u64 value;
	struct snd_firewire_motu_command_dsp_meter meter;
};

int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)
{
	struct msg_parser *parser;

	parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
	if (!parser)
		return -ENOMEM;
	spin_lock_init(&parser->lock);
	motu->message_parser = parser;

	return 0;
}

int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc)
{
	struct msg_parser *parser = motu->message_parser;

	parser->state = INITIALIZED;

	// All of data blocks don't have messages with meaningful information.
	switch (sfc) {
	case CIP_SFC_176400:
	case CIP_SFC_192000:
		parser->interval = 4;
		break;
	case CIP_SFC_88200:
	case CIP_SFC_96000:
		parser->interval = 2;
		break;
	case CIP_SFC_32000:
	case CIP_SFC_44100:
	case CIP_SFC_48000:
	default:
		parser->interval = 1;
		break;
	}

	return 0;
}

#define FRAGMENT_POS			6
#define MIDI_BYTE_POS			7
#define MIDI_FLAG_POS			8
// One value of hardware meter consists of 4 messages.
#define FRAGMENTS_PER_VALUE		4
#define VALUES_AT_IMAGE_END		0xffffffffffffffff

void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s,
					const struct pkt_desc *desc, unsigned int count)
{
	struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);
	unsigned int data_block_quadlets = s->data_block_quadlets;
	struct msg_parser *parser = motu->message_parser;
	unsigned int interval = parser->interval;
	int i;

	guard(spinlock_irqsave)(&parser->lock);

	for (i = 0; i < count; ++i) {
		__be32 *buffer = desc->ctx_payload;
		unsigned int data_blocks = desc->data_blocks;
		int j;

		desc = amdtp_stream_next_packet_desc(s, desc);

		for (j = 0; j < data_blocks; ++j) {
			u8 *b = (u8 *)buffer;
			buffer += data_block_quadlets;

			switch (parser->state) {
			case INITIALIZED:
			{
				u8 fragment = b[FRAGMENT_POS];

				if (fragment > 0) {
					parser->value = fragment;
					parser->message_count = 1;
					parser->state = FRAGMENT_DETECTED;
				}

Annotation

Implementation Notes