xref: /openbmc/linux/tools/firewire/decode-fcp.c (revision 1bcc69fb6a48edb3ddf2e8c42f1d1c242196bf74)
19f6d3c4bSStefan Richter #include <stdlib.h>
29f6d3c4bSStefan Richter #include <stdio.h>
39f6d3c4bSStefan Richter #include "list.h"
49f6d3c4bSStefan Richter #include "nosy-dump.h"
59f6d3c4bSStefan Richter 
69f6d3c4bSStefan Richter #define CSR_FCP_COMMAND			0xfffff0000b00ull
79f6d3c4bSStefan Richter #define CSR_FCP_RESPONSE		0xfffff0000d00ull
89f6d3c4bSStefan Richter 
99f6d3c4bSStefan Richter static const char * const ctype_names[16] = {
109f6d3c4bSStefan Richter     "control",
119f6d3c4bSStefan Richter     "status",
129f6d3c4bSStefan Richter     "specific inquiry",
139f6d3c4bSStefan Richter     "notify",
149f6d3c4bSStefan Richter     "general inquiry",
159f6d3c4bSStefan Richter     "(reserved 0x05)",
169f6d3c4bSStefan Richter     "(reserved 0x06)",
179f6d3c4bSStefan Richter     "(reserved 0x07)",
189f6d3c4bSStefan Richter     "not implemented",
199f6d3c4bSStefan Richter     "accepted",
209f6d3c4bSStefan Richter     "rejected",
219f6d3c4bSStefan Richter     "in transition",
229f6d3c4bSStefan Richter     "stable",
239f6d3c4bSStefan Richter     "changed",
249f6d3c4bSStefan Richter     "(reserved 0x0e)",
259f6d3c4bSStefan Richter     "interim"
269f6d3c4bSStefan Richter };
279f6d3c4bSStefan Richter 
289f6d3c4bSStefan Richter static const char * const subunit_type_names[32] = {
299f6d3c4bSStefan Richter     "monitor",
309f6d3c4bSStefan Richter     "audio",
319f6d3c4bSStefan Richter     "printer",
329f6d3c4bSStefan Richter     "disc",
339f6d3c4bSStefan Richter     "tape recorder/player",
349f6d3c4bSStefan Richter     "tuner",
359f6d3c4bSStefan Richter     "ca",
369f6d3c4bSStefan Richter     "camera",
379f6d3c4bSStefan Richter     "(reserved 0x08)",
389f6d3c4bSStefan Richter     "panel",
399f6d3c4bSStefan Richter     "bulletin board",
409f6d3c4bSStefan Richter     "camera storage",
419f6d3c4bSStefan Richter     "(reserved 0x0c)",
429f6d3c4bSStefan Richter     "(reserved 0x0d)",
439f6d3c4bSStefan Richter     "(reserved 0x0e)",
449f6d3c4bSStefan Richter     "(reserved 0x0f)",
459f6d3c4bSStefan Richter     "(reserved 0x10)",
469f6d3c4bSStefan Richter     "(reserved 0x11)",
479f6d3c4bSStefan Richter     "(reserved 0x12)",
489f6d3c4bSStefan Richter     "(reserved 0x13)",
499f6d3c4bSStefan Richter     "(reserved 0x14)",
509f6d3c4bSStefan Richter     "(reserved 0x15)",
519f6d3c4bSStefan Richter     "(reserved 0x16)",
529f6d3c4bSStefan Richter     "(reserved 0x17)",
539f6d3c4bSStefan Richter     "(reserved 0x18)",
549f6d3c4bSStefan Richter     "(reserved 0x19)",
559f6d3c4bSStefan Richter     "(reserved 0x1a)",
569f6d3c4bSStefan Richter     "(reserved 0x1b)",
579f6d3c4bSStefan Richter     "vendor unique",
589f6d3c4bSStefan Richter     "all subunit types",
599f6d3c4bSStefan Richter     "subunit_type extended to next byte",
609f6d3c4bSStefan Richter     "unit"
619f6d3c4bSStefan Richter };
629f6d3c4bSStefan Richter 
639f6d3c4bSStefan Richter struct avc_enum {
649f6d3c4bSStefan Richter     int value;
659f6d3c4bSStefan Richter     const char *name;
669f6d3c4bSStefan Richter };
679f6d3c4bSStefan Richter 
689f6d3c4bSStefan Richter struct avc_field {
699f6d3c4bSStefan Richter   const char *name;	/* Short name for field. */
709f6d3c4bSStefan Richter   int offset;		/* Location of field, specified in bits.
719f6d3c4bSStefan Richter 			 * Negative means from end of packet */
729f6d3c4bSStefan Richter   int width;		/* Width of field, 0 means use data_length. */
739f6d3c4bSStefan Richter   struct avc_enum *names;
749f6d3c4bSStefan Richter };
759f6d3c4bSStefan Richter 
769f6d3c4bSStefan Richter struct avc_opcode_info {
779f6d3c4bSStefan Richter     const char *name;
789f6d3c4bSStefan Richter     struct avc_field fields[8];
799f6d3c4bSStefan Richter };
809f6d3c4bSStefan Richter 
819f6d3c4bSStefan Richter struct avc_enum power_field_names[] = {
829f6d3c4bSStefan Richter     { 0x70, "on" },
839f6d3c4bSStefan Richter     { 0x60, "off" },
849f6d3c4bSStefan Richter     { }
859f6d3c4bSStefan Richter };
869f6d3c4bSStefan Richter 
879f6d3c4bSStefan Richter static const struct avc_opcode_info opcode_info[256] = {
889f6d3c4bSStefan Richter 
899f6d3c4bSStefan Richter     /* TA Document 1999026
909f6d3c4bSStefan Richter      * AV/C Digital Interface Command Set General Specification
919f6d3c4bSStefan Richter      * Version 4.0 */
929f6d3c4bSStefan Richter     [0xb2] =
939f6d3c4bSStefan Richter     { "power", {
949f6d3c4bSStefan Richter 	    { "state", 0, 8, power_field_names }
959f6d3c4bSStefan Richter 	}
969f6d3c4bSStefan Richter     },
979f6d3c4bSStefan Richter     [0x30] =
989f6d3c4bSStefan Richter     { "unit info", {
999f6d3c4bSStefan Richter 	    { "foo", 0, 8 },
1009f6d3c4bSStefan Richter 	    { "unit_type", 8, 5 },
1019f6d3c4bSStefan Richter 	    { "unit", 13, 3 },
1029f6d3c4bSStefan Richter 	    { "company id", 16, 24 },
1039f6d3c4bSStefan Richter 	}
1049f6d3c4bSStefan Richter     },
1059f6d3c4bSStefan Richter     [0x31] = { "subunit info" },
1069f6d3c4bSStefan Richter     [0x01] = { "reserve" },
1079f6d3c4bSStefan Richter     [0xb0] = { "version" },
1089f6d3c4bSStefan Richter     [0x00] = { "vendor dependent" },
1099f6d3c4bSStefan Richter 
1109f6d3c4bSStefan Richter     [0x02] = { "plug info" },
1119f6d3c4bSStefan Richter     [0x12] = { "channel usage" },
1129f6d3c4bSStefan Richter     [0x24] = { "connect" },
1139f6d3c4bSStefan Richter     [0x20] = { "connect av" },
1149f6d3c4bSStefan Richter     [0x22] = { "connections" },
1159f6d3c4bSStefan Richter     [0x11] = { "digital input" },
1169f6d3c4bSStefan Richter     [0x10] = { "digital output" },
1179f6d3c4bSStefan Richter     [0x25] = { "disconnect" },
1189f6d3c4bSStefan Richter     [0x21] = { "disconnect av" },
1199f6d3c4bSStefan Richter     [0x19] = { "input plug signal format" },
1209f6d3c4bSStefan Richter     [0x18] = { "output plug signal format" },
1219f6d3c4bSStefan Richter     [0x1f] = { "general bus setup" },
1229f6d3c4bSStefan Richter 
1239f6d3c4bSStefan Richter     /* TA Document 1999025
1249f6d3c4bSStefan Richter      * AV/C Descriptor Mechanism Specification Version 1.0 */
1259f6d3c4bSStefan Richter     [0x0c] = { "create descriptor" },
1269f6d3c4bSStefan Richter     [0x08] = { "open descriptor" },
1279f6d3c4bSStefan Richter     [0x09] = { "read descriptor" },
1289f6d3c4bSStefan Richter     [0x0a] = { "write descriptor" },
1299f6d3c4bSStefan Richter     [0x05] = { "open info block" },
1309f6d3c4bSStefan Richter     [0x06] = { "read info block" },
1319f6d3c4bSStefan Richter     [0x07] = { "write info block" },
1329f6d3c4bSStefan Richter     [0x0b] = { "search descriptor" },
1339f6d3c4bSStefan Richter     [0x0d] = { "object number select" },
1349f6d3c4bSStefan Richter 
1359f6d3c4bSStefan Richter     /* TA Document 1999015
1369f6d3c4bSStefan Richter      * AV/C Command Set for Rate Control of Isochronous Data Flow 1.0 */
1379f6d3c4bSStefan Richter     [0xb3] = { "rate", {
1389f6d3c4bSStefan Richter 	    { "subfunction", 0, 8 },
1399f6d3c4bSStefan Richter 	    { "result", 8, 8 },
1409f6d3c4bSStefan Richter 	    { "plug_type", 16, 8 },
1419f6d3c4bSStefan Richter 	    { "plug_id", 16, 8 },
1429f6d3c4bSStefan Richter 	}
1439f6d3c4bSStefan Richter     },
1449f6d3c4bSStefan Richter 
1459f6d3c4bSStefan Richter     /* TA Document 1999008
1469f6d3c4bSStefan Richter      * AV/C Audio Subunit Specification 1.0 */
1479f6d3c4bSStefan Richter     [0xb8] = { "function block" },
1489f6d3c4bSStefan Richter 
1499f6d3c4bSStefan Richter     /* TA Document 2001001
1509f6d3c4bSStefan Richter      * AV/C Panel Subunit Specification 1.1 */
1519f6d3c4bSStefan Richter     [0x7d] = { "gui update" },
1529f6d3c4bSStefan Richter     [0x7e] = { "push gui data" },
1539f6d3c4bSStefan Richter     [0x7f] = { "user action" },
1549f6d3c4bSStefan Richter     [0x7c] = { "pass through" },
1559f6d3c4bSStefan Richter 
1569f6d3c4bSStefan Richter     /* */
1579f6d3c4bSStefan Richter     [0x26] = { "asynchronous connection" },
1589f6d3c4bSStefan Richter };
1599f6d3c4bSStefan Richter 
1609f6d3c4bSStefan Richter struct avc_frame {
161*1bcc69fbSStefan Richter     uint32_t operand0:8;
162*1bcc69fbSStefan Richter     uint32_t opcode:8;
163*1bcc69fbSStefan Richter     uint32_t subunit_id:3;
164*1bcc69fbSStefan Richter     uint32_t subunit_type:5;
165*1bcc69fbSStefan Richter     uint32_t ctype:4;
166*1bcc69fbSStefan Richter     uint32_t cts:4;
1679f6d3c4bSStefan Richter };
1689f6d3c4bSStefan Richter 
1699f6d3c4bSStefan Richter static void
1709f6d3c4bSStefan Richter decode_avc(struct link_transaction *t)
1719f6d3c4bSStefan Richter {
1729f6d3c4bSStefan Richter     struct avc_frame *frame = (struct avc_frame *) t->request->packet.write_block.data;
1739f6d3c4bSStefan Richter     const struct avc_opcode_info *info;
1749f6d3c4bSStefan Richter     const char *name;
1759f6d3c4bSStefan Richter     char buffer[32];
1769f6d3c4bSStefan Richter     int i;
1779f6d3c4bSStefan Richter 
1789f6d3c4bSStefan Richter     info = &opcode_info[frame->opcode];
1799f6d3c4bSStefan Richter     if (info->name == NULL) {
1809f6d3c4bSStefan Richter 	snprintf(buffer, sizeof buffer, "(unknown opcode 0x%02x)", frame->opcode);
1819f6d3c4bSStefan Richter 	name = buffer;
1829f6d3c4bSStefan Richter     } else {
1839f6d3c4bSStefan Richter 	name = info->name;
1849f6d3c4bSStefan Richter     }
1859f6d3c4bSStefan Richter 
1869f6d3c4bSStefan Richter     printf("av/c %s, subunit_type=%s, subunit_id=%d, opcode=%s",
1879f6d3c4bSStefan Richter 	   ctype_names[frame->ctype], subunit_type_names[frame->subunit_type],
1889f6d3c4bSStefan Richter 	   frame->subunit_id, name);
1899f6d3c4bSStefan Richter 
1909f6d3c4bSStefan Richter     for (i = 0; info->fields[i].name != NULL; i++) {
1919f6d3c4bSStefan Richter 	printf(", %s", info->fields[i].name);
1929f6d3c4bSStefan Richter     }
1939f6d3c4bSStefan Richter 
1949f6d3c4bSStefan Richter     printf("\n");
1959f6d3c4bSStefan Richter }
1969f6d3c4bSStefan Richter 
1979f6d3c4bSStefan Richter 
1989f6d3c4bSStefan Richter int
1999f6d3c4bSStefan Richter decode_fcp(struct link_transaction *t)
2009f6d3c4bSStefan Richter {
2019f6d3c4bSStefan Richter     struct avc_frame *frame = (struct avc_frame *) t->request->packet.write_block.data;
2029f6d3c4bSStefan Richter     unsigned long long offset;
2039f6d3c4bSStefan Richter 
2049f6d3c4bSStefan Richter     offset = ((unsigned long long) t->request->packet.common.offset_high << 32) |
2059f6d3c4bSStefan Richter 	t->request->packet.common.offset_low;
2069f6d3c4bSStefan Richter 
2079f6d3c4bSStefan Richter     if (t->request->packet.common.tcode != TCODE_WRITE_BLOCK)
2089f6d3c4bSStefan Richter 	return 0;
2099f6d3c4bSStefan Richter 
2109f6d3c4bSStefan Richter     if (offset == CSR_FCP_COMMAND || offset == CSR_FCP_RESPONSE) {
2119f6d3c4bSStefan Richter 	switch (frame->cts) {
2129f6d3c4bSStefan Richter 	case 0x00:
2139f6d3c4bSStefan Richter 	    decode_avc(t);
2149f6d3c4bSStefan Richter 	    break;
2159f6d3c4bSStefan Richter 	case 0x01:
2169f6d3c4bSStefan Richter 	    printf("cal fcp frame (cts=0x01)\n");
2179f6d3c4bSStefan Richter 	    break;
2189f6d3c4bSStefan Richter 	case 0x02:
2199f6d3c4bSStefan Richter 	    printf("ehs fcp frame (cts=0x02)\n");
2209f6d3c4bSStefan Richter 	    break;
2219f6d3c4bSStefan Richter 	case 0x03:
2229f6d3c4bSStefan Richter 	    printf("havi fcp frame (cts=0x03)\n");
2239f6d3c4bSStefan Richter 	    break;
2249f6d3c4bSStefan Richter 	case 0x0e:
2259f6d3c4bSStefan Richter 	    printf("vendor specific fcp frame (cts=0x0e)\n");
2269f6d3c4bSStefan Richter 	    break;
2279f6d3c4bSStefan Richter 	case 0x0f:
2289f6d3c4bSStefan Richter 	    printf("extended cts\n");
2299f6d3c4bSStefan Richter 	    break;
2309f6d3c4bSStefan Richter 	default:
2319f6d3c4bSStefan Richter 	    printf("reserved fcp frame (ctx=0x%02x)\n", frame->cts);
2329f6d3c4bSStefan Richter 	    break;
2339f6d3c4bSStefan Richter 	}
2349f6d3c4bSStefan Richter 	return 1;
2359f6d3c4bSStefan Richter     }
2369f6d3c4bSStefan Richter 
2379f6d3c4bSStefan Richter     return 0;
2389f6d3c4bSStefan Richter }
2399f6d3c4bSStefan Richter 
240