ATSHA204A加密芯片


1 特性

1 出厂带有9字节的序列号,存储在EEPROM中。
2 可以产生高质量随机数,可以作为设备的加密协议的一部分。
3 支持标准的'挑战-应答'协议。

1.1 名词

1.MAC:message authentication code。消息认证码。

1.2 设备组织

包含两个区块,分为eeprom和sram。

eeprom有664字节,分为这些区:

1.数据区

有512字节,分为16个通用功能,只读或者可读写的每个部分有32字节的内容的块。

每个块可以用来存储keys,校正数据,型号,或者其他信息。每一个块会根据配置区的的内容,有不同的访问权限。

2.配置区

有88字节,包含序列号,id信息,以及数据区的访问权限。配置区图如下:

ATSHA204A加密芯片_第1张图片
配置区图例

3 一次性编程区

有64字节,可以存储只读数据,或者单向信息。在锁住OTP区域前,需要使用标准的写命令。这里也是EEPROM的一部分。在出厂的时候,这里面的数据内容全部为1。也就是为0xffffffff。

1.3 设备上锁

有两种不同的锁:
1.锁配置区,这是通过设置LockConfig。
2.锁数据区和一次编程区,这是通过设置LockData。

上面锁的配置是在配置区,使用Lock命令来使能的。一旦上锁,就不能再开锁了。

1.4 SRAM

该芯片包含一个sram数组,可以用来存储输入命令或者输出结果,中间计算值,临时密钥等。临时密钥定义为TempKey,可以作为MAC,HMAC,CheckMAC,GenDig和DeriveKey命令的输入。也可以用来作为数据保护密钥。

1.4.1 TempKey

是一个存储寄存器,可以用来存储来自Nonce,GenDig,CheckMac或者SHA命令等临时密钥。

ATSHA204A加密芯片_第2张图片
临时密钥存储寄存器

临时密钥存储寄存器的valid位在如下情况下,会被清零:

1.上电,sleep,电压过低,看门狗超时,篡改检测。在空闲模式下,TempKey的值不消失。

2.在执行除了Nonce或者GenDig命令后,不管是否执行成功,可以使用CheckMac命令清零。除非通信错误,例如crc错误。

3.在转换的过程中出错,或者执行了GenDig或者Nonce命令。

4.执行GenDig会替换前面的Nonce命令的输出,执行Nonce命令也会替换前面的GenDig命令的输出。

2 数据传输

2.1 I2C数据传输

ATSHA204A加密芯片_第3张图片
I2C数据通信
ATSHA204A加密芯片_第4张图片
ATSHA204A的I2C总线通信数据格式

注意:
在i2c写数据包的过程中,ATSHA204A将第二个字节的数据解释为word address,来表明数据包的功能,如下图所示:

ATSHA204A加密芯片_第5张图片
word address数据包作用

2.2 I2C同步

同步过程的执行,需要执行以下步骤:
1.执行标准的i2c软件复位序列,如下:
a.start启动信号。
b.9个周期的SCL,SDA保持高电平。
c.另外一个启动信号。
d.停止信号。

发送完成以上内容之后,才可以发送读序列,如果同步已经完成,ATSHA204A就会给回应ACK。

在ATSHA204A响应了设备地址之后,系统应该复位内部地址计数器。可以通过发送word address 0x00(复位),紧随着停止条件。

2.如果设备不给响应,它有可能处在asleep状态。在这种条件下,系统应该发送完整的wake序列,然后在上升沿后等待Twhi时间。系统应该发送另外的读序列,如果同步完成,设备就会返回ACK信号。

3.如果设备仍然不回复ACK信号,它有可能处于busy状态,那么需要等待Texec时间,然后再发送读序列,这会给出响应。

3 验证类型

3.1 固定的挑战认证

ATSHA204A加密芯片_第6张图片
固定的挑战认证方法模型
ATSHA204A加密芯片_第7张图片
AHSHA204A加密芯片的固定挑战认证方式

3.2 随机挑战认证

该方式比固定挑战增加了可变信息的挑战数据。该方式可以让系统防御重放攻击方式。

ATSHA204A加密芯片_第8张图片
随机挑战认证理论基础
ATSHA204A加密芯片_第9张图片
AHSHA204A随机挑战加密图

3.3 独特的挑战认证

相比固定的挑战认证,只是在每次的请求中加上了一个特殊的挑战。该方式也能方式重放攻击。

ATSHA204A加密芯片_第10张图片
独特的挑战认证理论基础
ATSHA204A加密芯片_第11张图片
ATSHA204A独特的挑战认证加密

3.4 多元化的密钥认证

多元化的密钥认证能让主机识别特定的器件。那么就可以使用访问列表的方法。

ATSHA204A加密芯片_第12张图片
多元化的固定密钥认证理论基础
ATSHA204A加密芯片_第13张图片
ATSHA204A的多元化固定密钥认证
ATSHA204A加密芯片_第14张图片
多元化的随机密钥验证理论基础
ATSHA204A加密芯片_第15张图片
AHSHA204A多元化的随机密钥验证

3.5 例子

固定和随机挑战:

ATSHA204A加密芯片_第16张图片
固定随机挑战,主机到从机
ATSHA204A加密芯片_第17张图片
固定随机挑战,从机到主机

这种方法,理解起来,加密思路是这样的:

ATSHA204A数据区有512字节,在做加密的时候,只使用512字节的(16片区)*(32)的一个片区,也就是32字节。在做密钥匹配的时候,主机存有密钥,所以自己知道位置。ATSHA204A本身就需要主机通知了,这会塞进I2C数据里面。

1.将密钥通过PC连接器写入ATSHA204A的数据区,总共512字节,然后将芯片锁住,我们只使用了有效的32字节的密钥区。
2.将该密钥写入程序中。
3.主机给从机发送有效的7字节随机码生成请求,然后从机给主机返回数据,有效数据为32字节,该数据称为挑战码。
4.主机将32位有效挑战码发送给从机,从机内部进行计算,返回结果给主机,这个称为响应,有效数据为32字节。
5.主机按照已知的密钥,计算出结果。
6.将4生成的结果和5的结果进行比较,共32位数据,相同则校验通过。否则,失败。

多元随机挑战

多元随机挑战,挑战-响应的次数比较多,列出如下:

ATSHA204A加密芯片_第18张图片
主机发送读取命令
ATSHA204A加密芯片_第19张图片
主机获取从机响应
ATSHA204A加密芯片_第20张图片
主机产生密钥
ATSHA204A加密芯片_第21张图片
主机读取状态
ATSHA204A加密芯片_第22张图片
主机发送MAC给从机
ATSHA204A加密芯片_第23张图片
主机读取从机响应数据

4 命令格式

4.1 命令格式总分布图

ATSHA204A加密芯片_第24张图片
格式总图
ATSHA204A加密芯片_第25张图片
命令数据包格式

在ATSHA204A接收到该block数据后,会转向busy状态并试图执行命令。在busy的时候,状态或者结果都是不能读取到的。

ATSHA204A加密芯片_第26张图片
命令操作码
ATSHA204A加密芯片_第27张图片
第一个参数param1
ATSHA204A加密芯片_第28张图片
第二个参数param2
ATSHA204A加密芯片_第29张图片
block的有效值

4.2 读操作

数据区:
若数据区锁住,该命令会返回错误。否则,对应的SlotConfig将会控制访问的值。
配置区:
该区的数据是永远可读的,不管LockConfig的值是什么。
OTP区:
若OTP区没有锁住,该命令会返回错误。一旦锁住,若OTP不在传统模式,所有的数据都是可读取的。若OTP是在传统的模式,那么只有4个字节的数据可读,为0或者1的地址会返回错误。

具体固定位置的指令图如下:

ATSHA204A加密芯片_第30张图片
输入的指令参数

操作码需要为读,值为0x02。第一个参数是区域,分为3个部分。

关于zone encoding我再贴一次图:

ATSHA204A加密芯片_第31张图片
zone 编码

5 在树莓派A20上驱动程序编写

5.1 硬件配置

$ cd /home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.1/tools/sunxi-tools/
$ vi sys_config.fex

添加项目:

[atsha204_para]
atsha204_used = 1
si2c_scl = port:PB20<1><1>
si2c_sda = port:PB21<1><1>

如下图所示:

Paste_Image.png

上图将PB20,PB21配置为输出。

同时需要去掉本身自带的配置:

原来的配置

要修改为:

修改配置信息

5.2 内核配置

在/linux-sunxi/drivers/char目录下,修改Kconfig文件,添加如下内容:

config ATSHA204
    tristate "Atmel CryptoAuthentication ATSHA204A Device"
    depends on I2C
    default y
    help
      The Atmel CryptoAuthentication ATSHA204A is a full turnkey security device.
      Access to the chip is through a standard I2C interface at speeds up to 1Mb/sec.

在Makefile中添加:

obj-$(CONFIG_ATSHA204)      += atsha204.o

如下图所示:

Makefile中添加内容

然后,

$ make menuconfig 

我们能找到配置信息:

ATSHA204A加密芯片_第32张图片
添加的ATSHA204A的配置信息

在内核的根目录下的.config中能找到配置(这是内核自动添加上去的):

.config中ATSHA的配置

5.3 驱动程序编写

将驱动程序命名为atsha204.c,然后编辑内容,最后将文件放在linux-sunxi/drivers/char目录下,驱动程序内容为:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define ATSHA204_DEBUG

#ifdef ATSHA204_DEBUG
#define atsha204_debug(fmt, ...) printk(KERN_INFO "[ATSHA204][BUG][%d]"fmt, __LINE__, ##__VA_ARGS__)
#else
#define atsha204_debug(fmt, ...)
#endif /* ATSHA204_DEBUG */

#define atsha204_error(fmt, ...) printk(KERN_INFO "[ATSHA204][ERR]"fmt"\n", ##__VA_ARGS__)

#define DRV_NAME "atsha204"

//! maximum size of command packet (CheckMac)
#define ATSHA204_CMD_SIZE_MAX          ((u8) 84)

//!< maximum size of response packet
#define ATSHA204_RSP_SIZE_MAX          ((u8) 35)

#define SLAVE_ADDR_DEFAULT  (0xC8 >> 1)

#define ATSHA204_CMD_MAGIC          'S'
#define ATSHA204_CMD_GET_SLAVE_ADDR _IOR(ATSHA204_CMD_MAGIC, 0, u8)
#define ATSHA204_CMD_SET_SLAVE_ADDR _IOW(ATSHA204_CMD_MAGIC, 1, u8)
#define ATSHA204_CMD_WAKEUP         _IOR(ATSHA204_CMD_MAGIC, 2, u8[4])

#define SCL_DELAY_US    5
#define SDA_DELAY_US    (SCL_DELAY_US - 1)
#define IDLE_DELAY_US   (SDA_DELAY_US / 2)

enum PinDirections {
    PIN_IN,
    PIN_OUT,
};

//SI2C管脚ID,与si2c_pin_name对应
enum SI2C_PinNameId {
    SI2C_PIN_SCL,
    SI2C_PIN_SDA,
};

#define SI2C_PIN_NAME_SCL "si2c_scl"
#define SI2C_PIN_NAME_SDA "si2c_sda"
static const u8 *si2c_pin_name[] = {SI2C_PIN_NAME_SCL, SI2C_PIN_NAME_SDA};

struct atsha204info {
    u8 slave_addr;
    unsigned int gpio_handle;
    struct miscdevice misc;
};

struct atsha204_write_data {
    u8 command;
    u8 length;
    u8 data[ATSHA204_CMD_SIZE_MAX];
};

static struct atsha204info atsha204_info = {.slave_addr = SLAVE_ADDR_DEFAULT};

/* Set pin direction -> out (mul_sel = 1), pin_data -> value */
static int atsha204_gpio_set_direction(const u32 p_handle, const enum SI2C_PinNameId pin_name_id, const enum PinDirections dire, int value)
{
    int ret;

    if ((p_handle == 0) || ((pin_name_id < SI2C_PIN_SCL) && (pin_name_id > SI2C_PIN_SDA))) {
        atsha204_error("[%s]parameter invalid", __FUNCTION__);

        return -1;
    }
    
    if (dire == PIN_IN) {
        ret =  gpio_set_one_pin_io_status(p_handle, PIN_IN, si2c_pin_name[pin_name_id]);
        if (ret < 0) {
            atsha204_error("gpio_set_one_pin_io_status error");

            return -1;
        }
    } else {
        ret =  gpio_set_one_pin_io_status(p_handle, PIN_OUT, si2c_pin_name[pin_name_id]);
        if (ret < 0) {
            atsha204_error("gpio_set_one_pin_io_status error");

            return -1;
        }

        ret = gpio_write_one_pin_value(p_handle, (value == 0) ? 0 : 1, si2c_pin_name[pin_name_id]);
        if (ret < 0) {
            atsha204_error("gpio_write_one_pin_value error");

            return -1;
        }
    }

    return 0;
}

/* Get gpio pin value */
static int atsha204_gpio_get_value(const u32 p_handle, const enum SI2C_PinNameId pin_name_id)
{
    if ((p_handle == 0) || ((pin_name_id < SI2C_PIN_SCL) && (pin_name_id > SI2C_PIN_SDA))) {
        atsha204_error("[%s]parameter invalid", __FUNCTION__);

        return -1;
    }
    
    return gpio_read_one_pin_value(p_handle, si2c_pin_name[pin_name_id]);
}

/* Set pin value (output mode) */
static int atsha204_gpio_set_value(const u32 p_handle, const enum SI2C_PinNameId pin_name_id, int value)
{
    if ((p_handle == 0) || ((pin_name_id < SI2C_PIN_SCL) && (pin_name_id > SI2C_PIN_SDA))) {
        atsha204_error("[%s]parameter invalid", __FUNCTION__);

        return -1;
    }

    return gpio_write_one_pin_value(p_handle, (value == 0) ? 0 : 1, si2c_pin_name[pin_name_id]);
}

#define SDA_IN()            atsha204_gpio_set_direction(atsha204_info.gpio_handle, SI2C_PIN_SDA, PIN_IN, 0)
#define SDA_OUT()           atsha204_gpio_set_direction(atsha204_info.gpio_handle, SI2C_PIN_SDA, PIN_OUT, 1)
#define SCL_SET(BitVal)     atsha204_gpio_set_value(atsha204_info.gpio_handle, SI2C_PIN_SCL, BitVal)
#define SDA_SET(BitVal)     atsha204_gpio_set_value(atsha204_info.gpio_handle, SI2C_PIN_SDA, BitVal)
#define SDA_GET()           atsha204_gpio_get_value(atsha204_info.gpio_handle, SI2C_PIN_SDA)

/*
 * @brief SI2C起始信号
 */
static void SI2C_Start(void)
{
    SDA_OUT();
    SDA_SET(1);
    udelay(SDA_DELAY_US);
    
    SCL_SET(1);
    udelay(SCL_DELAY_US);
    
    SDA_SET(0);
    udelay(SDA_DELAY_US);
    
    SCL_SET(0);
    udelay(SCL_DELAY_US);
}

/*
 * @brief SI2C结束信号
 */
static void SI2C_Stop(void)
{
    SDA_OUT();
    SDA_SET(0);
    udelay(SDA_DELAY_US);
    
    SCL_SET(1);
    udelay(SCL_DELAY_US);
    
    SDA_SET(1);
    udelay(SDA_DELAY_US);
    
    SCL_SET(0);
    udelay(SCL_DELAY_US);
}

/*
 * @brief SI2C应答信号
 */
static void SI2C_Ack(void)
{
    SCL_SET(0);
    udelay(SCL_DELAY_US);
    
    SDA_OUT();
    SDA_SET(1);
    udelay(SDA_DELAY_US);
    
    SDA_SET(0);
    udelay(SDA_DELAY_US);
    
    SCL_SET(1);
    udelay(SCL_DELAY_US);
    
    SCL_SET(0);
    udelay(SCL_DELAY_US);
    
    SDA_SET(1);
    udelay(SDA_DELAY_US);
}

/*
 * @brief SI2C非应答信号
 */
static void SI2C_NAck(void)
{
    SCL_SET(0);
    udelay(SCL_DELAY_US);
    
    SDA_OUT();
    SDA_SET(1);
    udelay(SDA_DELAY_US);
    
    SCL_SET(1);
    udelay(SCL_DELAY_US);
    
    SCL_SET(0);
    udelay(SCL_DELAY_US);
}

/*
 * @brief SI2C等待从设备响应信号
 */
static int SI2C_Wait_Ack(void)
{
    uint8_t is_time_out = 0;
    
    SCL_SET(0);
    udelay(SCL_DELAY_US);
    
    SDA_IN();
    
    while (SDA_GET() != 0)
    {
        ++is_time_out;
        if (is_time_out > 250)
        {
            SI2C_Stop();
            
            return -1;
        }
    }
    
    SCL_SET(1);
    udelay(SCL_DELAY_US);
    
    SCL_SET(0);
    udelay(SCL_DELAY_US);
    
    return 0;
}

/*
 * @brief SI2C Send Byte
 */
static int SI2C_Send_Byte(u8 TxByte)
{
    u8 i = 0;
    
    SDA_OUT();
    
    SCL_SET(0);
    udelay(SCL_DELAY_US);
    
    for (i = 0; i < 8; ++i)
    {
        if (TxByte & 0x80)
        {
            SDA_SET(1);
        }
        else
        {
            SDA_SET(0);
        }
        
        TxByte <<= 1;
        udelay(SDA_DELAY_US);
        
        SCL_SET(1);
        udelay(SCL_DELAY_US);
        
        SCL_SET(0);
        udelay(SCL_DELAY_US);
    }
    

    if (SI2C_Wait_Ack() != 0)
    {
        //此处必须有延时,不然会出错,至少延时1ms,由于只有出
        //错才会进入此处(次数少),可以多延时一点,取5ms
    //  udelay(5000);
        msleep(5000 / 1000);
        
        SI2C_Stop();
        
        return -1;
    }
    
    return 0;
}

/*
 * @brief SI2C Recv Byte
 */
static u8 SI2C_Recv_Byte(void)
{
    u8 i = 0;
    u8 recv = 0;
    
    SDA_IN();
    
    for (i = 0; i < 8; ++i)
    {
        SCL_SET(0);
        udelay(SCL_DELAY_US);
        
        SCL_SET(1);
        udelay(SCL_DELAY_US);
        
        recv <<= 1;
        if (SDA_GET())
        {
            ++recv;
        }
    }
    
    SI2C_Ack();
    udelay(IDLE_DELAY_US);
    
    return recv;
}


/*
 *以下部分是与ATSHA204A相关的接口,它并非标准的I2C协议,需要重新实现读写
 */

/*
 * @brief SI2C send many byte
 */
static int SI2C_Send_Bytes(u8 *TxBytes, u8 TxByteCount)
{
    u8 i = 0;
    u8 data = 0;
    
    SDA_OUT();
    
    SCL_SET(0);
    udelay(SCL_DELAY_US);
    
    for (i = 0; i < TxByteCount; ++i)
    {
        data = TxBytes[i];
        if (SI2C_Send_Byte(data) != 0)
        {
            SI2C_Stop();
            
            return -1;
        }
    }
    
    return 0;
}

/*
 * @brief SI2C recv many byte
 */
static void SI2C_Recv_Bytes(u8 *RxBytes, u8 RxByteCount)
{
    u8 i = 0;

    for (i = 0; i < RxByteCount - 1; ++i)
    {
    //  udelay(IDLE_DELAY_US);
        RxBytes[i] = SI2C_Recv_Byte();
    }
    
    RxBytes[i] = SI2C_Recv_Byte();
    SI2C_NAck();
}

/*
 * @brief SI2C SHA204A Wakeup
 */
static void SI2C_SHA204A_Wake(void)
{
    SI2C_Start();
    udelay(85);
    
    SI2C_Send_Byte(0x00);
    udelay(60);
    SI2C_Stop();
//  udelay(3800);
    msleep(4);
}

/*
 * @brief SI2C Read many byte from slave device
 */
static int SI2C_SHA204A_Read(u8 *RxBytes, u8 RxByteLength)
{
    u8 count = 0;
    
    SI2C_Start();
    if (SI2C_Send_Byte(((atsha204_info.slave_addr) << 1) + 1) != 0)
    {
    //  SI2C_Stop();
        atsha204_error("1.send err");
        
        return -1;
    }

    //read count byte
    count = SI2C_Recv_Byte();
    if ((count < 4) || (count > RxByteLength))
    {
        atsha204_error("2.[%d]count err", count);
        return -1;
    }
    
    RxBytes[0] = count;
    
    SI2C_Recv_Bytes(&RxBytes[1], count - 1);
    
    SI2C_Stop();
    
    return 0;
}

/*
 * @brief SI2C Write many byte from slave device
 */
static int SI2C_SHA204A_Write(u8 WordAddress, u8 *TxBytes, u8 TxByteLength)
{
    int ret = 0;
    
    SI2C_Start();
    if (SI2C_Send_Byte((atsha204_info.slave_addr) << 1) != 0)
    {
        SI2C_Stop();
        
        return -1;
    }
    
    //write WordAddress(data type)
    if (SI2C_Send_Bytes(&WordAddress, 1) != 0)
    {
        return -1;
    }
    
    if (TxByteLength == 0) {
        // We are done for packets that are not commands (Sleep, Idle, Reset).
        SI2C_Stop();
        
        return 0;
    }
    
    ret = SI2C_Send_Bytes(TxBytes, TxByteLength);
    SI2C_Stop();
    
    return ret;
}


//唤醒atsha204芯片至唤醒模式
static int atsha204_wakeup(u8 *response)
{
    u8 read_buf[4] = {0};
    
    SI2C_SHA204A_Wake();
    if (SI2C_SHA204A_Read(read_buf, sizeof(read_buf)) < 0) {
        atsha204_error("SI2C_SHA204A_Read error");

        return -1;
    } else {
        if (copy_to_user(response, read_buf, sizeof(read_buf)) != 0) {
            atsha204_error("[%s]copy_to_user error", __FUNCTION__);

            return -1;
        }

        return 0;
    }
}

static int atsha204_open(struct inode *inode, struct file *file)
{
    return 0;
}

static int atsha204_close(struct inode *inode, struct file *file)
{
    return 0;
}

static ssize_t atsha204_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
    u8 read_buf[ATSHA204_RSP_SIZE_MAX] = {0};
    int len = 0;

    if (count > ATSHA204_RSP_SIZE_MAX) {
        return -1;
    }

    if (SI2C_SHA204A_Read(read_buf, count) < 0) {
        atsha204_error("SI2C_SHA204A_Read error");

        return -1;
    } else {
        len = read_buf[0];
        if (copy_to_user(buf, read_buf, len) != 0) {
            atsha204_error("[%s]copy_to_user error", __FUNCTION__);

            return -1;
        }

        return len;
    }
}

static ssize_t atsha204_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
    struct atsha204_write_data data_tmp = {0};
    u8 len = 0;

    if (copy_from_user(&data_tmp, buf, sizeof(struct atsha204_write_data)) != 0) {
        atsha204_error("copy_from_user error");

        return -1;
    }
    
    atsha204_debug("command:%d, length:%d, count=%d\n", data_tmp.command, data_tmp.length, count);

    len = (ATSHA204_CMD_SIZE_MAX > data_tmp.length) ? data_tmp.length : ATSHA204_CMD_SIZE_MAX;

    //write data address(data type) 
    if (SI2C_SHA204A_Write(data_tmp.command, data_tmp.data, len) < 0) {
        atsha204_error("SI2C_SHA204A_Write error");

        return -1;
    }

    return len;
}

static long atsha204_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    atsha204_debug("cmd = %d, type:%c\n", cmd, _IOC_TYPE(cmd));

    if (_IOC_TYPE(cmd) != ATSHA204_CMD_MAGIC)
        return -1;
    
    if (cmd == ATSHA204_CMD_GET_SLAVE_ADDR) {
        if (copy_to_user((u8 *)arg, &atsha204_info.slave_addr, sizeof(u8)) != 0) {
            atsha204_error("[%s]copy_to_user error", __FUNCTION__);

            return -1;
        }
        
        return 0;
    } else if (cmd == ATSHA204_CMD_SET_SLAVE_ADDR) {
        if (copy_from_user(&atsha204_info.slave_addr, (u8 *)arg, sizeof(u8)) != 0) {
            atsha204_error("copy_from_user error");

            return -1;
        }
        
        return 0;
    } else if (cmd == ATSHA204_CMD_WAKEUP) {
        return atsha204_wakeup((u8 *)arg);
    } else {
        return -1;
    }
    
}

static const struct file_operations atsha204_fops = {
    .owner              = THIS_MODULE,
    .open               = atsha204_open,
    .release            = atsha204_close,
    .unlocked_ioctl     = atsha204_ioctl,
    .read      = atsha204_read,
    .write     = atsha204_write,
};

static int __init atsha204_init(void)
{
    int atsha204_used = 0;
    int ret = 0;
    struct miscdevice *misc = &atsha204_info.misc;

    atsha204_debug("atsha204  driver init\n");

    atsha204_debug("Addr:0x%X\n", atsha204_info.slave_addr);
    
    ret = script_parser_fetch("atsha204_para", "atsha204_used", &atsha204_used, sizeof(atsha204_used)/sizeof(int));
    if (ret) {
        /* Not error - just info */
        atsha204_error("can't find script data '[atsha204_para]' 'atsha204_used'\n");

        return -1;
    }

    if (!atsha204_used) {
        atsha204_error("atsha204_used is false. Skip atsha204 initialization\n");

        return -1;
    }

    atsha204_info.gpio_handle= gpio_request_ex("atsha204_para", NULL);
    if(!atsha204_info.gpio_handle) {
        atsha204_error("atsha204_para request gpio fail!\n");
        
        return -1;
    }

    if (gpio_set_one_pin_io_status(atsha204_info.gpio_handle, 1, "si2c_scl") < 0) {
        atsha204_error("set si2c_scl gpio output fail!\n");
        
        return -1;
    }

    if (gpio_set_one_pin_io_status(atsha204_info.gpio_handle, 1, "si2c_sda") < 0) {
        atsha204_error("set si2c_scl gpio output fail!\n");
        
        return -1;
    }

    
//-----------------------------------
    misc->minor = MISC_DYNAMIC_MINOR;
    misc->name = DRV_NAME;
    misc->fops = &atsha204_fops;
    ret = misc_register(misc);
    if (ret) {
        atsha204_error("Unable to register a misc device\n");

        return -1;
    }
    atsha204_debug("Register a misc device Ok\n");


    return ret;
}

static void __exit atsha204_exit(void)
{
    struct miscdevice *misc = &atsha204_info.misc;

    atsha204_debug("In %s\n", __FUNCTION__);

    gpio_release(atsha204_info.gpio_handle, 2);
    
    misc_deregister(misc);

    return;
}

module_init(atsha204_init);
module_exit(atsha204_exit);

MODULE_AUTHOR("peace ");
MODULE_DESCRIPTION("Atmel CryptoAuthentication driver for atsha204A");
MODULE_LICENSE("GPL");

注册的是misc设备类,所以在开发板下能找到:

root@marsboard:~# ls /sys/class/misc/
ashmem    cachefiles       fuse        log_system          rfkill
atsha204  cpu_dma_latency  log_events  loop-control
autofs    cuse             log_main    network_latency
binder    device-mapper    log_radio   network_throughput
root@marsboard:~# 
root@marsboard:~# ls /dev/atsha204 
/dev/atsha204
root@marsboard:~# 
root@marsboard:~# ./sha204_test 
ATSHA204 Test
[ATSHA204][BUG][547]cmd = -2147200254, type:S
<6>[ATSHA204][ERR]1.send err
<6>[ATSHA204][ERR]SI2C_SHA204A_Read error
ioctl error: Operation not permitted
[TEST][ERR][53]sha204c_wakeup error
[ATSHA204][ERR][156]write error
[TEST][ERR][80]sha204c_sleep error
Error, Quit
root@marsboard:~#

你可能感兴趣的:(ATSHA204A加密芯片)