^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * see flexcop.c for copyright information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include "flexcop.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /*EEPROM (Skystar2 has one "24LC08B" chip on board) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static int eeprom_lrc_write(struct adapter *adapter, u32 addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) u32 len, u8 *wbuf, u8 *rbuf, int retries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) for (i = 0; i < retries; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) if (eeprom_write(adapter, addr, wbuf, len) == len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) /* These functions could be used to unlock SkyStar2 cards. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) u8 rbuf[20];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) u8 wbuf[20];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (len != 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) memcpy(wbuf, key, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) wbuf[16] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) wbuf[17] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) wbuf[18] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) wbuf[19] = calc_lrc(wbuf, 19);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) u8 buf[20];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (len != 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) memcpy(key, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u8 tmp[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (type != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) tmp[0] = mac[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) tmp[1] = mac[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) tmp[2] = mac[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) tmp[3] = mac[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) tmp[4] = mac[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) tmp[5] = mac[7];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) tmp[0] = mac[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) tmp[1] = mac[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) tmp[2] = mac[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) tmp[3] = mac[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) tmp[4] = mac[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) tmp[5] = mac[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) tmp[6] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) tmp[7] = calc_lrc(tmp, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int flexcop_eeprom_read(struct flexcop_device *fc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u16 addr, u8 *buf, u16 len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static u8 calc_lrc(u8 *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u8 sum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) for (i = 0; i < len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) sum = sum ^ buf[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return sum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static int flexcop_eeprom_request(struct flexcop_device *fc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) int i,ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) u8 chipaddr = 0x50 | ((addr >> 8) & 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) for (i = 0; i < retries; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) addr & 0xff, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) u8 *buf, u16 len, int retries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (calc_lrc(buf, len - 1) != buf[len - 1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* JJ's comment about extended == 1: it is not presently used anywhere but was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * added to the low-level functions for possible support of EUI64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) u8 buf[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (extended != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) err("TODO: extended (EUI64) MAC addresses aren't completely supported yet");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) memcpy(fc->dvb_adapter.proposed_mac,buf,6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);