1#!/usr/bin/perl 2 3# Copyright (C) 2010 Mauro Carvalho Chehab 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, version 2 of the License. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# This small script parses register dumps generated by cx231xx driver 15# with debug options enabled, generating a source code with the results 16# of the dump. 17# 18# To use it, you may modprobe cx231xx with reg_debug=1, and do: 19# dmesg | ./parse_em28xx.pl 20# 21# Also, there are other utilities that produce similar outputs, and it 22# is not hard to parse some USB analyzers log into the expected format. 23# 24 25use strict; 26 27my %cfg_reg_map = ( 28 0x0 => "BOARD_CFG_STAT", 29 0x4 => "TS_MODE_REG", 30 0x8 => "TS1_CFG_REG", 31 0xc => "TS1_LENGTH_REG", 32 0x10 => "TS2_CFG_REG", 33 0x14 => "TS2_LENGTH_REG", 34 0x18 => "EP_MODE_SET", 35 0x1c => "CIR_PWR_PTN1", 36 0x20 => "CIR_PWR_PTN2", 37 0x24 => "CIR_PWR_PTN3", 38 0x28 => "CIR_PWR_MASK0", 39 0x2c => "CIR_PWR_MASK1", 40 0x30 => "CIR_PWR_MASK2", 41 0x34 => "CIR_GAIN", 42 0x38 => "CIR_CAR_REG", 43 0x40 => "CIR_OT_CFG1", 44 0x44 => "CIR_OT_CFG2", 45 0x68 => "GBULK_BIT_EN", 46 0x74 => "PWR_CTL_EN", 47); 48 49sub parse_i2c($$$$$$) 50{ 51 my $reqtype = shift; 52 my $req = shift; 53 my $wvalue = shift; 54 my $windex = shift; 55 my $wlen = shift; 56 my $payload = shift; 57 58 my $daddr = $wvalue >> 9; 59 my $reserved = ($wvalue >>6 ) & 0x07; 60 my $period = ($wvalue >> 4) & 0x03; 61 my $addr_len = ($wvalue >> 2) & 0x03; 62 my $nostop = ($wvalue >>1) & 0x01; 63 my $sync = $wvalue & 0x01; 64 65 if ($nostop) { 66 $nostop="nostop "; 67 } else { 68 $nostop=""; 69 } 70 if ($sync) { 71 $sync="sync "; 72 } else { 73 $sync=""; 74 } 75 my $type; 76 my $i2c_channel; 77 if ($reqtype > 128) { 78 $type = "IN "; 79 $i2c_channel = $req - 4; 80 } else { 81 $type = "OUT"; 82 $i2c_channel = $req; 83 } 84 if ($period == 0) { 85 $period = "1Mbps"; 86 } elsif ($period == 1) { 87 $period = "400kbps"; 88 } elsif ($period == 2) { 89 $period = "100kbps"; 90 } else { 91 $period = "???kbps"; 92 } 93 printf("$type i2c channel#%d daddr 0x%02x %s addr_len %d %s%slen %d = ", 94 $i2c_channel, $daddr, $period, $addr_len, $nostop, $sync, 95 $wlen); 96 if ($addr_len == 1) { 97 printf("(saddr)%02x ", $windex & 0xff); 98 } elsif ($addr_len == 2) { 99 printf("(saddr)%04x ", $windex); 100 } 101 printf("$payload\n"); 102} 103 104sub parse_gpio($$$$$$) 105{ 106 my $reqtype = shift; 107 my $req = shift; 108 my $wvalue = shift; 109 my $windex = shift; 110 my $wlen = shift; 111 my $payload = shift; 112 113 my $type; 114 if ($req == 8) { 115 $type .= "SET gpio"; 116 } elsif ($req == 9) { 117 $type .= "GET gpio"; 118 } elsif ($req == 0xa) { 119 $type .= "SET gpie"; 120 } elsif ($req == 0xb) { 121 $type .= "GET gpie"; 122 } 123 124 my $gpio_bit = ($wvalue << 16) | $windex; 125 126 $payload =~ s/([a-f\d].)\s([a-f\d].)\s([a-f\d].)\s([a-f\d].)/0x$4$3$2$1/; 127 128 printf("$type: Reqtype %3d Req %3d len %d wvalue 0x%04x windex 0x%02x => direction=0x%04x val = %s\n", 129 $reqtype, $req, $wlen, $wvalue, $windex, $gpio_bit, $payload); 130} 131 132while (<>) { 133 tr/A-F/a-f/; 134 if (m/([4c]0) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].)[\<\>\s]+(.*)/) { 135 my $reqtype = hex($1); 136 my $req = hex($2); 137 my $wvalue = hex("$4$3"); 138 my $windex = hex("$6$5"); 139 my $wlen = hex("$8$7"); 140 my $payload = $9; 141 142 if ($reqtype > 128 && (($req >= 4) && ($req <= 6))) { 143 parse_i2c($reqtype, $req, $wvalue, $windex, $wlen, $payload); 144 } elsif ($req < 3) { 145 parse_i2c($reqtype, $req, $wvalue, $windex, $wlen, $payload); 146 } elsif ($req >= 8 && $req <= 0xb) { 147 parse_gpio($reqtype, $req, $wvalue, $windex, $wlen, $payload); 148 } elsif ($req == 0xc) { 149 my $cfg_len; 150 if ($wvalue == 1) { 151 $cfg_len = 1; 152 } elsif($wvalue == 3) { 153 $cfg_len = 2; 154 } elsif($wvalue == 7) { 155 $cfg_len = 3; 156 } elsif($wvalue == 0xf) { 157 $cfg_len = 4; 158 } else { 159 printf("Invalid get len for "); 160 printf("Reqtype: %3d, Req %3d, wValue: 0x%04x, wIndex 0x%04x, wlen %d: %s\n", 161 $reqtype, $req, $wvalue, $windex, $wlen, $payload); 162 } 163 164 if ($cfg_len) { 165 my $reg = $windex; 166 $reg = $cfg_reg_map{$windex} if defined($cfg_reg_map{$windex}); 167 168 printf "cx231xx_write_ctrl_reg(dev, $reg, $payload, $cfg_len);\n"; 169 } 170 } elsif ($req == 0xd) { 171 my $cfg_len; 172 if ($wvalue == 1) { 173 $cfg_len = 1; 174 } elsif($wvalue == 3) { 175 $cfg_len = 2; 176 } elsif($wvalue == 7) { 177 $cfg_len = 3; 178 } elsif($wvalue == 0xf) { 179 $cfg_len = 4; 180 } else { 181 printf("Invalid get len for "); 182 printf("Reqtype: %3d, Req %3d, wValue: 0x%04x, wIndex 0x%04x, wlen %d: %s\n", 183 $reqtype, $req, $wvalue, $windex, $wlen, $payload); 184 } 185 if ($cfg_len) { 186 my $reg = $windex; 187 $reg = $cfg_reg_map{$windex} if defined($cfg_reg_map{$windex}); 188 189 printf "cx231xx_read_ctrl_reg(dev, $reg, $cfg_len);\t\t/* read %s */\n", 190 $payload; 191 } 192 } else { 193 printf("Reqtype: %3d, Req %3d, wValue: 0x%04x, wIndex 0x%04x, wlen %d: %s\n", 194 $reqtype, $req, $wvalue, $windex, $wlen, $payload); 195 } 196 } 197} 198