Squashed backup commit (no shallow-clone history issues) of xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream commit 9eece662e) plus all fixes applied to get everpal_defconfig building clean against a modern (GCC 15.2.0) toolchain -- see the previous commit message on the lineage-23.2 branch (also in this repo history is not available here since this is a squashed snapshot; full incremental history lives in the local DL380 checkout and the upstream GitHub remote). Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
1995 lines
58 KiB
C
1995 lines
58 KiB
C
/*******************************************************************************
|
|
* Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved.
|
|
*
|
|
*******************************************************************************
|
|
*
|
|
* DS28E16.c - DS28E16 device module. Requires low level 1-Wire connection.
|
|
*/
|
|
#define pr_fmt(fmt) "[ds28e16] %s: " fmt, __func__
|
|
|
|
#include <linux/slab.h> /* kfree() */
|
|
#include <linux/module.h>
|
|
#include <linux/err.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/string.h>
|
|
#include "sha384_software.h"
|
|
#include "ds28e16.h"
|
|
#include "onewire_gpio.h"
|
|
|
|
#include <linux/param.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/power_supply.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/gpio/consumer.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/random.h>
|
|
#include <linux/sched.h>
|
|
|
|
#define ds_info pr_info
|
|
#define ds_dbg pr_debug
|
|
#define ds_err pr_err
|
|
#define ds_log pr_err
|
|
|
|
struct ds28e16_data {
|
|
struct platform_device *pdev;
|
|
struct device *dev;
|
|
|
|
int version;
|
|
int cycle_count;
|
|
bool batt_verified;
|
|
|
|
struct power_supply *verify_psy;
|
|
struct power_supply_desc verify_psy_d;
|
|
|
|
struct delayed_work battery_verify_work;
|
|
//struct delayed_work authentic_work;
|
|
};
|
|
|
|
unsigned int attr_trytimes = 1;
|
|
|
|
unsigned char session_seed[32] = {
|
|
0x31, 0x42, 0x4E, 0x35, 0x43, 0x4B, 0x31, 0x41,
|
|
0x31, 0x30, 0x3C, 0x25, 0x2D, 0x3C, 0x28, 0x00,
|
|
0x46, 0x35, 0x39, 0x1C, 0x1E, 0x4D, 0x01, 0x4C,
|
|
0x51, 0x46, 0x04, 0x29, 0x56, 0x4F, 0x25, 0x60
|
|
};
|
|
|
|
unsigned char S_secret[32] = {
|
|
0xDF, 0xDD, 0xC1, 0x87, 0x18, 0xAE, 0xC7, 0xD8,
|
|
0x04, 0xB5, 0xE4, 0x30, 0x27, 0xE3, 0x99, 0x95,
|
|
0x07, 0x3D, 0x1D, 0x13, 0xC8, 0x16, 0x69, 0xBC,
|
|
0x94, 0xE0, 0x04, 0xD0, 0xF4, 0x73, 0xE5, 0x86
|
|
};
|
|
|
|
unsigned char challenge[32] = {0x00};
|
|
int auth_ANON = 1;
|
|
int auth_BDCONST = 1;
|
|
int pagenumber = 0;
|
|
|
|
// maxim define
|
|
int tm = 1;
|
|
unsigned short CRC16;
|
|
const short oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
|
|
unsigned char last_result_byte = RESULT_SUCCESS;
|
|
|
|
unsigned char MANID[2] = {0x00};
|
|
|
|
// mi add
|
|
unsigned char flag_mi_romid = 0;
|
|
unsigned char flag_mi_status = 0;
|
|
unsigned char flag_mi_page0_data = 0;
|
|
unsigned char flag_mi_page1_data = 0;
|
|
unsigned char flag_mi_counter = 0;
|
|
unsigned char flag_mi_auth_result = 0;
|
|
unsigned char mi_romid[8] = {0x00};
|
|
unsigned char mi_status[8] = {0x00};
|
|
unsigned char mi_page0_data[16] = {0x00};
|
|
unsigned char mi_page1_data[16] = {0x00};
|
|
unsigned char mi_counter[16] = {0x00};
|
|
int mi_auth_result = 0x00;
|
|
|
|
static bool flag_battery_verify_process = false;
|
|
|
|
static void set_sched_affinity_to_current(void)
|
|
{
|
|
long ret;
|
|
int current_cpu;
|
|
|
|
preempt_disable();
|
|
current_cpu = smp_processor_id();
|
|
ret = sched_setaffinity(CURRENT_DS28E16_TASK, cpumask_of(current_cpu));
|
|
preempt_enable();
|
|
if(ret) {
|
|
pr_info("Setting cpu affinity to current cpu failed(%ld) in %s.\n", ret, __func__);
|
|
} else {
|
|
pr_info("Setting cpu affinity to current cpu(%d) in %s.\n", current_cpu, __func__);
|
|
}
|
|
}
|
|
|
|
static void set_sched_affinity_to_all(void)
|
|
{
|
|
long ret;
|
|
cpumask_t dstp;
|
|
|
|
cpumask_setall(&dstp);
|
|
ret = sched_setaffinity(CURRENT_DS28E16_TASK, &dstp);
|
|
if(ret) {
|
|
pr_info("Setting cpu affinity to all valid cpus failed(%ld) in %s.\n", ret, __func__);
|
|
} else {
|
|
pr_info("Setting cpu affinity to all valid cpus in %s.\n", __func__);
|
|
}
|
|
}
|
|
|
|
unsigned char crc_low_first(unsigned char *ptr, unsigned char len)
|
|
{
|
|
unsigned char i;
|
|
unsigned char crc = 0x00;
|
|
|
|
while (len--) {
|
|
crc ^= *ptr++;
|
|
for (i = 0; i < 8; ++i) {
|
|
if (crc & 0x01)
|
|
crc = (crc >> 1) ^ 0x8c;
|
|
else
|
|
crc = (crc >> 1);
|
|
}
|
|
}
|
|
|
|
return (crc);
|
|
}
|
|
|
|
short Read_RomID(unsigned char *RomID)
|
|
{
|
|
unsigned char i;
|
|
unsigned char crc = 0x00;
|
|
|
|
ds_info("flag_mi_status = %02x, flag_mi_romid = %02x\n",
|
|
flag_mi_status, flag_mi_romid);
|
|
if (flag_mi_romid == 2) {
|
|
memcpy(RomID, mi_romid, 8);
|
|
return DS_TRUE;
|
|
}
|
|
|
|
if ((ow_reset()) != 0) {
|
|
ds_err("Failed to reset ds28e16!\n");
|
|
ow_reset();
|
|
return ERROR_NO_DEVICE;
|
|
}
|
|
|
|
ds_dbg("Ready to write 0x33 to maxim IC!\n");
|
|
write_byte(CMD_READ_ROM);
|
|
Delay_us(10);
|
|
for (i = 0; i < 8; i++)
|
|
RomID[i] = read_byte();
|
|
|
|
ds_info("RomID = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
RomID[0], RomID[1], RomID[2], RomID[3],
|
|
RomID[4], RomID[5], RomID[6], RomID[7]);
|
|
|
|
crc = crc_low_first(RomID, 7);
|
|
ds_info("crc_low_first = %02x\n", crc);
|
|
|
|
if (crc == RomID[7]) {
|
|
#if 0
|
|
if (flag_mi_status == 0)
|
|
flag_mi_romid = 1;
|
|
else
|
|
flag_mi_romid = 2;
|
|
#endif
|
|
memcpy(mi_romid, RomID, 8);
|
|
if ((mi_romid[0] == FAMILY_CODE) && (mi_romid[6] == CUSTOM_ID_MSB) && ((mi_romid[5] & 0xf0) == CUSTOM_ID_LSB))
|
|
flag_mi_romid = 2;
|
|
else
|
|
flag_mi_romid = 1;
|
|
return DS_TRUE;
|
|
} else {
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
}
|
|
|
|
unsigned short docrc16(unsigned short data)
|
|
{
|
|
data = (data ^ (CRC16 & 0xff)) & 0xff;
|
|
CRC16 >>= 8;
|
|
|
|
if (oddparity[data & 0xf] ^ oddparity[data >> 4])
|
|
CRC16 ^= 0xc001;
|
|
|
|
data <<= 6;
|
|
CRC16 ^= data;
|
|
data <<= 1;
|
|
CRC16 ^= data;
|
|
|
|
return CRC16;
|
|
}
|
|
|
|
int DS28E16_standard_cmd_flow(unsigned char *write_buf, int delay_ms,
|
|
unsigned char *read_buf, int *read_len, int write_len)
|
|
{
|
|
unsigned char buf[128];
|
|
int i;
|
|
int buf_len = 0;
|
|
int expected_read_len = *read_len;
|
|
|
|
//NEW FLOW
|
|
/*'1 Wire
|
|
'''''''''''''''''''''''
|
|
?<Reset/Presence>
|
|
?<ROM level command Sequence>
|
|
?TX: Start Command
|
|
?TX: Length Byte
|
|
?TX: Memory Command
|
|
?TX: Parameter, TX: Data
|
|
?RX: CRC16
|
|
?TX: Release Byte
|
|
?<Strong pull-up Delay>
|
|
?RX: Dummy Byte
|
|
?RX: Length Byte
|
|
?RX: Result byte
|
|
?RX: CRC16
|
|
?< wait for reset>
|
|
'''''''''''''''''''''''*/
|
|
ds_dbg("DS28E16_standard_cmd_flow start\n");
|
|
|
|
if ((ow_reset()) != 0) {
|
|
ds_err("Failed to reset ds28e16!\n");
|
|
ow_reset();
|
|
return ERROR_NO_DEVICE;
|
|
}
|
|
|
|
write_byte(CMD_SKIP_ROM);
|
|
|
|
buf[buf_len++] = CMD_START;
|
|
memcpy(&buf[buf_len], write_buf, write_len);
|
|
buf_len += write_len;
|
|
for (i = 0; i < buf_len; i++)
|
|
write_byte(buf[i]);
|
|
|
|
buf[buf_len++] = read_byte();
|
|
buf[buf_len++] = read_byte();
|
|
|
|
CRC16 = 0;
|
|
for (i = 0; i < buf_len; i++)
|
|
docrc16(buf[i]);
|
|
|
|
if (CRC16 != 0xB001) {
|
|
ow_reset();
|
|
ds_err("DS28E16_standard_cmd_flow: crc error!\n");
|
|
return DS_FALSE;
|
|
}
|
|
|
|
// check for strong pull-up
|
|
if (delay_ms > 0) {
|
|
write_byte(CMD_RELEASE_BYTE);
|
|
Delay_us(1000*delay_ms);
|
|
}
|
|
|
|
read_byte();
|
|
*read_len = read_byte();
|
|
|
|
if (expected_read_len != *read_len) {
|
|
ow_reset();
|
|
ds_err("DS28E16_standard_cmd_flow: len error!\n");
|
|
return DS_FALSE;
|
|
}
|
|
|
|
buf_len = *read_len + 2;
|
|
for (i = 0; i < buf_len; i++)
|
|
buf[i] = read_byte();
|
|
|
|
CRC16 = 0;
|
|
docrc16(*read_len);
|
|
for (i = 0; i < buf_len; i++)
|
|
docrc16(buf[i]);
|
|
|
|
if (CRC16 != 0xB001) {
|
|
ow_reset();
|
|
ds_err("DS28E16_standard_cmd_flow: crc2 error!\n");
|
|
return DS_FALSE;
|
|
}
|
|
|
|
memcpy(read_buf, buf, *read_len);
|
|
ds_info("DS28E16_standard_cmd_flow success!\n");
|
|
return DS_TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
/// 'Read Status' command
|
|
///
|
|
/// @param[out] data
|
|
/// pointer to unsigned char (buffer of length 1) for page protection data
|
|
///
|
|
/// @return
|
|
/// DS_TRUE - command successful @n
|
|
/// DS_FALSE - command failed
|
|
///
|
|
int DS28E16_cmd_readStatus(unsigned char *data)
|
|
{
|
|
unsigned char write_buf[255];
|
|
unsigned char read_buf[255];
|
|
int write_len = 0;
|
|
int len_byte = 1;
|
|
int read_len = 7;
|
|
|
|
if (flag_mi_status) {
|
|
memcpy(data, mi_status, 8);
|
|
return DS_TRUE;
|
|
}
|
|
|
|
last_result_byte = RESULT_FAIL_NONE;
|
|
/*
|
|
?<Start, device address write>
|
|
?TX: Read Page Protection command
|
|
?TX: Length (SMBus) [always 1]
|
|
?TX: Parameter
|
|
?<Stop>
|
|
?<Delay>
|
|
?<Start, device address read>
|
|
?RX: Length (SMBus) [always 1]
|
|
?RX: Protection Data
|
|
?<Stop>
|
|
*/
|
|
|
|
write_buf[write_len++] = len_byte;
|
|
write_buf[write_len++] = CMD_READ_STATUS;
|
|
|
|
if (DS28E16_standard_cmd_flow(write_buf, DELAY_DS28E16_EE_READ*tm,
|
|
read_buf, &read_len, write_len)) {
|
|
if (read_buf[0] == RESULT_SUCCESS) {
|
|
last_result_byte = read_buf[0];
|
|
memcpy(data, &read_buf[1], 8);
|
|
flag_mi_status = 1;
|
|
memcpy(mi_status, data, 8);
|
|
MANID[0] = data[4];
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
/// 'Read Memory' command
|
|
///
|
|
/// @param[in] pg
|
|
/// page number to read
|
|
/// @param[out] data
|
|
/// buffer length must be at least 32 bytes to hold memory read
|
|
///
|
|
/// @return
|
|
/// DS_TRUE - command successful @n
|
|
/// DS_FALSE - command failed
|
|
///
|
|
int DS28E16_cmd_readMemory(int pg, unsigned char *data)
|
|
{
|
|
unsigned char write_buf[3];
|
|
unsigned char read_buf[255];
|
|
int write_len = 0;
|
|
int read_len = 33;
|
|
int length_byte = 2;
|
|
unsigned char pagenum = (unsigned char)pg & 0x03;
|
|
|
|
switch (pagenum)
|
|
{
|
|
case 0x00:
|
|
if (flag_mi_page0_data) {
|
|
memcpy(data, mi_page0_data, 16);
|
|
return DS_TRUE;
|
|
}
|
|
break;
|
|
/*
|
|
case 0x01:
|
|
if (flag_mi_page1_data) {
|
|
memcpy(data, mi_page1_data, 16);
|
|
return DS_TRUE;
|
|
}
|
|
break;
|
|
case 0x02:
|
|
if (flag_mi_counter) {
|
|
memcpy(data, mi_counter, 16);
|
|
return DS_TRUE;
|
|
}
|
|
break;
|
|
*/
|
|
default:
|
|
break;
|
|
}
|
|
|
|
last_result_byte = RESULT_FAIL_NONE;
|
|
|
|
/*
|
|
?<Start, device address write>
|
|
?TX: Read Memory Command
|
|
?TX: Length (SMBus)
|
|
?TX: Parameter
|
|
?<Stop>
|
|
?<Delay>
|
|
?<Start, device address read>
|
|
?RX: Length (SMBus)
|
|
?RX: Result byte
|
|
?RX: Data
|
|
?<Stop>
|
|
*/
|
|
|
|
if (pg >= MAX_PAGENUM) {
|
|
ds_err("page(%d) data should not be set.\n", pg);
|
|
return DS_FALSE;
|
|
}
|
|
|
|
write_buf[write_len++] = length_byte;
|
|
write_buf[write_len++] = CMD_READ_MEM;
|
|
write_buf[write_len++] = pagenum;
|
|
|
|
ds_info("DS28E16_cmd_readMemory write_buf:\n");
|
|
ds_info("%02x %02x %02x", write_buf[0], write_buf[1], write_buf[2]);
|
|
|
|
if (DS28E16_standard_cmd_flow(write_buf, DELAY_DS28E16_EE_READ*tm,
|
|
read_buf, &read_len, write_len)) {
|
|
if (read_len == 33) {
|
|
last_result_byte = read_buf[0];
|
|
if (read_buf[0] == RESULT_SUCCESS) {
|
|
memcpy(data, &read_buf[1], 16);
|
|
if (pagenum == 0x00) {
|
|
flag_mi_page0_data = 1;
|
|
memcpy(mi_page0_data, data, 16);
|
|
}
|
|
/*
|
|
if (pagenum == 0x01) {
|
|
flag_mi_page1_data = 1;
|
|
memcpy(mi_page1_data, data, 16);
|
|
}
|
|
*/
|
|
return DS_TRUE;
|
|
} else {
|
|
if (read_buf[0] == 0x55 && pagenum == 2) {
|
|
memcpy(data, &read_buf[1], 16);
|
|
/*
|
|
flag_mi_counter = 1;
|
|
memcpy(mi_counter, data, 16);
|
|
*/
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
/// 'Write Memory' command
|
|
///
|
|
/// @param[in] pg
|
|
/// page number to write
|
|
/// @param[in] data
|
|
/// buffer must be at least 32 bytes
|
|
///
|
|
/// @return
|
|
/// DS_TRUE - command successful @n
|
|
/// DS_FALSE - command failed
|
|
///
|
|
int DS28E16_cmd_writeMemory(int pg, unsigned char *data)
|
|
{
|
|
unsigned char write_buf[255];
|
|
unsigned char read_buf[255];
|
|
int write_len = 0;
|
|
int read_len = 1;
|
|
int len_byte = 18;
|
|
unsigned char pagenum = (unsigned char)pg & 0x03;
|
|
|
|
last_result_byte = RESULT_FAIL_NONE;
|
|
|
|
if (pg > MAX_PAGENUM) {
|
|
ds_err("page(%d) data should not be set.\n", pg);
|
|
return DS_FALSE;
|
|
}
|
|
/*
|
|
?<Start, device address write>
|
|
?TX: Write Memory Command
|
|
?TX: Length (SMBus) [always 33]
|
|
?TX: Parameter
|
|
?TX: Data
|
|
?<Stop>
|
|
?<Delay>
|
|
?<Start, device address read>
|
|
?RX: Length (SMBus) [always 1]
|
|
?RX: Result byte
|
|
?<Stop>
|
|
*/
|
|
|
|
write_buf[write_len++] = len_byte;
|
|
write_buf[write_len++] = CMD_WRITE_MEM;
|
|
write_buf[write_len++] = pagenum;
|
|
memcpy(&write_buf[write_len], data, 16);
|
|
write_len += 16;
|
|
|
|
if (DS28E16_standard_cmd_flow(write_buf, DELAY_DS28E16_EE_WRITE*tm,
|
|
read_buf, &read_len, write_len)) {
|
|
if (read_len == 1) {
|
|
last_result_byte = read_buf[0];
|
|
if (read_buf[0] == RESULT_SUCCESS){
|
|
/*
|
|
if (pagenum == 0x00) {
|
|
flag_mi_page0_data = 0;
|
|
memset(mi_page0_data, 0x00, 16);
|
|
}
|
|
if (pagenum == 0x01) {
|
|
flag_mi_page1_data = 0;
|
|
memset(mi_page1_data, 0x00, 16);
|
|
}
|
|
if (pagenum == 0x02) {
|
|
flag_mi_counter = 0;
|
|
memset(mi_counter, 0x00, 16);
|
|
}
|
|
*/
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
/// 'Decrement Counter' command
|
|
///
|
|
/// @return
|
|
/// DS_TRUE - command successful @n
|
|
/// DS_FALSE - command failed
|
|
///
|
|
int DS28E16_cmd_decrementCounter(void)
|
|
{
|
|
unsigned char write_buf[255];
|
|
unsigned char read_buf[255];
|
|
int write_len = 0;
|
|
int read_len = 1;
|
|
|
|
last_result_byte = RESULT_FAIL_NONE;
|
|
/*
|
|
?<Start, device address write>
|
|
?TX: Decrement Counter Command
|
|
?<Stop>
|
|
?<Delay>
|
|
?<Start, device address read>
|
|
?RX: Length (SMBus) [always 1]
|
|
?RX: Result byte
|
|
?<Stop>
|
|
*/
|
|
|
|
write_buf[write_len++] = 1;
|
|
write_buf[write_len++] = CMD_DECREMENT_CNT;
|
|
|
|
if (DS28E16_standard_cmd_flow(write_buf, 50, read_buf, &read_len, write_len)) {
|
|
if (read_len == 1) {
|
|
last_result_byte = read_buf[0];
|
|
if (read_buf[0] == RESULT_SUCCESS)
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
/// 'Set Page Protection' command
|
|
///
|
|
/// @param[in] pg
|
|
/// block to set protection
|
|
/// @param[in] prot
|
|
/// protection value to set
|
|
///
|
|
/// @return
|
|
/// DS_TRUE - command successful @n
|
|
/// DS_FALSE - command failed
|
|
///
|
|
int DS28E16_cmd_setPageProtection(int page, unsigned char prot)
|
|
{
|
|
unsigned char write_buf[255];
|
|
unsigned char read_buf[255];
|
|
int write_len = 0;
|
|
int read_len = 1;
|
|
int len_byte = 3;
|
|
|
|
last_result_byte = RESULT_FAIL_NONE;
|
|
/*
|
|
?<Start, device address write>
|
|
?TX: Set Page Protection Command
|
|
?TX: Length (SMBus) [always 2]
|
|
?TX: Parameter
|
|
?TX: Protection Data
|
|
?<Stop>
|
|
?<Delay>
|
|
?<Start, device address read>
|
|
?RX: Length (SMBus) [always 1]
|
|
?RX: Result byte
|
|
?<Stop>
|
|
*/
|
|
|
|
write_buf[write_len++] = len_byte;
|
|
write_buf[write_len++] = CMD_SET_PAGE_PROT;
|
|
write_buf[write_len++] = page & 0x03;
|
|
write_buf[write_len++] = prot & 0x03;
|
|
|
|
if (DS28E16_standard_cmd_flow(write_buf,
|
|
DELAY_DS28E16_EE_WRITE*tm, read_buf, &read_len, write_len)) {
|
|
if (read_len == 1) {
|
|
last_result_byte = read_buf[0];
|
|
if (read_buf[0] == RESULT_SUCCESS)
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
int DS28E16_cmd_device_disable(int op, unsigned char *password)
|
|
{
|
|
unsigned char write_buf[64];
|
|
unsigned char read_buf[64];
|
|
int write_len = 0;
|
|
int read_len = 1;
|
|
int length_byte = 10;
|
|
|
|
last_result_byte = RESULT_FAIL_NONE;
|
|
/*
|
|
?<Start, device address write>
|
|
?TX: Length
|
|
?TX: Device Disable Command
|
|
?TX: Parameter
|
|
?<Stop>
|
|
?<Delay>
|
|
?<Start, device address read>
|
|
?RX: Length (SMBus)
|
|
?RX: Result byte
|
|
?RX: Data
|
|
?<Stop>
|
|
*/
|
|
|
|
write_buf[write_len++] = length_byte;
|
|
write_buf[write_len++] = CMD_DISABLE_DEVICE;
|
|
write_buf[write_len++] = op & 0x0F;
|
|
memcpy(&write_buf[write_len], password, 8);
|
|
write_len += 8;
|
|
|
|
if (DS28E16_standard_cmd_flow(write_buf,
|
|
DELAY_DS28E16_EE_WRITE, read_buf, &read_len, write_len)) {
|
|
if (read_len == 1) {
|
|
last_result_byte = read_buf[0];
|
|
if (read_buf[0] == RESULT_SUCCESS)
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
/// 'Compute and Read Page Authentication' command
|
|
///
|
|
/// @param[in] anon - boolean parameter
|
|
/// @param[in] pg - Page number 2,计数器; 0,page0; 1,page1;
|
|
/// @param[in] challenge
|
|
/// @param[out] hmac 返回的计算结果32个字节
|
|
///
|
|
/// @return
|
|
/// DS_TRUE - command successful @n
|
|
/// DS_FALSE - command failed
|
|
///
|
|
int DS28E16_cmd_computeReadPageAuthentication(int anon, int pg,
|
|
unsigned char *challenge, unsigned char *hmac)
|
|
{
|
|
unsigned char write_buf[255];
|
|
unsigned char read_buf[255];
|
|
int write_len = 0;
|
|
int read_len = 33;
|
|
int len_byte = 35;
|
|
|
|
last_result_byte = RESULT_FAIL_NONE;
|
|
|
|
write_buf[write_len++] = len_byte;
|
|
write_buf[write_len++] = CMD_COMP_READ_AUTH;
|
|
write_buf[write_len] = pg & 0x03;
|
|
if (anon)
|
|
write_buf[write_len] = (write_buf[write_len] | 0xE0);
|
|
|
|
write_len++;
|
|
write_buf[write_len++] = 0x02;// Fixed Parameter
|
|
memcpy(&write_buf[write_len], challenge, 32);// Challenge
|
|
write_len += 32;
|
|
|
|
ds_info("computeReadPageAuthen:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
write_buf[0], write_buf[1], write_buf[2], write_buf[3],
|
|
write_buf[4], write_buf[5], write_buf[6], write_buf[7],
|
|
write_buf[8], write_buf[9], write_buf[10], write_buf[11],
|
|
write_buf[12], write_buf[13], write_buf[14], write_buf[15],
|
|
write_buf[16], write_buf[17], write_buf[18], write_buf[19],
|
|
write_buf[20], write_buf[21], write_buf[22], write_buf[23],
|
|
write_buf[24], write_buf[25], write_buf[26], write_buf[27],
|
|
write_buf[28], write_buf[29], write_buf[30], write_buf[31],
|
|
write_buf[32], write_buf[33], write_buf[34]);
|
|
|
|
if (DS28E16_standard_cmd_flow(write_buf, DELAY_DS28E16_EE_WRITE, read_buf, &read_len, write_len)) {
|
|
last_result_byte = read_buf[0];
|
|
if (read_buf[0] == RESULT_SUCCESS) {
|
|
ds_info("hmac read_buf:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
read_buf[0], read_buf[1], read_buf[2], read_buf[3],
|
|
read_buf[4], read_buf[5], read_buf[6], read_buf[7],
|
|
read_buf[8], read_buf[9], read_buf[10], read_buf[11],
|
|
read_buf[12], read_buf[13], read_buf[14], read_buf[15],
|
|
read_buf[16], read_buf[17], read_buf[18], read_buf[19],
|
|
read_buf[20], read_buf[21], read_buf[22], read_buf[23],
|
|
read_buf[24], read_buf[25], read_buf[26], read_buf[27],
|
|
read_buf[28], read_buf[29], read_buf[30], read_buf[31],read_buf[32]);
|
|
memcpy(hmac, &read_buf[1], 32);
|
|
ds_info("hmac:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
hmac[0], hmac[1], hmac[2], hmac[3],
|
|
hmac[4], hmac[5], hmac[6], hmac[7],
|
|
hmac[8], hmac[9], hmac[10], hmac[11],
|
|
hmac[12], hmac[13], hmac[14], hmac[15],
|
|
hmac[16], hmac[17], hmac[18], hmac[19],
|
|
hmac[20], hmac[21], hmac[22], hmac[23],
|
|
hmac[24], hmac[25], hmac[26], hmac[27],
|
|
hmac[28], hmac[29], hmac[30], hmac[31]);
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
/// 'Compute Secret S' command
|
|
///
|
|
/// @param[in] anon - boolean parameter
|
|
/// @param[in] bdconst - boolean parameter
|
|
/// @param[in] pg - Page number 页面
|
|
/// @param[in] partial secret 32个字节的种子
|
|
///
|
|
/// @return
|
|
/// DS_TRUE - command successful @n
|
|
/// DS_FALSE - command failed
|
|
///
|
|
int DS28E16_cmd_computeS_Secret(int anon, int bdconst,
|
|
int pg, unsigned char *partial)
|
|
{
|
|
unsigned char write_buf[40];
|
|
unsigned char read_buf[40];
|
|
int write_len = 0;
|
|
int read_len = 1;
|
|
int len_byte = 35;
|
|
int param = pg & 0x03;
|
|
|
|
last_result_byte = RESULT_FAIL_NONE;
|
|
|
|
write_buf[write_len++] = len_byte;
|
|
write_buf[write_len++] = CMD_COMP_S_SECRET;
|
|
|
|
if (bdconst)
|
|
param = param | 0x04;
|
|
if (anon)
|
|
param = param | 0xE0;
|
|
|
|
write_buf[write_len] = param;
|
|
write_len++;
|
|
write_buf[write_len++] = 0x08;// Fixed Parameter
|
|
memcpy(&write_buf[write_len], partial, 32); // Partial Secret
|
|
write_len += 32;
|
|
|
|
ds_info("computeS_Secret:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
write_buf[0], write_buf[1], write_buf[2], write_buf[3],
|
|
write_buf[4], write_buf[5], write_buf[6], write_buf[7],
|
|
write_buf[8], write_buf[9], write_buf[10], write_buf[11],
|
|
write_buf[12], write_buf[13], write_buf[14], write_buf[15],
|
|
write_buf[16], write_buf[17], write_buf[18], write_buf[19],
|
|
write_buf[20], write_buf[21], write_buf[22], write_buf[23],
|
|
write_buf[24], write_buf[25], write_buf[26], write_buf[27],
|
|
write_buf[28], write_buf[29], write_buf[30], write_buf[31],
|
|
write_buf[32], write_buf[33], write_buf[34]);
|
|
|
|
if (DS28E16_standard_cmd_flow(write_buf, DELAY_DS28E16_EE_WRITE,
|
|
read_buf, &read_len, write_len)) {
|
|
last_result_byte = read_buf[0];
|
|
if (read_buf[0] == RESULT_SUCCESS)
|
|
return DS_TRUE;
|
|
}
|
|
|
|
ow_reset();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
int AuthenticateDS28E16(int anon, int bdconst, int S_Secret_PageNum, int PageNum,
|
|
unsigned char *Challenge, unsigned char *Secret_Seeds, unsigned char *S_Secret)
|
|
{
|
|
unsigned char PageData[32], MAC_Read_Value[32], CAL_MAC[32];
|
|
unsigned char status_chip[16];
|
|
unsigned char MAC_Computer_Datainput[128];
|
|
int i = 0;
|
|
int msg_len = 0;
|
|
unsigned char flag = DS_FALSE;
|
|
|
|
/*
|
|
//if (flag_mi_auth_result)
|
|
if (mi_auth_result == DS_TRUE)
|
|
return mi_auth_result;
|
|
*/
|
|
if (anon != ANONYMOUS) {
|
|
if (ds28el16_get_page_status_retry(status_chip) == DS_TRUE) {
|
|
MANID[0] = status_chip[4];
|
|
} else {
|
|
ow_reset();
|
|
return ERROR_R_STATUS;
|
|
}
|
|
|
|
if (ds28el16_Read_RomID_retry(mi_romid) != DS_TRUE) {
|
|
ow_reset();
|
|
return ERROR_R_ROMID;
|
|
}
|
|
}
|
|
|
|
// DS28E16 calculate its session secret
|
|
flag = DS28E16_cmd_computeS_Secret_retry(anon,
|
|
bdconst, S_Secret_PageNum, Secret_Seeds);
|
|
if (flag == DS_FALSE) {
|
|
ds_err("DS28E16_cmd_computeS_Secret error");
|
|
ow_reset();
|
|
return ERROR_S_SECRET;
|
|
}
|
|
|
|
// DS28E16 compute its MAC based on above sessio secret
|
|
flag = DS28E16_cmd_computeReadPageAuthentication_retry(anon,
|
|
PageNum, Challenge, MAC_Read_Value);
|
|
if (flag == DS_FALSE) {
|
|
ds_err("DS28E16_cmd_computeReadPageAuthentication error");
|
|
ow_reset();
|
|
return ERROR_COMPUTE_MAC;
|
|
}
|
|
|
|
ds_info("%02x %02x %02x %02x", anon, bdconst, S_Secret_PageNum, PageNum);
|
|
|
|
ds_dbg("Seeds:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
Secret_Seeds[0], Secret_Seeds[1], Secret_Seeds[2], Secret_Seeds[3],
|
|
Secret_Seeds[4], Secret_Seeds[5], Secret_Seeds[6], Secret_Seeds[7],
|
|
Secret_Seeds[8], Secret_Seeds[9], Secret_Seeds[10], Secret_Seeds[11],
|
|
Secret_Seeds[12], Secret_Seeds[13], Secret_Seeds[14], Secret_Seeds[15],
|
|
Secret_Seeds[16], Secret_Seeds[17], Secret_Seeds[18], Secret_Seeds[19],
|
|
Secret_Seeds[20], Secret_Seeds[21], Secret_Seeds[22], Secret_Seeds[23],
|
|
Secret_Seeds[24], Secret_Seeds[25], Secret_Seeds[26], Secret_Seeds[27],
|
|
Secret_Seeds[28], Secret_Seeds[29], Secret_Seeds[30], Secret_Seeds[31]);
|
|
|
|
ds_dbg("S_Secret:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
S_Secret[0], S_Secret[1], S_Secret[2], S_Secret[3],
|
|
S_Secret[4], S_Secret[5], S_Secret[6], S_Secret[7],
|
|
S_Secret[8], S_Secret[9], S_Secret[10], S_Secret[11],
|
|
S_Secret[12], S_Secret[13], S_Secret[14], S_Secret[15],
|
|
S_Secret[16], S_Secret[17], S_Secret[18], S_Secret[19],
|
|
S_Secret[20], S_Secret[21], S_Secret[22], S_Secret[23],
|
|
S_Secret[24], S_Secret[25], S_Secret[26], S_Secret[27],
|
|
S_Secret[28], S_Secret[29], S_Secret[30], S_Secret[31]);
|
|
|
|
ds_dbg("Challenge:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
Challenge[0], Challenge[1], Challenge[2], Challenge[3],
|
|
Challenge[4], Challenge[5], Challenge[6], Challenge[7],
|
|
Challenge[8], Challenge[9], Challenge[10], Challenge[11],
|
|
Challenge[12], Challenge[13], Challenge[14], Challenge[15],
|
|
Challenge[16], Challenge[17], Challenge[18], Challenge[19],
|
|
Challenge[20], Challenge[21], Challenge[22], Challenge[23],
|
|
Challenge[24], Challenge[25], Challenge[26], Challenge[27],
|
|
Challenge[28], Challenge[29], Challenge[30], Challenge[31]);
|
|
|
|
ds_dbg("MAC_Read_Value:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
MAC_Read_Value[0], MAC_Read_Value[1], MAC_Read_Value[2], MAC_Read_Value[3],
|
|
MAC_Read_Value[4], MAC_Read_Value[5], MAC_Read_Value[6], MAC_Read_Value[7],
|
|
MAC_Read_Value[8], MAC_Read_Value[9], MAC_Read_Value[10], MAC_Read_Value[11],
|
|
MAC_Read_Value[12], MAC_Read_Value[13], MAC_Read_Value[14], MAC_Read_Value[15],
|
|
MAC_Read_Value[16], MAC_Read_Value[17], MAC_Read_Value[18], MAC_Read_Value[19],
|
|
MAC_Read_Value[20], MAC_Read_Value[21], MAC_Read_Value[22], MAC_Read_Value[23],
|
|
MAC_Read_Value[24], MAC_Read_Value[25], MAC_Read_Value[26], MAC_Read_Value[27],
|
|
MAC_Read_Value[28], MAC_Read_Value[29], MAC_Read_Value[30], MAC_Read_Value[31]);
|
|
|
|
// read the page data
|
|
flag = ds28el16_get_page_data_retry(PageNum, PageData);
|
|
if (flag != DS_TRUE) {
|
|
ds_err("DS28E16_cmd_readMemory error");
|
|
ow_reset();
|
|
return ERROR_R_PAGEDATA;
|
|
}
|
|
|
|
// insert mi_romid
|
|
if (anon != ANONYMOUS)
|
|
memcpy(MAC_Computer_Datainput, mi_romid, 8);
|
|
else
|
|
memset(MAC_Computer_Datainput, 0xff, 8);
|
|
msg_len += 8;
|
|
|
|
// insert Page Data
|
|
memcpy(&MAC_Computer_Datainput[msg_len], PageData, 16);
|
|
msg_len += 16;
|
|
memset(&MAC_Computer_Datainput[msg_len], 0x00, 16);
|
|
msg_len += 16;
|
|
|
|
// insert Challenge
|
|
memcpy(&MAC_Computer_Datainput[msg_len], Challenge, 32);
|
|
msg_len += 32;
|
|
|
|
// insert Bind Data Page number
|
|
MAC_Computer_Datainput[msg_len] = PageNum & 0x03;
|
|
MAC_Computer_Datainput[msg_len] = MAC_Computer_Datainput[msg_len] & 0x03;
|
|
msg_len += 1;
|
|
|
|
// insert MANID
|
|
memcpy(&MAC_Computer_Datainput[msg_len], MANID, 2);
|
|
msg_len += 2;
|
|
|
|
// calculate the MAC
|
|
sha3_256_hmac(S_Secret, 32, MAC_Computer_Datainput, msg_len, CAL_MAC);
|
|
|
|
ds_dbg("host data:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
MAC_Computer_Datainput[0], MAC_Computer_Datainput[1], MAC_Computer_Datainput[2],
|
|
MAC_Computer_Datainput[3], MAC_Computer_Datainput[4], MAC_Computer_Datainput[5],
|
|
MAC_Computer_Datainput[6], MAC_Computer_Datainput[7], MAC_Computer_Datainput[8],
|
|
MAC_Computer_Datainput[9], MAC_Computer_Datainput[10], MAC_Computer_Datainput[11],
|
|
MAC_Computer_Datainput[12], MAC_Computer_Datainput[13], MAC_Computer_Datainput[14],
|
|
MAC_Computer_Datainput[15], MAC_Computer_Datainput[16], MAC_Computer_Datainput[17],
|
|
MAC_Computer_Datainput[18], MAC_Computer_Datainput[19], MAC_Computer_Datainput[20],
|
|
MAC_Computer_Datainput[21], MAC_Computer_Datainput[22], MAC_Computer_Datainput[23],
|
|
MAC_Computer_Datainput[24], MAC_Computer_Datainput[25], MAC_Computer_Datainput[26],
|
|
MAC_Computer_Datainput[27], MAC_Computer_Datainput[28], MAC_Computer_Datainput[29],
|
|
MAC_Computer_Datainput[30], MAC_Computer_Datainput[31], MAC_Computer_Datainput[32],
|
|
MAC_Computer_Datainput[33], MAC_Computer_Datainput[34], MAC_Computer_Datainput[35],
|
|
MAC_Computer_Datainput[36], MAC_Computer_Datainput[37], MAC_Computer_Datainput[38],
|
|
MAC_Computer_Datainput[39], MAC_Computer_Datainput[40], MAC_Computer_Datainput[41],
|
|
MAC_Computer_Datainput[42], MAC_Computer_Datainput[43], MAC_Computer_Datainput[44],
|
|
MAC_Computer_Datainput[45], MAC_Computer_Datainput[46], MAC_Computer_Datainput[47],
|
|
MAC_Computer_Datainput[48], MAC_Computer_Datainput[49], MAC_Computer_Datainput[50],
|
|
MAC_Computer_Datainput[51], MAC_Computer_Datainput[52], MAC_Computer_Datainput[53],
|
|
MAC_Computer_Datainput[54], MAC_Computer_Datainput[55], MAC_Computer_Datainput[56],
|
|
MAC_Computer_Datainput[57], MAC_Computer_Datainput[58], MAC_Computer_Datainput[59],
|
|
MAC_Computer_Datainput[60], MAC_Computer_Datainput[61], MAC_Computer_Datainput[62],
|
|
MAC_Computer_Datainput[63], MAC_Computer_Datainput[64], MAC_Computer_Datainput[65],
|
|
MAC_Computer_Datainput[66], MAC_Computer_Datainput[67], MAC_Computer_Datainput[68],
|
|
MAC_Computer_Datainput[69], MAC_Computer_Datainput[70], MAC_Computer_Datainput[71],
|
|
MAC_Computer_Datainput[72], MAC_Computer_Datainput[73], MAC_Computer_Datainput[74],
|
|
MAC_Computer_Datainput[75], MAC_Computer_Datainput[76], MAC_Computer_Datainput[77],
|
|
MAC_Computer_Datainput[78], MAC_Computer_Datainput[79]);
|
|
|
|
ds_dbg("host mac:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
CAL_MAC[0], CAL_MAC[1], CAL_MAC[2], CAL_MAC[3],
|
|
CAL_MAC[4], CAL_MAC[5], CAL_MAC[6], CAL_MAC[7],
|
|
CAL_MAC[8], CAL_MAC[9], CAL_MAC[10], CAL_MAC[11],
|
|
CAL_MAC[12], CAL_MAC[13], CAL_MAC[14], CAL_MAC[15],
|
|
CAL_MAC[16], CAL_MAC[17], CAL_MAC[18], CAL_MAC[19],
|
|
CAL_MAC[20], CAL_MAC[21], CAL_MAC[22], CAL_MAC[23],
|
|
CAL_MAC[24], CAL_MAC[25], CAL_MAC[26], CAL_MAC[27],
|
|
CAL_MAC[28], CAL_MAC[29], CAL_MAC[30], CAL_MAC[31]);
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
if (CAL_MAC[i] != MAC_Read_Value[i])
|
|
break;
|
|
}
|
|
|
|
if (i != 32) {
|
|
flag_mi_auth_result = 1;
|
|
mi_auth_result = ERROR_UNMATCH_MAC;
|
|
// for debug
|
|
ds_info("hmac is not match. result=ERROR_UNMATCH_MAC\n");
|
|
//flag_mi_page1_data = 0;
|
|
return ERROR_UNMATCH_MAC;
|
|
} else {
|
|
flag_mi_auth_result = 1;
|
|
ds_info("hmac is match. result=DS_TRUE\n");
|
|
mi_auth_result = DS_TRUE;
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// retry interface start //
|
|
static int ds28el16_Read_RomID_retry(unsigned char *RomID)
|
|
{
|
|
int i;
|
|
unsigned char data[50];
|
|
|
|
set_sched_affinity_to_current();
|
|
for (i = 0; i < GET_ROM_ID_RETRY; i++) {
|
|
ds_info("read rom id communication start %d...\n", i);
|
|
if (DS28E16_cmd_readStatus(data) == DS_TRUE) {
|
|
if (Read_RomID(RomID) == DS_TRUE) {
|
|
set_sched_affinity_to_all();
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
}
|
|
set_sched_affinity_to_all();
|
|
return DS_FALSE;
|
|
}
|
|
|
|
static int ds28el16_get_page_status_retry(unsigned char *data)
|
|
{
|
|
int i;
|
|
|
|
set_sched_affinity_to_current();
|
|
for (i = 0; i < GET_BLOCK_STATUS_RETRY; i++) {
|
|
ds_info("read page status communication start... %d\n", i);
|
|
|
|
if (DS28E16_cmd_readStatus(data) == DS_TRUE) {
|
|
set_sched_affinity_to_all();
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
set_sched_affinity_to_all();
|
|
|
|
return DS_FALSE;
|
|
}
|
|
|
|
/*
|
|
static int ds28el16_set_page_status_retry(unsigned char page, unsigned char status)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SET_BLOCK_STATUS_RETRY; i++) {
|
|
ds_info("set page status communication start... %d\n", i);
|
|
|
|
if (DS28E16_cmd_setPageProtection(page, status) == TRUE)
|
|
return DS_TRUE;
|
|
}
|
|
|
|
return DS_FALSE;
|
|
}
|
|
*/
|
|
|
|
static int ds28el16_get_page_data_retry(int page, unsigned char *data)
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
if (page >= MAX_PAGENUM)
|
|
return DS_FALSE;
|
|
*/
|
|
set_sched_affinity_to_current();
|
|
for (i = 0; i < GET_USER_MEMORY_RETRY; i++) {
|
|
ds_info("read page data communication start... %d\n", i);
|
|
|
|
if (DS28E16_cmd_readMemory(page, data) == DS_TRUE) {
|
|
set_sched_affinity_to_all();
|
|
ds_dbg("page number is %d\n", page);
|
|
ds_dbg("page data:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
data[0], data[1], data[2], data[3],
|
|
data[4], data[5], data[6], data[7],
|
|
data[8], data[9], data[10], data[11],
|
|
data[12], data[13], data[14], data[15]);
|
|
ds_dbg("flag_mi_page0_data is %d\n", flag_mi_page0_data);
|
|
ds_dbg("mi_page0_data data:\n");
|
|
ds_dbg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
mi_page0_data[0], mi_page0_data[1], mi_page0_data[2], mi_page0_data[3],
|
|
mi_page0_data[4], mi_page0_data[5], mi_page0_data[6], mi_page0_data[7],
|
|
mi_page0_data[8], mi_page0_data[9], mi_page0_data[10], mi_page0_data[11],
|
|
mi_page0_data[12], mi_page0_data[13], mi_page0_data[14], mi_page0_data[15]);
|
|
ds_dbg("flag_mi_page1_data is %d\n", flag_mi_page1_data);
|
|
ds_dbg("mi_page1_data data:\n");
|
|
ds_dbg("%%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
mi_page1_data[0], mi_page1_data[1], mi_page1_data[2], mi_page1_data[3],
|
|
mi_page1_data[4], mi_page1_data[5], mi_page1_data[6], mi_page1_data[7],
|
|
mi_page1_data[8], mi_page1_data[9], mi_page1_data[10], mi_page1_data[11],
|
|
mi_page1_data[12], mi_page1_data[13], mi_page1_data[14], mi_page1_data[15]);
|
|
ds_dbg("flag_mi_counter is %d\n", flag_mi_counter);
|
|
return DS_TRUE;
|
|
}
|
|
}
|
|
set_sched_affinity_to_all();
|
|
|
|
return DS_FALSE;
|
|
}
|
|
|
|
static int DS28E16_cmd_computeS_Secret_retry(int anon, int bdconst,
|
|
int pg, unsigned char *partial)
|
|
{
|
|
int i;
|
|
|
|
if (pg >= MAX_PAGENUM)
|
|
return DS_FALSE;
|
|
|
|
for (i = 0; i < GET_S_SECRET_RETRY; i++) {
|
|
if (DS28E16_cmd_computeS_Secret(anon, bdconst,
|
|
pg, partial) == DS_TRUE)
|
|
return DS_TRUE;
|
|
}
|
|
|
|
return DS_FALSE;
|
|
}
|
|
|
|
static int DS28E16_cmd_computeReadPageAuthentication_retry(int anon, int pg,
|
|
unsigned char *challenge, unsigned char *hmac)
|
|
{
|
|
int i;
|
|
|
|
if (pg >= MAX_PAGENUM)
|
|
return DS_FALSE;
|
|
|
|
for (i = 0; i < GET_MAC_RETRY; i++) {
|
|
if (DS28E16_cmd_computeReadPageAuthentication(anon, pg,
|
|
challenge, hmac) == DS_TRUE)
|
|
return DS_TRUE;
|
|
}
|
|
|
|
return DS_FALSE;
|
|
}
|
|
|
|
// retry interface end //
|
|
|
|
static int ds28el16_do_authentication(struct ds28e16_data *data)
|
|
{
|
|
int result = 0, i;
|
|
|
|
ds_log("%s enter\n", __func__);
|
|
|
|
if (flag_battery_verify_process) {
|
|
ds_log("%s flag_battery_verify_process...\n", __func__);
|
|
return result;
|
|
}
|
|
|
|
set_sched_affinity_to_current();
|
|
for (i = 0; i < GET_VERIFY_RETRY; i++) {
|
|
result = AuthenticateDS28E16(auth_ANON, auth_BDCONST, 0,
|
|
pagenumber, challenge, session_seed, S_secret);
|
|
if (result == DS_TRUE) {
|
|
data->batt_verified = 1;
|
|
set_sched_affinity_to_all();
|
|
ds_log("%s battery verify ok[%d]", __func__, result);
|
|
return result;
|
|
}
|
|
}
|
|
set_sched_affinity_to_all();
|
|
|
|
if (result != DS_TRUE) {
|
|
data->batt_verified = 0;
|
|
ds_log("%s battery verify failed[%d]", __func__, result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* All power supply functions here */
|
|
|
|
static enum power_supply_property verify_props[] = {
|
|
POWER_SUPPLY_PROP_ROMID,
|
|
POWER_SUPPLY_PROP_DS_STATUS,
|
|
POWER_SUPPLY_PROP_PAGENUMBER,
|
|
POWER_SUPPLY_PROP_PAGEDATA,
|
|
POWER_SUPPLY_PROP_AUTHEN_RESULT,
|
|
POWER_SUPPLY_PROP_SESSION_SEED,
|
|
POWER_SUPPLY_PROP_S_SECRET,
|
|
POWER_SUPPLY_PROP_CHALLENGE,
|
|
POWER_SUPPLY_PROP_AUTH_ANON,
|
|
POWER_SUPPLY_PROP_AUTH_BDCONST,
|
|
POWER_SUPPLY_PROP_PAGE0_DATA,
|
|
POWER_SUPPLY_PROP_PAGE1_DATA,
|
|
POWER_SUPPLY_PROP_VERIFY_MODEL_NAME,
|
|
POWER_SUPPLY_PROP_CHIP_OK,
|
|
POWER_SUPPLY_PROP_MI_BATTERY_ID,
|
|
POWER_SUPPLY_PROP_MAXIM_BATT_CYCLE_COUNT,
|
|
POWER_SUPPLY_PROP_AUTHENTIC,
|
|
};
|
|
|
|
static int verify_get_property(struct power_supply *psy, enum power_supply_property psp,
|
|
union power_supply_propval *val)
|
|
{
|
|
struct ds28e16_data *data = power_supply_get_drvdata(psy);
|
|
int ret;
|
|
unsigned int cycle_count;
|
|
unsigned char pagedata[16] = {0x00};
|
|
unsigned char buf[50];
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_VERIFY_MODEL_NAME:
|
|
ret = Read_RomID(mi_romid);
|
|
if (ret == DS_TRUE)
|
|
val->strval = "ds28e16";
|
|
else
|
|
val->strval = "unknown";
|
|
break;
|
|
case POWER_SUPPLY_PROP_AUTHEN_RESULT:
|
|
if (data->batt_verified == DS_TRUE)
|
|
val->intval = true;
|
|
else
|
|
val->intval = false;
|
|
break;
|
|
case POWER_SUPPLY_PROP_PAGENUMBER:
|
|
val->intval = pagenumber;
|
|
break;
|
|
case POWER_SUPPLY_PROP_ROMID:
|
|
ret = Read_RomID(mi_romid);
|
|
// memcpy(val->arrayval, mi_romid, 8);
|
|
if (ret != DS_TRUE)
|
|
ret = -EAGAIN;
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHIP_OK:
|
|
ret = ds28el16_Read_RomID_retry(mi_romid);
|
|
ds_err("get chip_ok read RomID = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
mi_romid[0], mi_romid[1], mi_romid[2], mi_romid[3],
|
|
mi_romid[4], mi_romid[5], mi_romid[6], mi_romid[7]);
|
|
if ((mi_romid[0] == FAMILY_CODE) && (mi_romid[6] == CUSTOM_ID_MSB) && ((mi_romid[5] & 0xf0) == CUSTOM_ID_LSB))
|
|
val->intval = true;
|
|
else
|
|
val->intval = false;
|
|
break;
|
|
case POWER_SUPPLY_PROP_MI_BATTERY_ID:
|
|
ret = DS28E16_cmd_readMemory(pagenumber, pagedata);
|
|
val->intval = pagedata[11];
|
|
ds_err("pagedata = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
pagedata[0], pagedata[1], pagedata[2], pagedata[3],
|
|
pagedata[4], pagedata[5], pagedata[6], pagedata[7],
|
|
pagedata[8], pagedata[9], pagedata[10], pagedata[11],
|
|
pagedata[12], pagedata[13], pagedata[14], pagedata[15]);
|
|
break;
|
|
case POWER_SUPPLY_PROP_DS_STATUS:
|
|
ret = DS28E16_cmd_readStatus(buf);
|
|
// memcpy(val->arrayval, buf, 8);
|
|
if (ret != DS_TRUE)
|
|
ret = -EAGAIN;
|
|
break;
|
|
case POWER_SUPPLY_PROP_PAGEDATA:
|
|
ret = DS28E16_cmd_readMemory(pagenumber, buf);
|
|
// memcpy(val->arrayval, buf, 16);
|
|
if (ret != DS_TRUE)
|
|
ret = -EAGAIN;
|
|
break;
|
|
case POWER_SUPPLY_PROP_PAGE0_DATA:
|
|
ret = DS28E16_cmd_readMemory(0, buf);
|
|
// memcpy(val->arrayval, buf, 16);
|
|
if (ret != DS_TRUE)
|
|
ret = -EAGAIN;
|
|
break;
|
|
case POWER_SUPPLY_PROP_PAGE1_DATA:
|
|
ret = DS28E16_cmd_readMemory(1, buf);
|
|
// memcpy(val->arrayval, buf, 16);
|
|
if (ret != DS_TRUE)
|
|
ret = -EAGAIN;
|
|
break;
|
|
case POWER_SUPPLY_PROP_MAXIM_BATT_CYCLE_COUNT:
|
|
ret = ds28el16_get_page_data_retry(DC_PAGE, pagedata);
|
|
if (ret == DS_TRUE) {
|
|
cycle_count = (pagedata[2] << 16) + (pagedata[1] << 8)
|
|
+ pagedata[0];
|
|
val->intval = DC_INIT_VALUE - cycle_count;
|
|
}
|
|
break;
|
|
default:
|
|
ds_err("unsupported property %d\n", psp);
|
|
return -ENODATA;
|
|
}
|
|
|
|
if (ret < 0) {
|
|
ds_err("Couldn't get prop %d rc = %d\n", psp, ret);
|
|
return -ENODATA;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int verify_set_property(struct power_supply *psy,
|
|
enum power_supply_property prop,
|
|
const union power_supply_propval *val)
|
|
{
|
|
//int ret;
|
|
//unsigned char buf[50];
|
|
struct ds28e16_data *data = power_supply_get_drvdata(psy);
|
|
int authen_result;
|
|
|
|
switch (prop) {
|
|
case POWER_SUPPLY_PROP_PAGENUMBER:
|
|
pagenumber = val->intval;
|
|
break;
|
|
/*
|
|
case POWER_SUPPLY_PROP_PAGEDATA:
|
|
memcpy(buf, val->arrayval, 16);
|
|
ret = DS28E16_cmd_writeMemory(pagenumber, buf);
|
|
if (ret != DS_TRUE)
|
|
return -EAGAIN;
|
|
break;
|
|
case POWER_SUPPLY_PROP_SESSION_SEED:
|
|
memcpy(session_seed, val->arrayval, 32);
|
|
break;
|
|
case POWER_SUPPLY_PROP_S_SECRET:
|
|
memcpy(S_secret, val->arrayval, 32);
|
|
break;
|
|
case POWER_SUPPLY_PROP_CHALLENGE:
|
|
memcpy(challenge, val->arrayval, 32);
|
|
break;
|
|
*/
|
|
case POWER_SUPPLY_PROP_AUTH_ANON:
|
|
auth_ANON = val->intval;
|
|
break;
|
|
case POWER_SUPPLY_PROP_AUTH_BDCONST:
|
|
auth_BDCONST = val->intval;
|
|
break;
|
|
case POWER_SUPPLY_PROP_MAXIM_BATT_CYCLE_COUNT:
|
|
DS28E16_cmd_decrementCounter();
|
|
break;
|
|
case POWER_SUPPLY_PROP_AUTHENTIC:
|
|
if (val->intval == 1) {
|
|
authen_result = ds28el16_do_authentication(data);
|
|
pr_err("redo authentic: authen_result: %d\n", authen_result);
|
|
}
|
|
break;
|
|
default:
|
|
ds_err("unsupported property %d\n", prop);
|
|
return -ENODATA;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int verify_prop_is_writeable(struct power_supply *psy,
|
|
enum power_supply_property prop)
|
|
{
|
|
int ret;
|
|
|
|
switch (prop) {
|
|
case POWER_SUPPLY_PROP_PAGENUMBER:
|
|
case POWER_SUPPLY_PROP_PAGEDATA:
|
|
case POWER_SUPPLY_PROP_SESSION_SEED:
|
|
case POWER_SUPPLY_PROP_S_SECRET:
|
|
case POWER_SUPPLY_PROP_CHALLENGE:
|
|
case POWER_SUPPLY_PROP_AUTH_ANON:
|
|
case POWER_SUPPLY_PROP_AUTH_BDCONST:
|
|
case POWER_SUPPLY_PROP_MAXIM_BATT_CYCLE_COUNT:
|
|
case POWER_SUPPLY_PROP_AUTHENTIC:
|
|
ret = 1;
|
|
break;
|
|
default:
|
|
ret = 0;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int verify_psy_register(struct ds28e16_data *ds)
|
|
{
|
|
struct power_supply_config verify_psy_cfg = {};
|
|
|
|
ds->verify_psy_d.name = "batt_verify";
|
|
ds->verify_psy_d.type = POWER_SUPPLY_TYPE_BATT_VERIFY;
|
|
ds->verify_psy_d.properties = verify_props;
|
|
ds->verify_psy_d.num_properties = ARRAY_SIZE(verify_props);
|
|
ds->verify_psy_d.get_property = verify_get_property;
|
|
ds->verify_psy_d.set_property = verify_set_property;
|
|
ds->verify_psy_d.property_is_writeable = verify_prop_is_writeable;
|
|
|
|
verify_psy_cfg.drv_data = ds;
|
|
verify_psy_cfg.of_node = ds->dev->of_node;
|
|
verify_psy_cfg.num_supplicants = 0;
|
|
ds->verify_psy = devm_power_supply_register(ds->dev,
|
|
&ds->verify_psy_d,
|
|
&verify_psy_cfg);
|
|
if (IS_ERR(ds->verify_psy)) {
|
|
ds_err("Failed to register verify_psy");
|
|
return PTR_ERR(ds->verify_psy);
|
|
}
|
|
|
|
ds_log("%s power supply register successfully\n", ds->verify_psy_d.name);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void verify_psy_unregister(struct ds28e16_data *ds)
|
|
{
|
|
power_supply_unregister(ds->verify_psy);
|
|
}
|
|
|
|
// parse dts
|
|
static int ds28e16_parse_dt(struct device *dev,
|
|
struct ds28e16_data *pdata)
|
|
{
|
|
int error, val;
|
|
struct device_node *np = dev->of_node;
|
|
|
|
// parse version
|
|
pdata->version = 0;
|
|
error = of_property_read_u32(np, "maxim,version", &val);
|
|
if (error && (error != -EINVAL))
|
|
ds_err("Unable to read maxim,version node.\n");
|
|
else if (error != -EINVAL)
|
|
pdata->version = val;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// read data from file
|
|
static ssize_t ds28e16_ds_Auth_Result_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int result;
|
|
|
|
result = AuthenticateDS28E16(auth_ANON, auth_BDCONST, 0,
|
|
pagenumber, challenge, session_seed, S_secret);
|
|
if (result == ERROR_R_STATUS)
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Authenticate failed : ERROR_R_STATUS!\n");
|
|
else if (result == ERROR_UNMATCH_MAC)
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Authenticate failed : MAC is not match!\n");
|
|
else if (result == ERROR_R_ROMID)
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Authenticate failed : ERROR_R_ROMID!\n");
|
|
else if (result == ERROR_COMPUTE_MAC)
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Authenticate failed : ERROR_COMPUTE_MAC!\n");
|
|
else if (result == ERROR_S_SECRET)
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Authenticate failed : ERROR_S_SECRET!\n");
|
|
else if (result == DS_TRUE)
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Authenticate success!!!\n");
|
|
else
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Authenticate failed : other reason.\n");
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_romid_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
short status;
|
|
unsigned char RomID[10] = {0x00};
|
|
int i = 0; int count = 0;
|
|
|
|
for (i = 0; i < attr_trytimes; i++) {
|
|
status = Read_RomID(RomID);
|
|
|
|
if (status == DS_TRUE) {
|
|
count++;
|
|
ds_log("Read_RomID success!\n");
|
|
} else {
|
|
ds_log("Read_RomID fail!\n");
|
|
}
|
|
ds_dbg("RomID = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
RomID[0], RomID[1], RomID[2], RomID[3],
|
|
RomID[4], RomID[5], RomID[6], RomID[7]);
|
|
Delay_us(1000);
|
|
}
|
|
ds_log("test done\nsuccess time : %d\n", count);
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Success = %d\nRomID = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
count, RomID[0], RomID[1], RomID[2], RomID[3],
|
|
RomID[4], RomID[5], RomID[6], RomID[7]);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_pagenumber_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE, "%02x\n", pagenumber);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_pagenumber_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int buf_int;
|
|
|
|
if (sscanf(buf, "%d", &buf_int) != 1)
|
|
return -EINVAL;
|
|
|
|
ds_dbg("new pagenumber = %d\n", buf_int);
|
|
|
|
if ((buf_int >= 0) && (buf_int <= 3))
|
|
pagenumber = buf_int;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_pagedata_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int result;
|
|
unsigned char pagedata[16] = {0x00};
|
|
int i = 0; int count = 0;
|
|
|
|
for (i = 0; i < attr_trytimes; i++) {
|
|
result = DS28E16_cmd_readMemory(pagenumber, pagedata);
|
|
|
|
if (result == DS_TRUE) {
|
|
count++;
|
|
ds_log("DS28E16_cmd_readMemory success!\n");
|
|
} else {
|
|
ds_log("DS28E16_cmd_readMemory fail!\n");
|
|
}
|
|
ds_dbg("pagedata = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
pagedata[0], pagedata[1], pagedata[2], pagedata[3],
|
|
pagedata[4], pagedata[5], pagedata[6], pagedata[7],
|
|
pagedata[8], pagedata[9], pagedata[10], pagedata[11],
|
|
pagedata[12], pagedata[13], pagedata[14], pagedata[15]);
|
|
Delay_us(1000);
|
|
}
|
|
ds_log("test done\nsuccess time : %d\n", count);
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Success = %d\npagedata = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
count, pagedata[0], pagedata[1], pagedata[2], pagedata[3],
|
|
pagedata[4], pagedata[5], pagedata[6], pagedata[7],
|
|
pagedata[8], pagedata[9], pagedata[10], pagedata[11],
|
|
pagedata[12], pagedata[13], pagedata[14], pagedata[15]);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_pagedata_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int result;
|
|
unsigned char pagedata[16] = {0x00};
|
|
|
|
if (sscanf(buf, "%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx",
|
|
&pagedata[0], &pagedata[1], &pagedata[2], &pagedata[3],
|
|
&pagedata[4], &pagedata[5], &pagedata[6], &pagedata[7],
|
|
&pagedata[8], &pagedata[9], &pagedata[10], &pagedata[11],
|
|
&pagedata[12], &pagedata[13], &pagedata[14], &pagedata[15]) != 16)
|
|
return -EINVAL;
|
|
|
|
ds_dbg("new data = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
pagedata[0], pagedata[1], pagedata[2], pagedata[3],
|
|
pagedata[4], pagedata[5], pagedata[6], pagedata[7],
|
|
pagedata[8], pagedata[9], pagedata[10], pagedata[11],
|
|
pagedata[12], pagedata[13], pagedata[14], pagedata[15]);
|
|
|
|
result = DS28E16_cmd_writeMemory(pagenumber, pagedata);
|
|
if (result == DS_TRUE)
|
|
ds_log("DS28E16_cmd_writeMemory success!\n");
|
|
else
|
|
ds_log("DS28E16_cmd_writeMemory fail!\n");
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_time_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE, "%d\n", attr_trytimes);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_time_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int buf_int;
|
|
|
|
if (sscanf(buf, "%d", &buf_int) != 1)
|
|
return -EINVAL;
|
|
|
|
ds_log("new trytimes = %d\n", buf_int);
|
|
|
|
if (buf_int > 0)
|
|
attr_trytimes = buf_int;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_session_seed_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n",
|
|
session_seed[0], session_seed[1], session_seed[2], session_seed[3],
|
|
session_seed[4], session_seed[5], session_seed[6], session_seed[7],
|
|
session_seed[8], session_seed[9], session_seed[10], session_seed[11],
|
|
session_seed[12], session_seed[13], session_seed[14], session_seed[15],
|
|
session_seed[16], session_seed[17], session_seed[18], session_seed[19],
|
|
session_seed[20], session_seed[21], session_seed[22], session_seed[23],
|
|
session_seed[24], session_seed[25], session_seed[26], session_seed[27],
|
|
session_seed[28], session_seed[29], session_seed[30], session_seed[31]);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_session_seed_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
if (sscanf(buf, "%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx",
|
|
&session_seed[0], &session_seed[1], &session_seed[2],
|
|
&session_seed[3], &session_seed[4], &session_seed[5],
|
|
&session_seed[6], &session_seed[7], &session_seed[8],
|
|
&session_seed[9], &session_seed[10], &session_seed[11],
|
|
&session_seed[12], &session_seed[13], &session_seed[14],
|
|
&session_seed[15], &session_seed[16], &session_seed[17],
|
|
&session_seed[18], &session_seed[19], &session_seed[20],
|
|
&session_seed[21], &session_seed[22], &session_seed[23],
|
|
&session_seed[24], &session_seed[25], &session_seed[26],
|
|
&session_seed[27], &session_seed[28], &session_seed[29],
|
|
&session_seed[30], &session_seed[31]) != 32)
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_challenge_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n",
|
|
challenge[0], challenge[1], challenge[2], challenge[3],
|
|
challenge[4], challenge[5], challenge[6], challenge[7],
|
|
challenge[8], challenge[9], challenge[10], challenge[11],
|
|
challenge[12], challenge[13], challenge[14], challenge[15],
|
|
challenge[16], challenge[17], challenge[18], challenge[19],
|
|
challenge[20], challenge[21], challenge[22], challenge[23],
|
|
challenge[24], challenge[25], challenge[26], challenge[27],
|
|
challenge[28], challenge[29], challenge[30], challenge[31]);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_challenge_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
if (sscanf(buf, "%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx",
|
|
&challenge[0], &challenge[1], &challenge[2], &challenge[3],
|
|
&challenge[4], &challenge[5], &challenge[6], &challenge[7],
|
|
&challenge[8], &challenge[9], &challenge[10], &challenge[11],
|
|
&challenge[12], &challenge[13], &challenge[14], &challenge[15],
|
|
&challenge[16], &challenge[17], &challenge[18], &challenge[19],
|
|
&challenge[20], &challenge[21], &challenge[22], &challenge[23],
|
|
&challenge[24], &challenge[25], &challenge[26], &challenge[27],
|
|
&challenge[28], &challenge[29],
|
|
&challenge[30], &challenge[31]) != 32)
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_S_secret_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,\n",
|
|
S_secret[0], S_secret[1], S_secret[2], S_secret[3],
|
|
S_secret[4], S_secret[5], S_secret[6], S_secret[7],
|
|
S_secret[8], S_secret[9], S_secret[10], S_secret[11],
|
|
S_secret[12], S_secret[13], S_secret[14], S_secret[15],
|
|
S_secret[16], S_secret[17], S_secret[18], S_secret[19],
|
|
S_secret[20], S_secret[21], S_secret[22], S_secret[23],
|
|
S_secret[24], S_secret[25], S_secret[26], S_secret[27],
|
|
S_secret[28], S_secret[29], S_secret[30], S_secret[31]);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_S_secret_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
if (sscanf(buf, "%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx,%2hhx",
|
|
&S_secret[0], &S_secret[1], &S_secret[2], &S_secret[3],
|
|
&S_secret[4], &S_secret[5], &S_secret[6], &S_secret[7],
|
|
&S_secret[8], &S_secret[9], &S_secret[10], &S_secret[11],
|
|
&S_secret[12], &S_secret[13], &S_secret[14], &S_secret[15],
|
|
&S_secret[16], &S_secret[17], &S_secret[18], &S_secret[19],
|
|
&S_secret[20], &S_secret[21], &S_secret[22], &S_secret[23],
|
|
&S_secret[24], &S_secret[25], &S_secret[26], &S_secret[27],
|
|
&S_secret[28], &S_secret[29],
|
|
&S_secret[30], &S_secret[31]) != 32)
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_auth_ANON_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE, "%02x\n", auth_ANON);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_auth_ANON_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
if (sscanf(buf, "%d", &auth_ANON) != 1)
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_auth_BDCONST_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE, "%02x\n", auth_BDCONST);
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_auth_BDCONST_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
if (sscanf(buf, "%d", &auth_BDCONST) != 1)
|
|
return -EINVAL;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds28e16_ds_readstatus_status_read(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
int result;
|
|
unsigned char status[16] = {0x00};
|
|
int i = 0; int count = 0;
|
|
|
|
|
|
for (i = 0; i < attr_trytimes; i++) {
|
|
result = DS28E16_cmd_readStatus(status);
|
|
|
|
if (result == DS_TRUE) {
|
|
count++;
|
|
ds_log("DS28E16_cmd_readStatus success!\n");
|
|
} else {
|
|
ds_log("DS28E16_cmd_readStatus fail!\n");
|
|
}
|
|
ds_dbg("Status = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
status[0], status[1], status[2], status[3],
|
|
status[4], status[5], status[6], status[7],
|
|
status[8], status[9], status[10], status[11],
|
|
status[12], status[13], status[14], status[15]);
|
|
Delay_us(1000);
|
|
}
|
|
ds_log("test done\nsuccess time : %d\n", count);
|
|
return scnprintf(buf, PAGE_SIZE,
|
|
"Success = %d\nStatus = %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
|
|
count, status[0], status[1], status[2], status[3],
|
|
status[4], status[5], status[6], status[7],
|
|
status[8], status[9], status[10], status[11],
|
|
status[12], status[13], status[14], status[15]);
|
|
}
|
|
|
|
static DEVICE_ATTR(ds_readstatus, S_IRUGO,
|
|
ds28e16_ds_readstatus_status_read, NULL);
|
|
static DEVICE_ATTR(ds_romid, S_IRUGO,
|
|
ds28e16_ds_romid_status_read, NULL);
|
|
static DEVICE_ATTR(ds_pagenumber, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
ds28e16_ds_pagenumber_status_read,
|
|
ds28e16_ds_pagenumber_store);
|
|
static DEVICE_ATTR(ds_pagedata, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
ds28e16_ds_pagedata_status_read,
|
|
ds28e16_ds_pagedata_store);
|
|
static DEVICE_ATTR(ds_time, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
ds28e16_ds_time_status_read,
|
|
ds28e16_ds_time_store);
|
|
static DEVICE_ATTR(ds_session_seed, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
ds28e16_ds_session_seed_status_read,
|
|
ds28e16_ds_session_seed_store);
|
|
static DEVICE_ATTR(ds_challenge, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
ds28e16_ds_challenge_status_read,
|
|
ds28e16_ds_challenge_store);
|
|
static DEVICE_ATTR(ds_S_secret, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
ds28e16_ds_S_secret_status_read,
|
|
ds28e16_ds_S_secret_store);
|
|
static DEVICE_ATTR(ds_auth_ANON, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
ds28e16_ds_auth_ANON_status_read,
|
|
ds28e16_ds_auth_ANON_store);
|
|
static DEVICE_ATTR(ds_auth_BDCONST, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
ds28e16_ds_auth_BDCONST_status_read,
|
|
ds28e16_ds_auth_BDCONST_store);
|
|
static DEVICE_ATTR(ds_Auth_Result, S_IRUGO,
|
|
ds28e16_ds_Auth_Result_status_read, NULL);
|
|
|
|
static struct attribute *ds_attributes[] = {
|
|
&dev_attr_ds_readstatus.attr,
|
|
&dev_attr_ds_romid.attr,
|
|
&dev_attr_ds_pagenumber.attr,
|
|
&dev_attr_ds_pagedata.attr,
|
|
&dev_attr_ds_time.attr,
|
|
&dev_attr_ds_session_seed.attr,
|
|
&dev_attr_ds_challenge.attr,
|
|
&dev_attr_ds_S_secret.attr,
|
|
&dev_attr_ds_auth_ANON.attr,
|
|
&dev_attr_ds_auth_BDCONST.attr,
|
|
&dev_attr_ds_Auth_Result.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group ds_attr_group = {
|
|
.attrs = ds_attributes,
|
|
};
|
|
|
|
#define VERIFY_PERIOD_S (5*1000)
|
|
#define VERIFY_MAX_COUNT 5
|
|
static void battery_verify(struct work_struct *work)
|
|
{
|
|
int result, i;
|
|
static int count;
|
|
struct ds28e16_data *data = container_of(work, struct ds28e16_data,
|
|
battery_verify_work.work);
|
|
|
|
ds_log("%s enter\n", __func__);
|
|
flag_battery_verify_process = true;
|
|
for (i = 0; i < GET_VERIFY_RETRY; i++) {
|
|
result = AuthenticateDS28E16(auth_ANON, auth_BDCONST, 0,
|
|
pagenumber, challenge, session_seed, S_secret);
|
|
if (result == DS_TRUE)
|
|
break;
|
|
}
|
|
|
|
if (result == DS_TRUE) {
|
|
data->batt_verified = 1;
|
|
ds_info("%s batt_verified = 1 \n", __func__);
|
|
} else {
|
|
data->batt_verified = 0;
|
|
if (count < VERIFY_MAX_COUNT) {
|
|
schedule_delayed_work(&data->battery_verify_work,
|
|
msecs_to_jiffies(VERIFY_PERIOD_S));
|
|
ds_info("%s battery verify failed times[%d]", __func__, count);
|
|
count++;
|
|
} else {
|
|
ds_info("%s battery verify failed[%d]", __func__, result);
|
|
}
|
|
}
|
|
|
|
if (data->batt_verified == 1) {
|
|
union power_supply_propval propval;
|
|
struct power_supply *battery;
|
|
unsigned char pagedata[16] = {0x00};
|
|
|
|
result = DS28E16_cmd_readMemory(pagenumber, pagedata);
|
|
if (result == DS_TRUE) {
|
|
propval.intval = pagedata[11];
|
|
ds_info("%s battery verify [%d] id = %x", __func__, result, propval.intval);
|
|
battery = power_supply_get_by_name("battery");
|
|
if (battery)
|
|
power_supply_set_property(battery, POWER_SUPPLY_PROP_BATT_ID_UPDATE, &propval);
|
|
}
|
|
}
|
|
flag_battery_verify_process = false;
|
|
}
|
|
static int ds28e16_probe(struct platform_device *pdev)
|
|
{
|
|
int retval = 0;
|
|
struct ds28e16_data *ds28e16_data;
|
|
//union power_supply_propval b_val = {0,};
|
|
|
|
ds_log("%s entry.", __func__);
|
|
ds_dbg("platform_device is %s", pdev->name);
|
|
if (strcmp(pdev->name, "maxim_ds28e16") != 0)
|
|
return -ENODEV;
|
|
|
|
if (!pdev->dev.of_node || !of_device_is_available(pdev->dev.of_node))
|
|
return -ENODEV;
|
|
|
|
if (pdev->dev.of_node) {
|
|
ds28e16_data = devm_kzalloc(&pdev->dev,
|
|
sizeof(struct ds28e16_data),
|
|
GFP_KERNEL);
|
|
if (!ds28e16_data) {
|
|
ds_err("Failed to allocate memory\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
retval = ds28e16_parse_dt(&pdev->dev, ds28e16_data);
|
|
if (retval) {
|
|
retval = -EINVAL;
|
|
goto ds28e16_parse_dt_err;
|
|
}
|
|
} else {
|
|
ds28e16_data = pdev->dev.platform_data;
|
|
}
|
|
|
|
if (!ds28e16_data) {
|
|
ds_err("No platform data found\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ds28e16_data->dev = &pdev->dev;
|
|
ds28e16_data->pdev = pdev;
|
|
platform_set_drvdata(pdev, ds28e16_data);
|
|
INIT_DELAYED_WORK(&ds28e16_data->battery_verify_work, battery_verify);
|
|
schedule_delayed_work(&ds28e16_data->battery_verify_work, msecs_to_jiffies(0));
|
|
|
|
retval = verify_psy_register(ds28e16_data);
|
|
if (retval) {
|
|
ds_err("Failed to verify_psy_register, err:%d\n", retval);
|
|
goto ds28e16_psy_register_err;
|
|
}
|
|
|
|
retval = sysfs_create_group(&ds28e16_data->dev->kobj, &ds_attr_group);
|
|
if (retval) {
|
|
ds_err("Failed to register sysfs, err:%d\n", retval);
|
|
goto ds28e16_create_group_err;
|
|
}
|
|
|
|
/*
|
|
retval = power_supply_get_property(ds28e16_data->verify_psy,
|
|
POWER_SUPPLY_PROP_AUTHEN_RESULT, &b_val);
|
|
if (b_val.intval != true) {
|
|
schedule_delayed_work(&ds28e16_data->authentic_work,
|
|
msecs_to_jiffies(0));
|
|
}
|
|
*/
|
|
return 0;
|
|
|
|
ds28e16_create_group_err:
|
|
//sysfs_remove_groups(&ds28e16_data->dev->kobj, &(&ds_attr_group));
|
|
ds28e16_psy_register_err:
|
|
dev_set_drvdata(ds28e16_data->dev, NULL);
|
|
ds28e16_parse_dt_err:
|
|
kfree(ds28e16_data);
|
|
return retval;
|
|
}
|
|
|
|
static int ds28e16_remove(struct platform_device *pdev)
|
|
{
|
|
struct ds28e16_data *ds28e16_data = platform_get_drvdata(pdev);
|
|
|
|
verify_psy_unregister(ds28e16_data);
|
|
kfree(ds28e16_data);
|
|
return 0;
|
|
}
|
|
|
|
static long ds28e16_dev_ioctl(struct file *file, unsigned int cmd,
|
|
unsigned long arg)
|
|
{
|
|
ds_log("%d, cmd: 0x%x\n", __LINE__, cmd);
|
|
return 0;
|
|
}
|
|
static int ds28e16_dev_open(struct inode *inode, struct file *file)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int ds28e16_dev_release(struct inode *inode, struct file *file)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static const struct file_operations ds28e16_dev_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = ds28e16_dev_open,
|
|
.unlocked_ioctl = ds28e16_dev_ioctl,
|
|
.release = ds28e16_dev_release,
|
|
};
|
|
|
|
static const struct of_device_id ds28e16_dt_match[] = {
|
|
{.compatible = "maxim,ds28e16"},
|
|
{},
|
|
};
|
|
|
|
static struct platform_driver ds28e16_driver = {
|
|
.driver = {
|
|
.owner = THIS_MODULE,
|
|
.name = "maxim_ds28e16",
|
|
.of_match_table = ds28e16_dt_match,
|
|
},
|
|
.probe = ds28e16_probe,
|
|
.remove = ds28e16_remove,
|
|
};
|
|
|
|
static int __init ds28e16_init(void)
|
|
{
|
|
ds_log("%s entry.", __func__);
|
|
|
|
return platform_driver_register(&ds28e16_driver);
|
|
}
|
|
|
|
static void __exit ds28e16_exit(void)
|
|
{
|
|
ds_log("%s entry.", __func__);
|
|
platform_driver_unregister(&ds28e16_driver);
|
|
}
|
|
|
|
module_init(ds28e16_init);
|
|
module_exit(ds28e16_exit);
|
|
|
|
MODULE_AUTHOR("xiaomi Inc.");
|
|
MODULE_DESCRIPTION("ds28e16 driver");
|
|
MODULE_LICENSE("GPL");
|