aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2012-01-05 16:36:08 -0500
committerClemens Ladisch <clemens@ladisch.de>2013-10-20 16:07:57 -0400
commitc614475b0ea9f7e6b3f76a46be315579bb899397 (patch)
tree6460fc0b88f1cbeefe509e10f2abc6882ccf2455 /sound/firewire
parent640d9b421d4d8c7593aa8647479a4c7c6fe0ca65 (diff)
ALSA: dice: add a proc file to show device information
For easier debugging, add a proc file to show the device's capabilities and current status. Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/dice.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c
index 3395c8ba7af1..25a96362e1aa 100644
--- a/sound/firewire/dice.c
+++ b/sound/firewire/dice.c
@@ -22,6 +22,7 @@
22#include <sound/core.h> 22#include <sound/core.h>
23#include <sound/firewire.h> 23#include <sound/firewire.h>
24#include <sound/hwdep.h> 24#include <sound/hwdep.h>
25#include <sound/info.h>
25#include <sound/initval.h> 26#include <sound/initval.h>
26#include <sound/pcm.h> 27#include <sound/pcm.h>
27#include <sound/pcm_params.h> 28#include <sound/pcm_params.h>
@@ -857,6 +858,249 @@ static int dice_create_hwdep(struct dice *dice)
857 return 0; 858 return 0;
858} 859}
859 860
861static int dice_proc_read_mem(struct dice *dice, void *buffer,
862 unsigned int offset_q, unsigned int quadlets)
863{
864 unsigned int i;
865 int err;
866
867 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
868 DICE_PRIVATE_SPACE + 4 * offset_q,
869 buffer, 4 * quadlets, 0);
870 if (err < 0)
871 return err;
872
873 for (i = 0; i < quadlets; ++i)
874 be32_to_cpus(&((u32 *)buffer)[i]);
875
876 return 0;
877}
878
879static const char *str_from_array(const char *const strs[], unsigned int count,
880 unsigned int i)
881{
882 if (i < count)
883 return strs[i];
884 else
885 return "(unknown)";
886}
887
888static void dice_proc_fixup_string(char *s, unsigned int size)
889{
890 unsigned int i;
891
892 for (i = 0; i < size; i += 4)
893 cpu_to_le32s((u32 *)(s + i));
894
895 for (i = 0; i < size - 2; ++i) {
896 if (s[i] == '\0')
897 return;
898 if (s[i] == '\\' && s[i + 1] == '\\') {
899 s[i + 2] = '\0';
900 return;
901 }
902 }
903 s[size - 1] = '\0';
904}
905
906static void dice_proc_read(struct snd_info_entry *entry,
907 struct snd_info_buffer *buffer)
908{
909 static const char *const section_names[5] = {
910 "global", "tx", "rx", "ext_sync", "unused2"
911 };
912 static const char *const clock_sources[] = {
913 "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
914 "wc", "arx1", "arx2", "arx3", "arx4", "internal"
915 };
916 static const char *const rates[] = {
917 "32000", "44100", "48000", "88200", "96000", "176400", "192000",
918 "any low", "any mid", "any high", "none"
919 };
920 struct dice *dice = entry->private_data;
921 u32 sections[ARRAY_SIZE(section_names) * 2];
922 struct {
923 u32 number;
924 u32 size;
925 } tx_rx_header;
926 union {
927 struct {
928 u32 owner_hi, owner_lo;
929 u32 notification;
930 char nick_name[NICK_NAME_SIZE];
931 u32 clock_select;
932 u32 enable;
933 u32 status;
934 u32 extended_status;
935 u32 sample_rate;
936 u32 version;
937 u32 clock_caps;
938 char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
939 } global;
940 struct {
941 u32 iso;
942 u32 number_audio;
943 u32 number_midi;
944 u32 speed;
945 char names[TX_NAMES_SIZE];
946 u32 ac3_caps;
947 u32 ac3_enable;
948 } tx;
949 struct {
950 u32 iso;
951 u32 seq_start;
952 u32 number_audio;
953 u32 number_midi;
954 char names[RX_NAMES_SIZE];
955 u32 ac3_caps;
956 u32 ac3_enable;
957 } rx;
958 struct {
959 u32 clock_source;
960 u32 locked;
961 u32 rate;
962 u32 adat_user_data;
963 } ext_sync;
964 } buf;
965 unsigned int quadlets, stream, i;
966
967 if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
968 return;
969 snd_iprintf(buffer, "sections:\n");
970 for (i = 0; i < ARRAY_SIZE(section_names); ++i)
971 snd_iprintf(buffer, " %s: offset %u, size %u\n",
972 section_names[i],
973 sections[i * 2], sections[i * 2 + 1]);
974
975 quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
976 if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
977 return;
978 snd_iprintf(buffer, "global:\n");
979 snd_iprintf(buffer, " owner: %04x:%04x%08x\n",
980 buf.global.owner_hi >> 16,
981 buf.global.owner_hi & 0xffff, buf.global.owner_lo);
982 snd_iprintf(buffer, " notification: %08x\n", buf.global.notification);
983 dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
984 snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name);
985 snd_iprintf(buffer, " clock select: %s %s\n",
986 str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
987 buf.global.clock_select & CLOCK_SOURCE_MASK),
988 str_from_array(rates, ARRAY_SIZE(rates),
989 (buf.global.clock_select & CLOCK_RATE_MASK)
990 >> CLOCK_RATE_SHIFT));
991 snd_iprintf(buffer, " enable: %u\n", buf.global.enable);
992 snd_iprintf(buffer, " status: %slocked %s\n",
993 buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
994 str_from_array(rates, ARRAY_SIZE(rates),
995 (buf.global.status &
996 STATUS_NOMINAL_RATE_MASK)
997 >> CLOCK_RATE_SHIFT));
998 snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status);
999 snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate);
1000 snd_iprintf(buffer, " version: %u.%u.%u.%u\n",
1001 (buf.global.version >> 24) & 0xff,
1002 (buf.global.version >> 16) & 0xff,
1003 (buf.global.version >> 8) & 0xff,
1004 (buf.global.version >> 0) & 0xff);
1005 if (quadlets >= 90) {
1006 snd_iprintf(buffer, " clock caps:");
1007 for (i = 0; i <= 6; ++i)
1008 if (buf.global.clock_caps & (1 << i))
1009 snd_iprintf(buffer, " %s", rates[i]);
1010 for (i = 0; i <= 12; ++i)
1011 if (buf.global.clock_caps & (1 << (16 + i)))
1012 snd_iprintf(buffer, " %s", clock_sources[i]);
1013 snd_iprintf(buffer, "\n");
1014 dice_proc_fixup_string(buf.global.clock_source_names,
1015 CLOCK_SOURCE_NAMES_SIZE);
1016 snd_iprintf(buffer, " clock source names: %s\n",
1017 buf.global.clock_source_names);
1018 }
1019
1020 if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
1021 return;
1022 quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx));
1023 for (stream = 0; stream < tx_rx_header.number; ++stream) {
1024 if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
1025 stream * tx_rx_header.size,
1026 quadlets) < 0)
1027 break;
1028 snd_iprintf(buffer, "tx %u:\n", stream);
1029 snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso);
1030 snd_iprintf(buffer, " audio channels: %u\n",
1031 buf.tx.number_audio);
1032 snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi);
1033 snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed);
1034 if (quadlets >= 68) {
1035 dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
1036 snd_iprintf(buffer, " names: %s\n", buf.tx.names);
1037 }
1038 if (quadlets >= 70) {
1039 snd_iprintf(buffer, " ac3 caps: %08x\n",
1040 buf.tx.ac3_caps);
1041 snd_iprintf(buffer, " ac3 enable: %08x\n",
1042 buf.tx.ac3_enable);
1043 }
1044 }
1045
1046 if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
1047 return;
1048 quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx));
1049 for (stream = 0; stream < tx_rx_header.number; ++stream) {
1050 if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
1051 stream * tx_rx_header.size,
1052 quadlets) < 0)
1053 break;
1054 snd_iprintf(buffer, "rx %u:\n", stream);
1055 snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso);
1056 snd_iprintf(buffer, " sequence start: %u\n",
1057 (int)buf.rx.seq_start);
1058 snd_iprintf(buffer, " audio channels: %u\n",
1059 buf.rx.number_audio);
1060 snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi);
1061 if (quadlets >= 68) {
1062 dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
1063 snd_iprintf(buffer, " names: %s\n", buf.rx.names);
1064 }
1065 if (quadlets >= 70) {
1066 snd_iprintf(buffer, " ac3 caps: %08x\n",
1067 buf.rx.ac3_caps);
1068 snd_iprintf(buffer, " ac3 enable: %08x\n",
1069 buf.rx.ac3_enable);
1070 }
1071 }
1072
1073 quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
1074 if (quadlets >= 4) {
1075 if (dice_proc_read_mem(dice, &buf.ext_sync,
1076 sections[6], 4) < 0)
1077 return;
1078 snd_iprintf(buffer, "ext status:\n");
1079 snd_iprintf(buffer, " clock source: %s\n",
1080 str_from_array(clock_sources,
1081 ARRAY_SIZE(clock_sources),
1082 buf.ext_sync.clock_source));
1083 snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked);
1084 snd_iprintf(buffer, " rate: %s\n",
1085 str_from_array(rates, ARRAY_SIZE(rates),
1086 buf.ext_sync.rate));
1087 snd_iprintf(buffer, " adat user data: ");
1088 if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
1089 snd_iprintf(buffer, "-\n");
1090 else
1091 snd_iprintf(buffer, "%x\n",
1092 buf.ext_sync.adat_user_data);
1093 }
1094}
1095
1096static void dice_create_proc(struct dice *dice)
1097{
1098 struct snd_info_entry *entry;
1099
1100 if (!snd_card_proc_new(dice->card, "dice", &entry))
1101 snd_info_set_text_ops(entry, dice, dice_proc_read);
1102}
1103
860static void dice_card_free(struct snd_card *card) 1104static void dice_card_free(struct snd_card *card)
861{ 1105{
862 struct dice *dice = card->private_data; 1106 struct dice *dice = card->private_data;
@@ -1131,6 +1375,8 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
1131 if (err < 0) 1375 if (err < 0)
1132 goto error; 1376 goto error;
1133 1377
1378 dice_create_proc(dice);
1379
1134 err = snd_card_register(card); 1380 err = snd_card_register(card);
1135 if (err < 0) 1381 if (err < 0)
1136 goto error; 1382 goto error;