18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Retrieve encoded MAC address from 24C16 serial 2-wire EEPROM, 48c2ecf20Sopenharmony_ci decode it and store it in the associated adapter struct for 58c2ecf20Sopenharmony_ci use by dvb_net.c 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci This card appear to have the 24C16 write protect held to ground, 88c2ecf20Sopenharmony_ci thus permitting normal read/write operation. Theoretically it 98c2ecf20Sopenharmony_ci would be possible to write routines to burn a different (encoded) 108c2ecf20Sopenharmony_ci MAC address into the EEPROM. 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci Robert Schlabbach GMX 138c2ecf20Sopenharmony_ci Michael Glaum KVH Industries 148c2ecf20Sopenharmony_ci Holger Waechtler Convergence 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci Copyright (C) 2002-2003 Ralph Metzler <rjkm@metzlerbros.de> 178c2ecf20Sopenharmony_ci Metzler Brothers Systementwicklung GbR 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci*/ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/errno.h> 238c2ecf20Sopenharmony_ci#include <linux/init.h> 248c2ecf20Sopenharmony_ci#include <linux/module.h> 258c2ecf20Sopenharmony_ci#include <linux/string.h> 268c2ecf20Sopenharmony_ci#include <linux/i2c.h> 278c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "ttpci-eeprom.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#if 1 328c2ecf20Sopenharmony_ci#define dprintk(x...) do { printk(x); } while (0) 338c2ecf20Sopenharmony_ci#else 348c2ecf20Sopenharmony_ci#define dprintk(x...) do { } while (0) 358c2ecf20Sopenharmony_ci#endif 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int check_mac_tt(u8 *buf) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int i; 418c2ecf20Sopenharmony_ci u16 tmp = 0xffff; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 448c2ecf20Sopenharmony_ci tmp = (tmp << 8) | ((tmp >> 8) ^ buf[i]); 458c2ecf20Sopenharmony_ci tmp ^= (tmp >> 4) & 0x0f; 468c2ecf20Sopenharmony_ci tmp ^= (tmp << 12) ^ ((tmp & 0xff) << 5); 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci tmp ^= 0xffff; 498c2ecf20Sopenharmony_ci return (((tmp >> 8) ^ buf[8]) | ((tmp & 0xff) ^ buf[9])); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int getmac_tt(u8 * decodedMAC, u8 * encodedMAC) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, 558c2ecf20Sopenharmony_ci 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, 568c2ecf20Sopenharmony_ci 0x1d, 0x36, 0x64, 0x78}; 578c2ecf20Sopenharmony_ci u8 data[20]; 588c2ecf20Sopenharmony_ci int i; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* In case there is a sig check failure have the orig contents available */ 618c2ecf20Sopenharmony_ci memcpy(data, encodedMAC, 20); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci for (i = 0; i < 20; i++) 648c2ecf20Sopenharmony_ci data[i] ^= xor[i]; 658c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) 668c2ecf20Sopenharmony_ci data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) 678c2ecf20Sopenharmony_ci >> ((data[2 * i + 1] >> 6) & 3); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (check_mac_tt(data)) 708c2ecf20Sopenharmony_ci return -ENODEV; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci decodedMAC[0] = data[2]; decodedMAC[1] = data[1]; decodedMAC[2] = data[0]; 738c2ecf20Sopenharmony_ci decodedMAC[3] = data[6]; decodedMAC[4] = data[5]; decodedMAC[5] = data[4]; 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciint ttpci_eeprom_decode_mac(u8 *decodedMAC, u8 *encodedMAC) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci u8 xor[20] = { 0x72, 0x23, 0x68, 0x19, 0x5c, 0xa8, 0x71, 0x2c, 808c2ecf20Sopenharmony_ci 0x54, 0xd3, 0x7b, 0xf1, 0x9E, 0x23, 0x16, 0xf6, 818c2ecf20Sopenharmony_ci 0x1d, 0x36, 0x64, 0x78}; 828c2ecf20Sopenharmony_ci u8 data[20]; 838c2ecf20Sopenharmony_ci int i; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci memcpy(data, encodedMAC, 20); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (i = 0; i < 20; i++) 888c2ecf20Sopenharmony_ci data[i] ^= xor[i]; 898c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) 908c2ecf20Sopenharmony_ci data[i] = ((data[2 * i + 1] << 8) | data[2 * i]) 918c2ecf20Sopenharmony_ci >> ((data[2 * i + 1] >> 6) & 3); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (check_mac_tt(data)) 948c2ecf20Sopenharmony_ci return -ENODEV; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci decodedMAC[0] = data[2]; 978c2ecf20Sopenharmony_ci decodedMAC[1] = data[1]; 988c2ecf20Sopenharmony_ci decodedMAC[2] = data[0]; 998c2ecf20Sopenharmony_ci decodedMAC[3] = data[6]; 1008c2ecf20Sopenharmony_ci decodedMAC[4] = data[5]; 1018c2ecf20Sopenharmony_ci decodedMAC[5] = data[4]; 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ttpci_eeprom_decode_mac); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encodedMAC) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci u8 b0[] = { 0xcc }; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 1128c2ecf20Sopenharmony_ci { .addr = 0x50, .flags = 0, .buf = b0, .len = 1 }, 1138c2ecf20Sopenharmony_ci { .addr = 0x50, .flags = I2C_M_RD, .buf = encodedMAC, .len = 20 } 1148c2ecf20Sopenharmony_ci }; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* dprintk("%s\n", __func__); */ 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ret = i2c_transfer(adapter, msg, 2); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (ret != 2) /* Assume EEPROM isn't there */ 1218c2ecf20Sopenharmony_ci return (-ENODEV); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciint ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci int ret; 1308c2ecf20Sopenharmony_ci u8 encodedMAC[20]; 1318c2ecf20Sopenharmony_ci u8 decodedMAC[6]; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ret = ttpci_eeprom_read_encodedMAC(adapter, encodedMAC); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (ret != 0) { /* Will only be -ENODEV */ 1368c2ecf20Sopenharmony_ci dprintk("Couldn't read from EEPROM: not there?\n"); 1378c2ecf20Sopenharmony_ci eth_zero_addr(proposed_mac); 1388c2ecf20Sopenharmony_ci return ret; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ret = getmac_tt(decodedMAC, encodedMAC); 1428c2ecf20Sopenharmony_ci if( ret != 0 ) { 1438c2ecf20Sopenharmony_ci dprintk("adapter failed MAC signature check\n"); 1448c2ecf20Sopenharmony_ci dprintk("encoded MAC from EEPROM was %*phC", 1458c2ecf20Sopenharmony_ci (int)sizeof(encodedMAC), &encodedMAC); 1468c2ecf20Sopenharmony_ci eth_zero_addr(proposed_mac); 1478c2ecf20Sopenharmony_ci return ret; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci memcpy(proposed_mac, decodedMAC, 6); 1518c2ecf20Sopenharmony_ci dprintk("adapter has MAC addr = %pM\n", decodedMAC); 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ttpci_eeprom_parse_mac); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); 1598c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards made by Siemens, Technotrend, Hauppauge"); 160