1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 283ef7c75SStefan Richter #include <linux/firewire-constants.h> 39f6d3c4bSStefan Richter #include <stdio.h> 483ef7c75SStefan Richter #include <stdlib.h> 583ef7c75SStefan Richter 69f6d3c4bSStefan Richter #include "list.h" 79f6d3c4bSStefan Richter #include "nosy-dump.h" 89f6d3c4bSStefan Richter 99f6d3c4bSStefan Richter #define CSR_FCP_COMMAND 0xfffff0000b00ull 109f6d3c4bSStefan Richter #define CSR_FCP_RESPONSE 0xfffff0000d00ull 119f6d3c4bSStefan Richter 1292c16f7eSStefan Richter static const char * const ctype_names[] = { 1392c16f7eSStefan Richter [0x0] = "control", [0x8] = "not implemented", 1492c16f7eSStefan Richter [0x1] = "status", [0x9] = "accepted", 1592c16f7eSStefan Richter [0x2] = "specific inquiry", [0xa] = "rejected", 1692c16f7eSStefan Richter [0x3] = "notify", [0xb] = "in transition", 1792c16f7eSStefan Richter [0x4] = "general inquiry", [0xc] = "stable", 1892c16f7eSStefan Richter [0x5] = "(reserved 0x05)", [0xd] = "changed", 1992c16f7eSStefan Richter [0x6] = "(reserved 0x06)", [0xe] = "(reserved 0x0e)", 2092c16f7eSStefan Richter [0x7] = "(reserved 0x07)", [0xf] = "interim", 219f6d3c4bSStefan Richter }; 229f6d3c4bSStefan Richter 2392c16f7eSStefan Richter static const char * const subunit_type_names[] = { 2492c16f7eSStefan Richter [0x00] = "monitor", [0x10] = "(reserved 0x10)", 2592c16f7eSStefan Richter [0x01] = "audio", [0x11] = "(reserved 0x11)", 2692c16f7eSStefan Richter [0x02] = "printer", [0x12] = "(reserved 0x12)", 2792c16f7eSStefan Richter [0x03] = "disc", [0x13] = "(reserved 0x13)", 2892c16f7eSStefan Richter [0x04] = "tape recorder/player",[0x14] = "(reserved 0x14)", 2992c16f7eSStefan Richter [0x05] = "tuner", [0x15] = "(reserved 0x15)", 3092c16f7eSStefan Richter [0x06] = "ca", [0x16] = "(reserved 0x16)", 3192c16f7eSStefan Richter [0x07] = "camera", [0x17] = "(reserved 0x17)", 3292c16f7eSStefan Richter [0x08] = "(reserved 0x08)", [0x18] = "(reserved 0x18)", 3392c16f7eSStefan Richter [0x09] = "panel", [0x19] = "(reserved 0x19)", 3492c16f7eSStefan Richter [0x0a] = "bulletin board", [0x1a] = "(reserved 0x1a)", 3592c16f7eSStefan Richter [0x0b] = "camera storage", [0x1b] = "(reserved 0x1b)", 3692c16f7eSStefan Richter [0x0c] = "(reserved 0x0c)", [0x1c] = "vendor unique", 3792c16f7eSStefan Richter [0x0d] = "(reserved 0x0d)", [0x1d] = "all subunit types", 3892c16f7eSStefan Richter [0x0e] = "(reserved 0x0e)", [0x1e] = "subunit_type extended to next byte", 3992c16f7eSStefan Richter [0x0f] = "(reserved 0x0f)", [0x1f] = "unit", 409f6d3c4bSStefan Richter }; 419f6d3c4bSStefan Richter 429f6d3c4bSStefan Richter struct avc_enum { 439f6d3c4bSStefan Richter int value; 449f6d3c4bSStefan Richter const char *name; 459f6d3c4bSStefan Richter }; 469f6d3c4bSStefan Richter 479f6d3c4bSStefan Richter struct avc_field { 489f6d3c4bSStefan Richter const char *name; /* Short name for field. */ 4992c16f7eSStefan Richter int offset; /* Location of field, specified in bits; */ 5092c16f7eSStefan Richter /* negative means from end of packet. */ 519f6d3c4bSStefan Richter int width; /* Width of field, 0 means use data_length. */ 529f6d3c4bSStefan Richter struct avc_enum *names; 539f6d3c4bSStefan Richter }; 549f6d3c4bSStefan Richter 559f6d3c4bSStefan Richter struct avc_opcode_info { 569f6d3c4bSStefan Richter const char *name; 579f6d3c4bSStefan Richter struct avc_field fields[8]; 589f6d3c4bSStefan Richter }; 599f6d3c4bSStefan Richter 609f6d3c4bSStefan Richter struct avc_enum power_field_names[] = { 619f6d3c4bSStefan Richter { 0x70, "on" }, 629f6d3c4bSStefan Richter { 0x60, "off" }, 639f6d3c4bSStefan Richter { } 649f6d3c4bSStefan Richter }; 659f6d3c4bSStefan Richter 669f6d3c4bSStefan Richter static const struct avc_opcode_info opcode_info[256] = { 679f6d3c4bSStefan Richter 6892c16f7eSStefan Richter /* TA Document 1999026 */ 6992c16f7eSStefan Richter /* AV/C Digital Interface Command Set General Specification 4.0 */ 7092c16f7eSStefan Richter [0xb2] = { "power", { 719f6d3c4bSStefan Richter { "state", 0, 8, power_field_names } 729f6d3c4bSStefan Richter } 739f6d3c4bSStefan Richter }, 7492c16f7eSStefan Richter [0x30] = { "unit info", { 759f6d3c4bSStefan Richter { "foo", 0, 8 }, 769f6d3c4bSStefan Richter { "unit_type", 8, 5 }, 779f6d3c4bSStefan Richter { "unit", 13, 3 }, 789f6d3c4bSStefan Richter { "company id", 16, 24 }, 799f6d3c4bSStefan Richter } 809f6d3c4bSStefan Richter }, 819f6d3c4bSStefan Richter [0x31] = { "subunit info" }, 829f6d3c4bSStefan Richter [0x01] = { "reserve" }, 839f6d3c4bSStefan Richter [0xb0] = { "version" }, 849f6d3c4bSStefan Richter [0x00] = { "vendor dependent" }, 859f6d3c4bSStefan Richter [0x02] = { "plug info" }, 869f6d3c4bSStefan Richter [0x12] = { "channel usage" }, 879f6d3c4bSStefan Richter [0x24] = { "connect" }, 889f6d3c4bSStefan Richter [0x20] = { "connect av" }, 899f6d3c4bSStefan Richter [0x22] = { "connections" }, 909f6d3c4bSStefan Richter [0x11] = { "digital input" }, 919f6d3c4bSStefan Richter [0x10] = { "digital output" }, 929f6d3c4bSStefan Richter [0x25] = { "disconnect" }, 939f6d3c4bSStefan Richter [0x21] = { "disconnect av" }, 949f6d3c4bSStefan Richter [0x19] = { "input plug signal format" }, 959f6d3c4bSStefan Richter [0x18] = { "output plug signal format" }, 969f6d3c4bSStefan Richter [0x1f] = { "general bus setup" }, 979f6d3c4bSStefan Richter 9892c16f7eSStefan Richter /* TA Document 1999025 */ 9992c16f7eSStefan Richter /* AV/C Descriptor Mechanism Specification Version 1.0 */ 1009f6d3c4bSStefan Richter [0x0c] = { "create descriptor" }, 1019f6d3c4bSStefan Richter [0x08] = { "open descriptor" }, 1029f6d3c4bSStefan Richter [0x09] = { "read descriptor" }, 1039f6d3c4bSStefan Richter [0x0a] = { "write descriptor" }, 1049f6d3c4bSStefan Richter [0x05] = { "open info block" }, 1059f6d3c4bSStefan Richter [0x06] = { "read info block" }, 1069f6d3c4bSStefan Richter [0x07] = { "write info block" }, 1079f6d3c4bSStefan Richter [0x0b] = { "search descriptor" }, 1089f6d3c4bSStefan Richter [0x0d] = { "object number select" }, 1099f6d3c4bSStefan Richter 11092c16f7eSStefan Richter /* TA Document 1999015 */ 11192c16f7eSStefan Richter /* AV/C Command Set for Rate Control of Isochronous Data Flow 1.0 */ 1129f6d3c4bSStefan Richter [0xb3] = { "rate", { 1139f6d3c4bSStefan Richter { "subfunction", 0, 8 }, 1149f6d3c4bSStefan Richter { "result", 8, 8 }, 1159f6d3c4bSStefan Richter { "plug_type", 16, 8 }, 1169f6d3c4bSStefan Richter { "plug_id", 16, 8 }, 1179f6d3c4bSStefan Richter } 1189f6d3c4bSStefan Richter }, 1199f6d3c4bSStefan Richter 12092c16f7eSStefan Richter /* TA Document 1999008 */ 12192c16f7eSStefan Richter /* AV/C Audio Subunit Specification 1.0 */ 1229f6d3c4bSStefan Richter [0xb8] = { "function block" }, 1239f6d3c4bSStefan Richter 12492c16f7eSStefan Richter /* TA Document 2001001 */ 12592c16f7eSStefan Richter /* AV/C Panel Subunit Specification 1.1 */ 1269f6d3c4bSStefan Richter [0x7d] = { "gui update" }, 1279f6d3c4bSStefan Richter [0x7e] = { "push gui data" }, 1289f6d3c4bSStefan Richter [0x7f] = { "user action" }, 1299f6d3c4bSStefan Richter [0x7c] = { "pass through" }, 1309f6d3c4bSStefan Richter 1319f6d3c4bSStefan Richter /* */ 1329f6d3c4bSStefan Richter [0x26] = { "asynchronous connection" }, 1339f6d3c4bSStefan Richter }; 1349f6d3c4bSStefan Richter 1359f6d3c4bSStefan Richter struct avc_frame { 1361bcc69fbSStefan Richter uint32_t operand0:8; 1371bcc69fbSStefan Richter uint32_t opcode:8; 1381bcc69fbSStefan Richter uint32_t subunit_id:3; 1391bcc69fbSStefan Richter uint32_t subunit_type:5; 1401bcc69fbSStefan Richter uint32_t ctype:4; 1411bcc69fbSStefan Richter uint32_t cts:4; 1429f6d3c4bSStefan Richter }; 1439f6d3c4bSStefan Richter 1449f6d3c4bSStefan Richter static void 1459f6d3c4bSStefan Richter decode_avc(struct link_transaction *t) 1469f6d3c4bSStefan Richter { 14792c16f7eSStefan Richter struct avc_frame *frame = 14892c16f7eSStefan Richter (struct avc_frame *) t->request->packet.write_block.data; 1499f6d3c4bSStefan Richter const struct avc_opcode_info *info; 1509f6d3c4bSStefan Richter const char *name; 1519f6d3c4bSStefan Richter char buffer[32]; 1529f6d3c4bSStefan Richter int i; 1539f6d3c4bSStefan Richter 1549f6d3c4bSStefan Richter info = &opcode_info[frame->opcode]; 1559f6d3c4bSStefan Richter if (info->name == NULL) { 15692c16f7eSStefan Richter snprintf(buffer, sizeof(buffer), 15792c16f7eSStefan Richter "(unknown opcode 0x%02x)", frame->opcode); 1589f6d3c4bSStefan Richter name = buffer; 1599f6d3c4bSStefan Richter } else { 1609f6d3c4bSStefan Richter name = info->name; 1619f6d3c4bSStefan Richter } 1629f6d3c4bSStefan Richter 1639f6d3c4bSStefan Richter printf("av/c %s, subunit_type=%s, subunit_id=%d, opcode=%s", 1649f6d3c4bSStefan Richter ctype_names[frame->ctype], subunit_type_names[frame->subunit_type], 1659f6d3c4bSStefan Richter frame->subunit_id, name); 1669f6d3c4bSStefan Richter 16792c16f7eSStefan Richter for (i = 0; info->fields[i].name != NULL; i++) 1689f6d3c4bSStefan Richter printf(", %s", info->fields[i].name); 1699f6d3c4bSStefan Richter 1709f6d3c4bSStefan Richter printf("\n"); 1719f6d3c4bSStefan Richter } 1729f6d3c4bSStefan Richter 1739f6d3c4bSStefan Richter int 1749f6d3c4bSStefan Richter decode_fcp(struct link_transaction *t) 1759f6d3c4bSStefan Richter { 17692c16f7eSStefan Richter struct avc_frame *frame = 17792c16f7eSStefan Richter (struct avc_frame *) t->request->packet.write_block.data; 17892c16f7eSStefan Richter unsigned long long offset = 17992c16f7eSStefan Richter ((unsigned long long) t->request->packet.common.offset_high << 32) | 1809f6d3c4bSStefan Richter t->request->packet.common.offset_low; 1819f6d3c4bSStefan Richter 18283ef7c75SStefan Richter if (t->request->packet.common.tcode != TCODE_WRITE_BLOCK_REQUEST) 1839f6d3c4bSStefan Richter return 0; 1849f6d3c4bSStefan Richter 1859f6d3c4bSStefan Richter if (offset == CSR_FCP_COMMAND || offset == CSR_FCP_RESPONSE) { 1869f6d3c4bSStefan Richter switch (frame->cts) { 1879f6d3c4bSStefan Richter case 0x00: 1889f6d3c4bSStefan Richter decode_avc(t); 1899f6d3c4bSStefan Richter break; 1909f6d3c4bSStefan Richter case 0x01: 1919f6d3c4bSStefan Richter printf("cal fcp frame (cts=0x01)\n"); 1929f6d3c4bSStefan Richter break; 1939f6d3c4bSStefan Richter case 0x02: 1949f6d3c4bSStefan Richter printf("ehs fcp frame (cts=0x02)\n"); 1959f6d3c4bSStefan Richter break; 1969f6d3c4bSStefan Richter case 0x03: 1979f6d3c4bSStefan Richter printf("havi fcp frame (cts=0x03)\n"); 1989f6d3c4bSStefan Richter break; 1999f6d3c4bSStefan Richter case 0x0e: 2009f6d3c4bSStefan Richter printf("vendor specific fcp frame (cts=0x0e)\n"); 2019f6d3c4bSStefan Richter break; 2029f6d3c4bSStefan Richter case 0x0f: 2039f6d3c4bSStefan Richter printf("extended cts\n"); 2049f6d3c4bSStefan Richter break; 2059f6d3c4bSStefan Richter default: 2069f6d3c4bSStefan Richter printf("reserved fcp frame (ctx=0x%02x)\n", frame->cts); 2079f6d3c4bSStefan Richter break; 2089f6d3c4bSStefan Richter } 2099f6d3c4bSStefan Richter return 1; 2109f6d3c4bSStefan Richter } 2119f6d3c4bSStefan Richter 2129f6d3c4bSStefan Richter return 0; 2139f6d3c4bSStefan Richter } 2149f6d3c4bSStefan Richter 215