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信息,以及数据区的访问权限。配置区图如下:

配置区图例

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命令等临时密钥。

临时密钥存储寄存器

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

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

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

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

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

2 数据传输

2.1 I2C数据传输

I2C数据通信
ATSHA204A的I2C总线通信数据格式

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

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 固定的挑战认证

固定的挑战认证方法模型
AHSHA204A加密芯片的固定挑战认证方式

3.2 随机挑战认证

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

随机挑战认证理论基础
AHSHA204A随机挑战加密图

3.3 独特的挑战认证

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

独特的挑战认证理论基础
ATSHA204A独特的挑战认证加密

3.4 多元化的密钥认证

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

多元化的固定密钥认证理论基础
ATSHA204A的多元化固定密钥认证
多元化的随机密钥验证理论基础
AHSHA204A多元化的随机密钥验证

3.5 例子

固定和随机挑战:

固定随机挑战,主机到从机
固定随机挑战,从机到主机

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

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位数据,相同则校验通过。否则,失败。

多元随机挑战

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

主机发送读取命令
主机获取从机响应
主机产生密钥
主机读取状态
主机发送MAC给从机
主机读取从机响应数据

4 命令格式

4.1 命令格式总分布图

格式总图
命令数据包格式

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

命令操作码
第一个参数param1
第二个参数param2
block的有效值

4.2 读操作

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

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

输入的指令参数

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

关于zone encoding我再贴一次图:

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><default><default><1>
si2c_sda = port:PB21<1><default><default><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的配置信息

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

.config中ATSHA的配置

5.3 驱动程序编写

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

#include <linux/delay.h>
#include <linux/uaccess.h>
#include <plat/sys_config.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/export.h>
#include <linux/module.h>

#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 <whb_xxx@sina.com>");
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
<open device ok
6>[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:~#
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,591评论 18 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,857评论 6 13
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,174评论 11 349
  • 人生苦短月似长, 拼他一拼又何妨。 万里长城连万里, 千古流芳世赞扬。
    一只路明非阅读 246评论 0 0
  • 过了穿短袖的时节,刚穿上外套没多久,就感觉薄薄的外套丝毫也不顶用,早上出门下楼时感觉还好,然而推开一楼楼道门,只感...
    风吹草折阅读 297评论 1 2