18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/firewire-constants.h> 38c2ecf20Sopenharmony_ci#include <stdio.h> 48c2ecf20Sopenharmony_ci#include <stdlib.h> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "list.h" 78c2ecf20Sopenharmony_ci#include "nosy-dump.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define CSR_FCP_COMMAND 0xfffff0000b00ull 108c2ecf20Sopenharmony_ci#define CSR_FCP_RESPONSE 0xfffff0000d00ull 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic const char * const ctype_names[] = { 138c2ecf20Sopenharmony_ci [0x0] = "control", [0x8] = "not implemented", 148c2ecf20Sopenharmony_ci [0x1] = "status", [0x9] = "accepted", 158c2ecf20Sopenharmony_ci [0x2] = "specific inquiry", [0xa] = "rejected", 168c2ecf20Sopenharmony_ci [0x3] = "notify", [0xb] = "in transition", 178c2ecf20Sopenharmony_ci [0x4] = "general inquiry", [0xc] = "stable", 188c2ecf20Sopenharmony_ci [0x5] = "(reserved 0x05)", [0xd] = "changed", 198c2ecf20Sopenharmony_ci [0x6] = "(reserved 0x06)", [0xe] = "(reserved 0x0e)", 208c2ecf20Sopenharmony_ci [0x7] = "(reserved 0x07)", [0xf] = "interim", 218c2ecf20Sopenharmony_ci}; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic const char * const subunit_type_names[] = { 248c2ecf20Sopenharmony_ci [0x00] = "monitor", [0x10] = "(reserved 0x10)", 258c2ecf20Sopenharmony_ci [0x01] = "audio", [0x11] = "(reserved 0x11)", 268c2ecf20Sopenharmony_ci [0x02] = "printer", [0x12] = "(reserved 0x12)", 278c2ecf20Sopenharmony_ci [0x03] = "disc", [0x13] = "(reserved 0x13)", 288c2ecf20Sopenharmony_ci [0x04] = "tape recorder/player",[0x14] = "(reserved 0x14)", 298c2ecf20Sopenharmony_ci [0x05] = "tuner", [0x15] = "(reserved 0x15)", 308c2ecf20Sopenharmony_ci [0x06] = "ca", [0x16] = "(reserved 0x16)", 318c2ecf20Sopenharmony_ci [0x07] = "camera", [0x17] = "(reserved 0x17)", 328c2ecf20Sopenharmony_ci [0x08] = "(reserved 0x08)", [0x18] = "(reserved 0x18)", 338c2ecf20Sopenharmony_ci [0x09] = "panel", [0x19] = "(reserved 0x19)", 348c2ecf20Sopenharmony_ci [0x0a] = "bulletin board", [0x1a] = "(reserved 0x1a)", 358c2ecf20Sopenharmony_ci [0x0b] = "camera storage", [0x1b] = "(reserved 0x1b)", 368c2ecf20Sopenharmony_ci [0x0c] = "(reserved 0x0c)", [0x1c] = "vendor unique", 378c2ecf20Sopenharmony_ci [0x0d] = "(reserved 0x0d)", [0x1d] = "all subunit types", 388c2ecf20Sopenharmony_ci [0x0e] = "(reserved 0x0e)", [0x1e] = "subunit_type extended to next byte", 398c2ecf20Sopenharmony_ci [0x0f] = "(reserved 0x0f)", [0x1f] = "unit", 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct avc_enum { 438c2ecf20Sopenharmony_ci int value; 448c2ecf20Sopenharmony_ci const char *name; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct avc_field { 488c2ecf20Sopenharmony_ci const char *name; /* Short name for field. */ 498c2ecf20Sopenharmony_ci int offset; /* Location of field, specified in bits; */ 508c2ecf20Sopenharmony_ci /* negative means from end of packet. */ 518c2ecf20Sopenharmony_ci int width; /* Width of field, 0 means use data_length. */ 528c2ecf20Sopenharmony_ci struct avc_enum *names; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct avc_opcode_info { 568c2ecf20Sopenharmony_ci const char *name; 578c2ecf20Sopenharmony_ci struct avc_field fields[8]; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct avc_enum power_field_names[] = { 618c2ecf20Sopenharmony_ci { 0x70, "on" }, 628c2ecf20Sopenharmony_ci { 0x60, "off" }, 638c2ecf20Sopenharmony_ci { } 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic const struct avc_opcode_info opcode_info[256] = { 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* TA Document 1999026 */ 698c2ecf20Sopenharmony_ci /* AV/C Digital Interface Command Set General Specification 4.0 */ 708c2ecf20Sopenharmony_ci [0xb2] = { "power", { 718c2ecf20Sopenharmony_ci { "state", 0, 8, power_field_names } 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci }, 748c2ecf20Sopenharmony_ci [0x30] = { "unit info", { 758c2ecf20Sopenharmony_ci { "foo", 0, 8 }, 768c2ecf20Sopenharmony_ci { "unit_type", 8, 5 }, 778c2ecf20Sopenharmony_ci { "unit", 13, 3 }, 788c2ecf20Sopenharmony_ci { "company id", 16, 24 }, 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci }, 818c2ecf20Sopenharmony_ci [0x31] = { "subunit info" }, 828c2ecf20Sopenharmony_ci [0x01] = { "reserve" }, 838c2ecf20Sopenharmony_ci [0xb0] = { "version" }, 848c2ecf20Sopenharmony_ci [0x00] = { "vendor dependent" }, 858c2ecf20Sopenharmony_ci [0x02] = { "plug info" }, 868c2ecf20Sopenharmony_ci [0x12] = { "channel usage" }, 878c2ecf20Sopenharmony_ci [0x24] = { "connect" }, 888c2ecf20Sopenharmony_ci [0x20] = { "connect av" }, 898c2ecf20Sopenharmony_ci [0x22] = { "connections" }, 908c2ecf20Sopenharmony_ci [0x11] = { "digital input" }, 918c2ecf20Sopenharmony_ci [0x10] = { "digital output" }, 928c2ecf20Sopenharmony_ci [0x25] = { "disconnect" }, 938c2ecf20Sopenharmony_ci [0x21] = { "disconnect av" }, 948c2ecf20Sopenharmony_ci [0x19] = { "input plug signal format" }, 958c2ecf20Sopenharmony_ci [0x18] = { "output plug signal format" }, 968c2ecf20Sopenharmony_ci [0x1f] = { "general bus setup" }, 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* TA Document 1999025 */ 998c2ecf20Sopenharmony_ci /* AV/C Descriptor Mechanism Specification Version 1.0 */ 1008c2ecf20Sopenharmony_ci [0x0c] = { "create descriptor" }, 1018c2ecf20Sopenharmony_ci [0x08] = { "open descriptor" }, 1028c2ecf20Sopenharmony_ci [0x09] = { "read descriptor" }, 1038c2ecf20Sopenharmony_ci [0x0a] = { "write descriptor" }, 1048c2ecf20Sopenharmony_ci [0x05] = { "open info block" }, 1058c2ecf20Sopenharmony_ci [0x06] = { "read info block" }, 1068c2ecf20Sopenharmony_ci [0x07] = { "write info block" }, 1078c2ecf20Sopenharmony_ci [0x0b] = { "search descriptor" }, 1088c2ecf20Sopenharmony_ci [0x0d] = { "object number select" }, 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* TA Document 1999015 */ 1118c2ecf20Sopenharmony_ci /* AV/C Command Set for Rate Control of Isochronous Data Flow 1.0 */ 1128c2ecf20Sopenharmony_ci [0xb3] = { "rate", { 1138c2ecf20Sopenharmony_ci { "subfunction", 0, 8 }, 1148c2ecf20Sopenharmony_ci { "result", 8, 8 }, 1158c2ecf20Sopenharmony_ci { "plug_type", 16, 8 }, 1168c2ecf20Sopenharmony_ci { "plug_id", 16, 8 }, 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci }, 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* TA Document 1999008 */ 1218c2ecf20Sopenharmony_ci /* AV/C Audio Subunit Specification 1.0 */ 1228c2ecf20Sopenharmony_ci [0xb8] = { "function block" }, 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* TA Document 2001001 */ 1258c2ecf20Sopenharmony_ci /* AV/C Panel Subunit Specification 1.1 */ 1268c2ecf20Sopenharmony_ci [0x7d] = { "gui update" }, 1278c2ecf20Sopenharmony_ci [0x7e] = { "push gui data" }, 1288c2ecf20Sopenharmony_ci [0x7f] = { "user action" }, 1298c2ecf20Sopenharmony_ci [0x7c] = { "pass through" }, 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* */ 1328c2ecf20Sopenharmony_ci [0x26] = { "asynchronous connection" }, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistruct avc_frame { 1368c2ecf20Sopenharmony_ci uint32_t operand0:8; 1378c2ecf20Sopenharmony_ci uint32_t opcode:8; 1388c2ecf20Sopenharmony_ci uint32_t subunit_id:3; 1398c2ecf20Sopenharmony_ci uint32_t subunit_type:5; 1408c2ecf20Sopenharmony_ci uint32_t ctype:4; 1418c2ecf20Sopenharmony_ci uint32_t cts:4; 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void 1458c2ecf20Sopenharmony_cidecode_avc(struct link_transaction *t) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct avc_frame *frame = 1488c2ecf20Sopenharmony_ci (struct avc_frame *) t->request->packet.write_block.data; 1498c2ecf20Sopenharmony_ci const struct avc_opcode_info *info; 1508c2ecf20Sopenharmony_ci const char *name; 1518c2ecf20Sopenharmony_ci char buffer[32]; 1528c2ecf20Sopenharmony_ci int i; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci info = &opcode_info[frame->opcode]; 1558c2ecf20Sopenharmony_ci if (info->name == NULL) { 1568c2ecf20Sopenharmony_ci snprintf(buffer, sizeof(buffer), 1578c2ecf20Sopenharmony_ci "(unknown opcode 0x%02x)", frame->opcode); 1588c2ecf20Sopenharmony_ci name = buffer; 1598c2ecf20Sopenharmony_ci } else { 1608c2ecf20Sopenharmony_ci name = info->name; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci printf("av/c %s, subunit_type=%s, subunit_id=%d, opcode=%s", 1648c2ecf20Sopenharmony_ci ctype_names[frame->ctype], subunit_type_names[frame->subunit_type], 1658c2ecf20Sopenharmony_ci frame->subunit_id, name); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci for (i = 0; info->fields[i].name != NULL; i++) 1688c2ecf20Sopenharmony_ci printf(", %s", info->fields[i].name); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci printf("\n"); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciint 1748c2ecf20Sopenharmony_cidecode_fcp(struct link_transaction *t) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct avc_frame *frame = 1778c2ecf20Sopenharmony_ci (struct avc_frame *) t->request->packet.write_block.data; 1788c2ecf20Sopenharmony_ci unsigned long long offset = 1798c2ecf20Sopenharmony_ci ((unsigned long long) t->request->packet.common.offset_high << 32) | 1808c2ecf20Sopenharmony_ci t->request->packet.common.offset_low; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (t->request->packet.common.tcode != TCODE_WRITE_BLOCK_REQUEST) 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (offset == CSR_FCP_COMMAND || offset == CSR_FCP_RESPONSE) { 1868c2ecf20Sopenharmony_ci switch (frame->cts) { 1878c2ecf20Sopenharmony_ci case 0x00: 1888c2ecf20Sopenharmony_ci decode_avc(t); 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci case 0x01: 1918c2ecf20Sopenharmony_ci printf("cal fcp frame (cts=0x01)\n"); 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci case 0x02: 1948c2ecf20Sopenharmony_ci printf("ehs fcp frame (cts=0x02)\n"); 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci case 0x03: 1978c2ecf20Sopenharmony_ci printf("havi fcp frame (cts=0x03)\n"); 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case 0x0e: 2008c2ecf20Sopenharmony_ci printf("vendor specific fcp frame (cts=0x0e)\n"); 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci case 0x0f: 2038c2ecf20Sopenharmony_ci printf("extended cts\n"); 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci default: 2068c2ecf20Sopenharmony_ci printf("reserved fcp frame (ctx=0x%02x)\n", frame->cts); 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci return 1; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 215