diff options
Diffstat (limited to 'tools/firewire/decode-fcp.c')
-rw-r--r-- | tools/firewire/decode-fcp.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/tools/firewire/decode-fcp.c b/tools/firewire/decode-fcp.c new file mode 100644 index 000000000000..cb9a31b37530 --- /dev/null +++ b/tools/firewire/decode-fcp.c | |||
@@ -0,0 +1,239 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <stdio.h> | ||
3 | #include "list.h" | ||
4 | #include "nosy-dump.h" | ||
5 | |||
6 | #define CSR_FCP_COMMAND 0xfffff0000b00ull | ||
7 | #define CSR_FCP_RESPONSE 0xfffff0000d00ull | ||
8 | |||
9 | static const char * const ctype_names[16] = { | ||
10 | "control", | ||
11 | "status", | ||
12 | "specific inquiry", | ||
13 | "notify", | ||
14 | "general inquiry", | ||
15 | "(reserved 0x05)", | ||
16 | "(reserved 0x06)", | ||
17 | "(reserved 0x07)", | ||
18 | "not implemented", | ||
19 | "accepted", | ||
20 | "rejected", | ||
21 | "in transition", | ||
22 | "stable", | ||
23 | "changed", | ||
24 | "(reserved 0x0e)", | ||
25 | "interim" | ||
26 | }; | ||
27 | |||
28 | static const char * const subunit_type_names[32] = { | ||
29 | "monitor", | ||
30 | "audio", | ||
31 | "printer", | ||
32 | "disc", | ||
33 | "tape recorder/player", | ||
34 | "tuner", | ||
35 | "ca", | ||
36 | "camera", | ||
37 | "(reserved 0x08)", | ||
38 | "panel", | ||
39 | "bulletin board", | ||
40 | "camera storage", | ||
41 | "(reserved 0x0c)", | ||
42 | "(reserved 0x0d)", | ||
43 | "(reserved 0x0e)", | ||
44 | "(reserved 0x0f)", | ||
45 | "(reserved 0x10)", | ||
46 | "(reserved 0x11)", | ||
47 | "(reserved 0x12)", | ||
48 | "(reserved 0x13)", | ||
49 | "(reserved 0x14)", | ||
50 | "(reserved 0x15)", | ||
51 | "(reserved 0x16)", | ||
52 | "(reserved 0x17)", | ||
53 | "(reserved 0x18)", | ||
54 | "(reserved 0x19)", | ||
55 | "(reserved 0x1a)", | ||
56 | "(reserved 0x1b)", | ||
57 | "vendor unique", | ||
58 | "all subunit types", | ||
59 | "subunit_type extended to next byte", | ||
60 | "unit" | ||
61 | }; | ||
62 | |||
63 | struct avc_enum { | ||
64 | int value; | ||
65 | const char *name; | ||
66 | }; | ||
67 | |||
68 | struct avc_field { | ||
69 | const char *name; /* Short name for field. */ | ||
70 | int offset; /* Location of field, specified in bits. | ||
71 | * Negative means from end of packet */ | ||
72 | int width; /* Width of field, 0 means use data_length. */ | ||
73 | struct avc_enum *names; | ||
74 | }; | ||
75 | |||
76 | struct avc_opcode_info { | ||
77 | const char *name; | ||
78 | struct avc_field fields[8]; | ||
79 | }; | ||
80 | |||
81 | struct avc_enum power_field_names[] = { | ||
82 | { 0x70, "on" }, | ||
83 | { 0x60, "off" }, | ||
84 | { } | ||
85 | }; | ||
86 | |||
87 | static const struct avc_opcode_info opcode_info[256] = { | ||
88 | |||
89 | /* TA Document 1999026 | ||
90 | * AV/C Digital Interface Command Set General Specification | ||
91 | * Version 4.0 */ | ||
92 | [0xb2] = | ||
93 | { "power", { | ||
94 | { "state", 0, 8, power_field_names } | ||
95 | } | ||
96 | }, | ||
97 | [0x30] = | ||
98 | { "unit info", { | ||
99 | { "foo", 0, 8 }, | ||
100 | { "unit_type", 8, 5 }, | ||
101 | { "unit", 13, 3 }, | ||
102 | { "company id", 16, 24 }, | ||
103 | } | ||
104 | }, | ||
105 | [0x31] = { "subunit info" }, | ||
106 | [0x01] = { "reserve" }, | ||
107 | [0xb0] = { "version" }, | ||
108 | [0x00] = { "vendor dependent" }, | ||
109 | |||
110 | [0x02] = { "plug info" }, | ||
111 | [0x12] = { "channel usage" }, | ||
112 | [0x24] = { "connect" }, | ||
113 | [0x20] = { "connect av" }, | ||
114 | [0x22] = { "connections" }, | ||
115 | [0x11] = { "digital input" }, | ||
116 | [0x10] = { "digital output" }, | ||
117 | [0x25] = { "disconnect" }, | ||
118 | [0x21] = { "disconnect av" }, | ||
119 | [0x19] = { "input plug signal format" }, | ||
120 | [0x18] = { "output plug signal format" }, | ||
121 | [0x1f] = { "general bus setup" }, | ||
122 | |||
123 | /* TA Document 1999025 | ||
124 | * AV/C Descriptor Mechanism Specification Version 1.0 */ | ||
125 | [0x0c] = { "create descriptor" }, | ||
126 | [0x08] = { "open descriptor" }, | ||
127 | [0x09] = { "read descriptor" }, | ||
128 | [0x0a] = { "write descriptor" }, | ||
129 | [0x05] = { "open info block" }, | ||
130 | [0x06] = { "read info block" }, | ||
131 | [0x07] = { "write info block" }, | ||
132 | [0x0b] = { "search descriptor" }, | ||
133 | [0x0d] = { "object number select" }, | ||
134 | |||
135 | /* TA Document 1999015 | ||
136 | * AV/C Command Set for Rate Control of Isochronous Data Flow 1.0 */ | ||
137 | [0xb3] = { "rate", { | ||
138 | { "subfunction", 0, 8 }, | ||
139 | { "result", 8, 8 }, | ||
140 | { "plug_type", 16, 8 }, | ||
141 | { "plug_id", 16, 8 }, | ||
142 | } | ||
143 | }, | ||
144 | |||
145 | /* TA Document 1999008 | ||
146 | * AV/C Audio Subunit Specification 1.0 */ | ||
147 | [0xb8] = { "function block" }, | ||
148 | |||
149 | /* TA Document 2001001 | ||
150 | * AV/C Panel Subunit Specification 1.1 */ | ||
151 | [0x7d] = { "gui update" }, | ||
152 | [0x7e] = { "push gui data" }, | ||
153 | [0x7f] = { "user action" }, | ||
154 | [0x7c] = { "pass through" }, | ||
155 | |||
156 | /* */ | ||
157 | [0x26] = { "asynchronous connection" }, | ||
158 | }; | ||
159 | |||
160 | struct avc_frame { | ||
161 | unsigned int operand0 : 8; | ||
162 | unsigned int opcode : 8; | ||
163 | unsigned int subunit_id : 3; | ||
164 | unsigned int subunit_type : 5; | ||
165 | unsigned int ctype : 4; | ||
166 | unsigned int cts : 4; | ||
167 | }; | ||
168 | |||
169 | static void | ||
170 | decode_avc(struct link_transaction *t) | ||
171 | { | ||
172 | struct avc_frame *frame = (struct avc_frame *) t->request->packet.write_block.data; | ||
173 | const struct avc_opcode_info *info; | ||
174 | const char *name; | ||
175 | char buffer[32]; | ||
176 | int i; | ||
177 | |||
178 | info = &opcode_info[frame->opcode]; | ||
179 | if (info->name == NULL) { | ||
180 | snprintf(buffer, sizeof buffer, "(unknown opcode 0x%02x)", frame->opcode); | ||
181 | name = buffer; | ||
182 | } else { | ||
183 | name = info->name; | ||
184 | } | ||
185 | |||
186 | printf("av/c %s, subunit_type=%s, subunit_id=%d, opcode=%s", | ||
187 | ctype_names[frame->ctype], subunit_type_names[frame->subunit_type], | ||
188 | frame->subunit_id, name); | ||
189 | |||
190 | for (i = 0; info->fields[i].name != NULL; i++) { | ||
191 | printf(", %s", info->fields[i].name); | ||
192 | } | ||
193 | |||
194 | printf("\n"); | ||
195 | } | ||
196 | |||
197 | |||
198 | int | ||
199 | decode_fcp(struct link_transaction *t) | ||
200 | { | ||
201 | struct avc_frame *frame = (struct avc_frame *) t->request->packet.write_block.data; | ||
202 | unsigned long long offset; | ||
203 | |||
204 | offset = ((unsigned long long) t->request->packet.common.offset_high << 32) | | ||
205 | t->request->packet.common.offset_low; | ||
206 | |||
207 | if (t->request->packet.common.tcode != TCODE_WRITE_BLOCK) | ||
208 | return 0; | ||
209 | |||
210 | if (offset == CSR_FCP_COMMAND || offset == CSR_FCP_RESPONSE) { | ||
211 | switch (frame->cts) { | ||
212 | case 0x00: | ||
213 | decode_avc(t); | ||
214 | break; | ||
215 | case 0x01: | ||
216 | printf("cal fcp frame (cts=0x01)\n"); | ||
217 | break; | ||
218 | case 0x02: | ||
219 | printf("ehs fcp frame (cts=0x02)\n"); | ||
220 | break; | ||
221 | case 0x03: | ||
222 | printf("havi fcp frame (cts=0x03)\n"); | ||
223 | break; | ||
224 | case 0x0e: | ||
225 | printf("vendor specific fcp frame (cts=0x0e)\n"); | ||
226 | break; | ||
227 | case 0x0f: | ||
228 | printf("extended cts\n"); | ||
229 | break; | ||
230 | default: | ||
231 | printf("reserved fcp frame (ctx=0x%02x)\n", frame->cts); | ||
232 | break; | ||
233 | } | ||
234 | return 1; | ||
235 | } | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||