brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · db0a031 Raw
308 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * dice_proc.c - a part of driver for Dice based devices4 *5 * Copyright (c) Clemens Ladisch6 * Copyright (c) 2014 Takashi Sakamoto7 */8 9#include "dice.h"10 11static int dice_proc_read_mem(struct snd_dice *dice, void *buffer,12			      unsigned int offset_q, unsigned int quadlets)13{14	unsigned int i;15	int err;16 17	err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,18				 DICE_PRIVATE_SPACE + 4 * offset_q,19				 buffer, 4 * quadlets, 0);20	if (err < 0)21		return err;22 23	for (i = 0; i < quadlets; ++i)24		be32_to_cpus(&((u32 *)buffer)[i]);25 26	return 0;27}28 29static const char *str_from_array(const char *const strs[], unsigned int count,30				  unsigned int i)31{32	if (i < count)33		return strs[i];34 35	return "(unknown)";36}37 38static void dice_proc_fixup_string(char *s, unsigned int size)39{40	unsigned int i;41 42	for (i = 0; i < size; i += 4)43		cpu_to_le32s((u32 *)(s + i));44 45	for (i = 0; i < size - 2; ++i) {46		if (s[i] == '\0')47			return;48		if (s[i] == '\\' && s[i + 1] == '\\') {49			s[i + 2] = '\0';50			return;51		}52	}53	s[size - 1] = '\0';54}55 56static void dice_proc_read(struct snd_info_entry *entry,57			   struct snd_info_buffer *buffer)58{59	static const char *const section_names[5] = {60		"global", "tx", "rx", "ext_sync", "unused2"61	};62	static const char *const clock_sources[] = {63		"aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",64		"wc", "arx1", "arx2", "arx3", "arx4", "internal"65	};66	static const char *const rates[] = {67		"32000", "44100", "48000", "88200", "96000", "176400", "192000",68		"any low", "any mid", "any high", "none"69	};70	struct snd_dice *dice = entry->private_data;71	u32 sections[ARRAY_SIZE(section_names) * 2];72	struct {73		u32 number;74		u32 size;75	} tx_rx_header;76	union {77		struct {78			u32 owner_hi, owner_lo;79			u32 notification;80			char nick_name[NICK_NAME_SIZE];81			u32 clock_select;82			u32 enable;83			u32 status;84			u32 extended_status;85			u32 sample_rate;86			u32 version;87			u32 clock_caps;88			char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];89		} global;90		struct {91			u32 iso;92			u32 number_audio;93			u32 number_midi;94			u32 speed;95			char names[TX_NAMES_SIZE];96			u32 ac3_caps;97			u32 ac3_enable;98		} tx;99		struct {100			u32 iso;101			u32 seq_start;102			u32 number_audio;103			u32 number_midi;104			char names[RX_NAMES_SIZE];105			u32 ac3_caps;106			u32 ac3_enable;107		} rx;108		struct {109			u32 clock_source;110			u32 locked;111			u32 rate;112			u32 adat_user_data;113		} ext_sync;114	} buf;115	unsigned int quadlets, stream, i;116 117	if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)118		return;119	snd_iprintf(buffer, "sections:\n");120	for (i = 0; i < ARRAY_SIZE(section_names); ++i)121		snd_iprintf(buffer, "  %s: offset %u, size %u\n",122			    section_names[i],123			    sections[i * 2], sections[i * 2 + 1]);124 125	quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);126	if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)127		return;128	snd_iprintf(buffer, "global:\n");129	snd_iprintf(buffer, "  owner: %04x:%04x%08x\n",130		    buf.global.owner_hi >> 16,131		    buf.global.owner_hi & 0xffff, buf.global.owner_lo);132	snd_iprintf(buffer, "  notification: %08x\n", buf.global.notification);133	dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);134	snd_iprintf(buffer, "  nick name: %s\n", buf.global.nick_name);135	snd_iprintf(buffer, "  clock select: %s %s\n",136		    str_from_array(clock_sources, ARRAY_SIZE(clock_sources),137				   buf.global.clock_select & CLOCK_SOURCE_MASK),138		    str_from_array(rates, ARRAY_SIZE(rates),139				   (buf.global.clock_select & CLOCK_RATE_MASK)140				   >> CLOCK_RATE_SHIFT));141	snd_iprintf(buffer, "  enable: %u\n", buf.global.enable);142	snd_iprintf(buffer, "  status: %slocked %s\n",143		    buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",144		    str_from_array(rates, ARRAY_SIZE(rates),145				   (buf.global.status &146				    STATUS_NOMINAL_RATE_MASK)147				   >> CLOCK_RATE_SHIFT));148	snd_iprintf(buffer, "  ext status: %08x\n", buf.global.extended_status);149	snd_iprintf(buffer, "  sample rate: %u\n", buf.global.sample_rate);150	if (quadlets >= 90) {151		snd_iprintf(buffer, "  version: %u.%u.%u.%u\n",152			    (buf.global.version >> 24) & 0xff,153			    (buf.global.version >> 16) & 0xff,154			    (buf.global.version >>  8) & 0xff,155			    (buf.global.version >>  0) & 0xff);156		snd_iprintf(buffer, "  clock caps:");157		for (i = 0; i <= 6; ++i)158			if (buf.global.clock_caps & (1 << i))159				snd_iprintf(buffer, " %s", rates[i]);160		for (i = 0; i <= 12; ++i)161			if (buf.global.clock_caps & (1 << (16 + i)))162				snd_iprintf(buffer, " %s", clock_sources[i]);163		snd_iprintf(buffer, "\n");164		dice_proc_fixup_string(buf.global.clock_source_names,165				       CLOCK_SOURCE_NAMES_SIZE);166		snd_iprintf(buffer, "  clock source names: %s\n",167			    buf.global.clock_source_names);168	}169 170	if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)171		return;172	quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);173	for (stream = 0; stream < tx_rx_header.number; ++stream) {174		if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +175				       stream * tx_rx_header.size,176				       quadlets) < 0)177			break;178		snd_iprintf(buffer, "tx %u:\n", stream);179		snd_iprintf(buffer, "  iso channel: %d\n", (int)buf.tx.iso);180		snd_iprintf(buffer, "  audio channels: %u\n",181			    buf.tx.number_audio);182		snd_iprintf(buffer, "  midi ports: %u\n", buf.tx.number_midi);183		snd_iprintf(buffer, "  speed: S%u\n", 100u << buf.tx.speed);184		if (quadlets >= 68) {185			dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);186			snd_iprintf(buffer, "  names: %s\n", buf.tx.names);187		}188		if (quadlets >= 70) {189			snd_iprintf(buffer, "  ac3 caps: %08x\n",190				    buf.tx.ac3_caps);191			snd_iprintf(buffer, "  ac3 enable: %08x\n",192				    buf.tx.ac3_enable);193		}194	}195 196	if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)197		return;198	quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);199	for (stream = 0; stream < tx_rx_header.number; ++stream) {200		if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +201				       stream * tx_rx_header.size,202				       quadlets) < 0)203			break;204		snd_iprintf(buffer, "rx %u:\n", stream);205		snd_iprintf(buffer, "  iso channel: %d\n", (int)buf.rx.iso);206		snd_iprintf(buffer, "  sequence start: %u\n", buf.rx.seq_start);207		snd_iprintf(buffer, "  audio channels: %u\n",208			    buf.rx.number_audio);209		snd_iprintf(buffer, "  midi ports: %u\n", buf.rx.number_midi);210		if (quadlets >= 68) {211			dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);212			snd_iprintf(buffer, "  names: %s\n", buf.rx.names);213		}214		if (quadlets >= 70) {215			snd_iprintf(buffer, "  ac3 caps: %08x\n",216				    buf.rx.ac3_caps);217			snd_iprintf(buffer, "  ac3 enable: %08x\n",218				    buf.rx.ac3_enable);219		}220	}221 222	quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);223	if (quadlets >= 4) {224		if (dice_proc_read_mem(dice, &buf.ext_sync,225				       sections[6], 4) < 0)226			return;227		snd_iprintf(buffer, "ext status:\n");228		snd_iprintf(buffer, "  clock source: %s\n",229			    str_from_array(clock_sources,230					   ARRAY_SIZE(clock_sources),231					   buf.ext_sync.clock_source));232		snd_iprintf(buffer, "  locked: %u\n", buf.ext_sync.locked);233		snd_iprintf(buffer, "  rate: %s\n",234			    str_from_array(rates, ARRAY_SIZE(rates),235					   buf.ext_sync.rate));236		snd_iprintf(buffer, "  adat user data: ");237		if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)238			snd_iprintf(buffer, "-\n");239		else240			snd_iprintf(buffer, "%x\n",241				    buf.ext_sync.adat_user_data);242	}243}244 245static void dice_proc_read_formation(struct snd_info_entry *entry,246				     struct snd_info_buffer *buffer)247{248	static const char *const rate_labels[] = {249		[SND_DICE_RATE_MODE_LOW]	= "low",250		[SND_DICE_RATE_MODE_MIDDLE]	= "middle",251		[SND_DICE_RATE_MODE_HIGH]	= "high",252	};253	struct snd_dice *dice = entry->private_data;254	int i, j;255 256	snd_iprintf(buffer, "Output stream from unit:\n");257	for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i)258		snd_iprintf(buffer, "\t%s", rate_labels[i]);259	snd_iprintf(buffer, "\tMIDI\n");260	for (i = 0; i < MAX_STREAMS; ++i) {261		snd_iprintf(buffer, "Tx %u:", i);262		for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j)263			snd_iprintf(buffer, "\t%u", dice->tx_pcm_chs[i][j]);264		snd_iprintf(buffer, "\t%u\n", dice->tx_midi_ports[i]);265	}266 267	snd_iprintf(buffer, "Input stream to unit:\n");268	for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i)269		snd_iprintf(buffer, "\t%s", rate_labels[i]);270	snd_iprintf(buffer, "\n");271	for (i = 0; i < MAX_STREAMS; ++i) {272		snd_iprintf(buffer, "Rx %u:", i);273		for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j)274			snd_iprintf(buffer, "\t%u", dice->rx_pcm_chs[i][j]);275		snd_iprintf(buffer, "\t%u\n", dice->rx_midi_ports[i]);276	}277}278 279static void add_node(struct snd_dice *dice, struct snd_info_entry *root,280		     const char *name,281		     void (*op)(struct snd_info_entry *entry,282				struct snd_info_buffer *buffer))283{284	struct snd_info_entry *entry;285 286	entry = snd_info_create_card_entry(dice->card, name, root);287	if (entry)288		snd_info_set_text_ops(entry, dice, op);289}290 291void snd_dice_create_proc(struct snd_dice *dice)292{293	struct snd_info_entry *root;294 295	/*296	 * All nodes are automatically removed at snd_card_disconnect(),297	 * by following to link list.298	 */299	root = snd_info_create_card_entry(dice->card, "firewire",300					  dice->card->proc_root);301	if (!root)302		return;303	root->mode = S_IFDIR | 0555;304 305	add_node(dice, root, "dice", dice_proc_read);306	add_node(dice, root, "formation", dice_proc_read_formation);307}308