1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM, |
4 | decode it and store it in the associated adapter struct for |
5 | use by dvb_net.c |
6 | |
7 | This card appear to have the 24C16 write protect held to ground, |
8 | thus permitting normal read/write operation. Theoretically it |
9 | would be possible to write routines to burn a different (encoded) |
10 | MAC address into the EEPROM. |
11 | |
12 | Robert Schlabbach GMX |
13 | Michael Glaum KVH Industries |
14 | Holger Waechtler Convergence |
15 | |
16 | Copyright (C) 2002-2003 Ralph Metzler <rjkm@metzlerbros.de> |
17 | Metzler Brothers Systementwicklung GbR |
18 | |
19 | |
20 | */ |
21 | |
22 | #include <asm/errno.h> |
23 | #include <linux/init.h> |
24 | #include <linux/module.h> |
25 | #include <linux/string.h> |
26 | #include <linux/i2c.h> |
27 | #include <linux/etherdevice.h> |
28 | |
29 | #include "ttpci-eeprom.h" |
30 | |
31 | #if 1 |
32 | #define dprintk(x...) do { printk(x); } while (0) |
33 | #else |
34 | #define dprintk(x...) do { } while (0) |
35 | #endif |
36 | |
37 | |
38 | static int check_mac_tt(u8 *buf) |
39 | { |
40 | int i; |
41 | u16 tmp = 0xffff; |
42 | |
43 | for (i = 0; i < 8; i++) { |
44 | tmp = (tmp << 8) | ((tmp >> 8) ^ buf[i]); |
45 | tmp ^= (tmp >> 4) & 0x0f; |
46 | tmp ^= (tmp << 12) ^ ((tmp & 0xff) << 5); |
47 | } |
48 | tmp ^= 0xffff; |
49 | return (((tmp >> 8) ^ buf[8]) | ((tmp & 0xff) ^ buf[9])); |
50 | } |
51 | |
52 | static int getmac_tt(u8 * decodedMAC, u8 * encodedMAC) |
53 | { |
54 | u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, |
55 | 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, |
56 | 0x1d, 0x36, 0x64, 0x78}; |
57 | u8 data[20]; |
58 | int i; |
59 | |
60 | /* In case there is a sig check failure have the orig contents available */ |
61 | memcpy(data, encodedMAC, 20); |
62 | |
63 | for (i = 0; i < 20; i++) |
64 | data[i] ^= xor[i]; |
65 | for (i = 0; i < 10; i++) |
66 | data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) |
67 | >> ((data[2 * i + 1] >> 6) & 3); |
68 | |
69 | if (check_mac_tt(buf: data)) |
70 | return -ENODEV; |
71 | |
72 | decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0]; |
73 | decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4]; |
74 | return 0; |
75 | } |
76 | |
77 | int ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC) |
78 | { |
79 | u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, |
80 | 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, |
81 | 0x1d, 0x36, 0x64, 0x78}; |
82 | u8 data[20]; |
83 | int i; |
84 | |
85 | memcpy(data, encodedMAC, 20); |
86 | |
87 | for (i = 0; i < 20; i++) |
88 | data[i] ^= xor[i]; |
89 | for (i = 0; i < 10; i++) |
90 | data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) |
91 | >> ((data[2 * i + 1] >> 6) & 3); |
92 | |
93 | if (check_mac_tt(buf: data)) |
94 | return -ENODEV; |
95 | |
96 | decodedMAC[0] = data[2]; |
97 | decodedMAC[1] = data[1]; |
98 | decodedMAC[2] = data[0]; |
99 | decodedMAC[3] = data[6]; |
100 | decodedMAC[4] = data[5]; |
101 | decodedMAC[5] = data[4]; |
102 | return 0; |
103 | } |
104 | EXPORT_SYMBOL(ttpci_eeprom_decode_mac); |
105 | |
106 | static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC) |
107 | { |
108 | int ret; |
109 | u8 b0[] = { 0xcc }; |
110 | |
111 | struct i2c_msg msg[] = { |
112 | { .addr = 0x50, .flags = 0, .buf = b0, .len = 1 }, |
113 | { .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 } |
114 | }; |
115 | |
116 | /* dprintk("%s\n", __func__); */ |
117 | |
118 | ret = i2c_transfer(adap: adapter, msgs: msg, num: 2); |
119 | |
120 | if (ret != 2) /* Assume EEPROM isn't there */ |
121 | return (-ENODEV); |
122 | |
123 | return 0; |
124 | } |
125 | |
126 | |
127 | int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) |
128 | { |
129 | int ret; |
130 | u8 encodedMAC[20]; |
131 | u8 decodedMAC[6]; |
132 | |
133 | ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC); |
134 | |
135 | if (ret != 0) { /* Will only be -ENODEV */ |
136 | dprintk("Couldn't read from EEPROM: not there?\n" ); |
137 | eth_zero_addr(addr: proposed_mac); |
138 | return ret; |
139 | } |
140 | |
141 | ret = getmac_tt(decodedMAC, encodedMAC); |
142 | if( ret != 0 ) { |
143 | dprintk("adapter failed MAC signature check\n" ); |
144 | dprintk("encoded MAC from EEPROM was %*phC" , |
145 | (int)sizeof(encodedMAC), &encodedMAC); |
146 | eth_zero_addr(addr: proposed_mac); |
147 | return ret; |
148 | } |
149 | |
150 | memcpy(proposed_mac, decodedMAC, 6); |
151 | dprintk("adapter has MAC addr = %pM\n" , decodedMAC); |
152 | return 0; |
153 | } |
154 | |
155 | EXPORT_SYMBOL(ttpci_eeprom_parse_mac); |
156 | |
157 | MODULE_LICENSE("GPL" ); |
158 | MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others" ); |
159 | MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards made by Siemens, Technotrend, Hauppauge" ); |
160 | |