From 673f633d34b1919a1ce4ba57376502a1cf3f0259 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 18 Feb 2024 19:41:59 +0100 Subject: initial commit --- ch340.lua | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100755 ch340.lua (limited to 'ch340.lua') diff --git a/ch340.lua b/ch340.lua new file mode 100755 index 0000000..37adef7 --- /dev/null +++ b/ch340.lua @@ -0,0 +1,118 @@ +local ch340_ctl = Proto("ch340.ctl", "CH340 Serial Control") +local ch340_bulk = Proto("ch340.bulk", "CH340 Serial Data") + +local ep_dir_f = Field.new("usb.endpoint_address.direction") + +local REQ_TBL = { + [0x5F] = "CH341_REQ_READ_VERSION", + [0x9A] = "CH341_REQ_WRITE_REG", + [0x95] = "CH341_REQ_READ_REG", + [0xA1] = "CH341_REQ_SERIAL_INIT", + [0xA4] = "CH341_REQ_MODEM_CTRL", +} + +local REG_TBL = { + [0x07] = "STATUS2", + [0x06] = "STATUS", + [0x13] = "DIVISOR", + [0x12] = "PRESCALER", + [0x18] = "LCR", + [0x25] = "LCR2", +} + +local req_F = ProtoField.uint8("ch340.ctl.req", "Request", base.HEX, REQ_TBL) +local reg1_F = ProtoField.uint8("ch340.ctl.reg1", "Register 1", base.HEX, REG_TBL) +local reg2_F = ProtoField.uint8("ch340.ctl.reg2", "Register 2", base.HEX, REG_TBL) +local val1_F = ProtoField.uint8("ch340.ctl.val1", "Value 1", base.HEX) +local val2_F = ProtoField.uint8("ch340.ctl.val2", "Value 2", base.HEX) +local modem_F = ProtoField.uint8("ch340.ctl.modem", "Modem", base.HEX) + +ch340_ctl.fields = { + req_F, + reg1_F, + val1_F, + reg2_F, + val2_F, + modem_F, +} + +local data_in_F = ProtoField.bytes("ch340.bulk.data_in", "Data In") +local data_out_F = ProtoField.bytes("ch340.bulk.data_out", "Data Out") + +ch340_bulk.fields = { + data_in_F, + data_out_F, +} + +local serial_tbl = DissectorTable.heuristic_new("ch340.serial_data", ch340_bulk) + +function ch340_ctl.dissector(buffer, pinfo, tree) + if buffer:captured_len() < 1 then return end + + local sub = tree:add(ch340_ctl, buffer()) + + local req = buffer(0, 1) + sub:add(req_F, req) + + req = REQ_TBL[req:uint()] + pinfo.cols.info:set("CH340 " .. req:sub(11)) + if req == "CH341_REQ_WRITE_REG" or + req == "CH341_REQ_READ_REG" then + + local reg2 = buffer(1, 1) + local reg1 = buffer(2, 1) + sub:add(reg1_F, reg1) + sub:add(reg2_F, reg2) + + reg1 = reg1:uint() + reg2 = reg2:uint() + + pinfo.cols.info:append(string.format(" %s/%s", (REG_TBL[reg1] or reg1), (REG_TBL[reg2] or reg2))) + + if req == "CH341_REQ_WRITE_REG" then + local val2 = buffer(3, 1) + local val1 = buffer(4, 1) + sub:add(val1_F, val1) + sub:add(val2_F, val2) + end + elseif name == "CH341_REQ_MODEM_CTRL" then + sub:add(modem_F, buffer(1)) + end +end + +function ch340_bulk.dissector(buffer, pinfo, tree) + if buffer:captured_len() < 1 then return end + + local sub = tree:add(ch340_bulk, buffer()) + pinfo.cols.info:set("CH340 Serial") + + local ep_dir = ep_dir_f()() -- 0: h2d, 1: d2h + if ep_dir == 0 then + pinfo.cols.info:append(" out") + pinfo.p2p_dir = P2P_DIR_SENT + sub:add(data_out_F, buffer()) + else + pinfo.cols.info:append(" in") + pinfo.p2p_dir = P2P_DIR_RECV + sub:add(data_in_F, buffer()) + end + + DissectorTable.try_heuristics("ch340.serial_data", buffer, pinfo, tree) +end + +function usb_protocol_key(class, subclass, protocol) + return bit.bor( + bit.lshift(1, 31), + bit.lshift(bit.band(class, 0xff), 16), + bit.lshift(bit.band(subclass, 0xff), 8), + bit.band(protocol, 0xff) + ) +end + +local ctl_table = DissectorTable.get("usb.control") +ctl_table:add(usb_protocol_key(0xff, 0x01, 0x02), ch340_ctl) +ctl_table:add(0xffff, ch340_ctl) + +local bulk_table = DissectorTable.get("usb.bulk") +bulk_table:add(usb_protocol_key(0xff, 0x01, 0x02), ch340_bulk) +bulk_table:add(0xffff, ch340_bulk) -- cgit v1.2.3