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