2 * Routines for HDMI dissection
3 * Copyright 2014 Martin Kaiser <martin@kaiser.cx>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 /* this dissector handles I2C messages on the HDMI Display Data Channel (DDC)
26 * EDID (Extended Display Identification Data) messages are dissected here,
27 * HDCP messages are passed on to the HDCP dissector
33 #include <epan/packet.h>
34 #include <epan/ptvcursor.h>
35 #include <epan/expert.h>
36 #include <epan/wmem/wmem.h>
37 #include "packet-hdmi.h"
39 void proto_register_hdmi(void);
41 static int proto_hdmi = -1;
43 static dissector_handle_t hdcp_handle;
45 static gint ett_hdmi = -1;
46 static gint ett_hdmi_edid = -1;
48 static int hf_hdmi_addr = -1;
49 static int hf_hdmi_edid_offset = -1;
50 static int hf_hdmi_edid_hdr = -1;
51 static int hf_hdmi_edid_manf_id = -1;
52 static int hf_hdmi_edid_manf_prod_code = -1;
53 static int hf_hdmi_edid_manf_serial = -1;
54 static int hf_hdmi_edid_manf_week = -1;
55 static int hf_hdmi_edid_mod_year = -1;
56 static int hf_hdmi_edid_manf_year = -1;
59 /* also called Source and Sink in the HDMI spec */
60 #define ADDR_TRX "Transmitter"
61 #define ADDR_RCV "Receiver"
63 /* we use 8bit I2C addresses, including the direction bit */
64 #define ADDR8_HDCP_WRITE 0x74 /* transmitter->receiver */
65 #define ADDR8_HDCP_READ 0x75 /* r->t */
66 #define ADDR8_EDID_WRITE 0xA0 /* t->r */
67 #define ADDR8_EDID_READ 0xA1 /* r->t */
69 #define HDCP_ADDR8(x) (x==ADDR8_HDCP_WRITE || x==ADDR8_HDCP_READ)
71 static const value_string hdmi_addr[] = {
72 { ADDR8_HDCP_WRITE, "transmitter writes HDCP data for receiver" },
73 { ADDR8_HDCP_READ, "transmitter reads HDCP data from receiver" },
75 { ADDR8_EDID_WRITE, "EDID request" },
76 { ADDR8_EDID_READ, "EDID read" },
80 #define EDID_HDR_VALUE G_GUINT64_CONSTANT(0x00ffffffffffff00)
82 /* grab 5 bits, from bit n to n+4, from a big-endian number x
83 map those bits to a capital letter such that A==1, B==2, ... */
84 #define CAPITAL_LETTER(x, n) ('A'-1 + (((x) & (0x1F<<n)) >> n))
88 sub_check_hdmi(packet_info *pinfo _U_)
90 /* by looking at the i2c_phdr only, we can't decide if this packet is HDMI
91 this function is called when the user explicitly selected HDMI
93 therefore, we always return TRUE and hand the data to the (new
94 style) dissector who sees the 8bit address and the packet content */
100 /* dissect EDID data from the receiver
101 return the offset after the dissected data */
103 dissect_hdmi_edid(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree)
106 proto_tree *edid_tree;
109 gchar manf_id_str[4]; /* 3 letters + 0-termination */
112 guint8 edid_ver, edid_rev;
115 ti = proto_tree_add_text(tree, tvb,
116 offset, tvb_reported_length_remaining(tvb, offset),
117 "Extended Display Identification Data (EDID)");
118 edid_tree = proto_item_add_subtree(ti, ett_hdmi_edid);
120 edid_hdr = tvb_get_ntoh64(tvb, offset);
121 if (edid_hdr != EDID_HDR_VALUE)
122 return offset; /* XXX handle fragmented EDID messages */
124 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "EDID");
126 proto_tree_add_item(edid_tree, hf_hdmi_edid_hdr,
127 tvb, offset, 8, ENC_LITTLE_ENDIAN);
130 /* read as big endian for easier splitting */
131 manf_id = tvb_get_ntohs(tvb, offset);
132 /* XXX check that MSB is 0 */
133 manf_id_str[0] = CAPITAL_LETTER(manf_id, 10);
134 manf_id_str[1] = CAPITAL_LETTER(manf_id, 5);
135 manf_id_str[2] = CAPITAL_LETTER(manf_id, 0);
137 proto_tree_add_string(edid_tree, hf_hdmi_edid_manf_id,
138 tvb, offset, 2, manf_id_str);
141 proto_tree_add_item(edid_tree, hf_hdmi_edid_manf_prod_code,
142 tvb, offset, 2, ENC_LITTLE_ENDIAN);
145 proto_tree_add_item(edid_tree, hf_hdmi_edid_manf_serial,
146 tvb, offset, 4, ENC_LITTLE_ENDIAN);
149 week = tvb_get_guint8(tvb, offset);
150 proto_tree_add_item(edid_tree, hf_hdmi_edid_manf_week,
151 tvb, offset, 1, ENC_LITTLE_ENDIAN);
154 year_hf = week==255 ? hf_hdmi_edid_mod_year : hf_hdmi_edid_manf_year;
155 year = tvb_get_guint8(tvb, offset);
156 yi = proto_tree_add_item(edid_tree, year_hf,
157 tvb, offset, 1, ENC_LITTLE_ENDIAN);
158 proto_item_append_text(yi, " (year %d)", 1990+year);
161 edid_ver = tvb_get_guint8(tvb, offset);
162 edid_rev = tvb_get_guint8(tvb, offset+1);
164 /* XXX make this filterable */
165 proto_tree_add_text(edid_tree, tvb, offset, 2,
166 "EDID Version %d.%d", edid_ver, edid_rev);
168 /* XXX dissect the parts following the EDID header */
170 return tvb_reported_length(tvb);
175 dissect_hdmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
180 proto_tree *hdmi_tree;
182 /* the I2C address in the first byte is always handled by the HDMI
183 dissector, even if the packet contains HDCP data */
184 addr = tvb_get_guint8(tvb, 0);
185 if (!try_val_to_str(addr, hdmi_addr))
186 return 0; /* no HDMI packet */
188 col_set_str(pinfo->cinfo, COL_PROTOCOL, "HDMI");
189 col_clear(pinfo->cinfo, COL_INFO);
191 pi = proto_tree_add_protocol_format(tree, proto_hdmi,
192 tvb, 0, tvb_reported_length(tvb), "HDMI");
193 hdmi_tree = proto_item_add_subtree(pi, ett_hdmi);
196 SET_ADDRESS(&pinfo->src, AT_STRINGZ, (int)strlen(ADDR_RCV)+1, ADDR_RCV);
197 SET_ADDRESS(&pinfo->dst, AT_STRINGZ, (int)strlen(ADDR_TRX)+1, ADDR_TRX);
198 pinfo->p2p_dir = P2P_DIR_RECV;
201 SET_ADDRESS(&pinfo->src, AT_STRINGZ, (int)strlen(ADDR_TRX)+1, ADDR_TRX);
202 SET_ADDRESS(&pinfo->dst, AT_STRINGZ, (int)strlen(ADDR_RCV)+1, ADDR_RCV);
203 pinfo->p2p_dir = P2P_DIR_SENT;
206 /* there's no explicit statement in the spec saying that the protocol is
208 there's three cases: one byte values, symmetrical values or values
209 that are explicitly marked as little endian
210 for the sake of simplicity, we use little endian everywhere */
211 proto_tree_add_item(hdmi_tree, hf_hdmi_addr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
214 if (HDCP_ADDR8(addr)) {
218 hdcp_len = tvb_reported_length_remaining(tvb, offset);
219 hdcp_tvb = tvb_new_subset(tvb, offset, hdcp_len, hdcp_len);
221 return call_dissector(hdcp_handle, hdcp_tvb, pinfo, hdmi_tree);
224 if (addr==ADDR8_EDID_WRITE) {
225 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "EDID request");
226 proto_tree_add_item(hdmi_tree, hf_hdmi_edid_offset,
227 tvb, offset, 1, ENC_LITTLE_ENDIAN);
232 return dissect_hdmi_edid(tvb, offset, pinfo, hdmi_tree);
237 proto_register_hdmi(void)
239 static hf_register_info hf[] = {
241 { "8bit I2C address", "hdmi.addr", FT_UINT8, BASE_HEX,
242 VALS(hdmi_addr), 0, NULL, HFILL } },
243 { &hf_hdmi_edid_offset,
244 { "Offset", "hdmi.edid.offset",
245 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
247 { "EDID header", "hdmi.edid.hdr",
248 FT_UINT64, BASE_HEX, NULL, 0, NULL, HFILL } },
249 { &hf_hdmi_edid_manf_id,
250 { "Manufacturer ID", "hdmi.edid.manf_id",
251 FT_STRING, STR_ASCII, NULL, 0, NULL, HFILL } },
252 { &hf_hdmi_edid_manf_prod_code,
253 { "Manufacturer product code", "hdmi.edid.manf_prod_code",
254 FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
255 { &hf_hdmi_edid_manf_serial,
256 { "Serial number", "hdmi.edid.serial_num",
257 FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
258 { &hf_hdmi_edid_manf_week,
259 { "Week of manufacture", "hdmi.edid.manf_week",
260 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
261 { &hf_hdmi_edid_mod_year,
262 { "Model year", "hdmi.edid.model_year",
263 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
264 { &hf_hdmi_edid_manf_year,
265 { "Year of manufacture", "hdmi.edid.manf_year",
266 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }
269 static gint *ett[] = {
274 proto_hdmi = proto_register_protocol(
275 "High-Definition Multimedia Interface", "HDMI", "hdmi");
277 proto_register_field_array(proto_hdmi, hf, array_length(hf));
278 proto_register_subtree_array(ett, array_length(ett));
280 new_register_dissector("hdmi", dissect_hdmi, proto_hdmi);
285 proto_reg_handoff_hdmi(void)
287 hdcp_handle = find_dissector("hdcp");
291 * Editor modelines - http://www.wireshark.org/tools/modelines.html
296 * indent-tabs-mode: nil
299 * vi: set shiftwidth=4 tabstop=8 expandtab:
300 * :indentSize=4:tabSize=8:noTabs=true: