五 . 樹莓派A20 I2C驅(qū)動程序


1 參考資料

1.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\input\touchscreen\Gt818_ts.c
2.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-core.c
3.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\include\linux\I2c.h
4.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-dev.c提供應(yīng)用層接口
5.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\I2c-core.c提供核心層文件
6.\marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\i2c\busses\I2c-sunxi.c提供底層硬件驅(qū)動

1.1 I2C框架總圖

I2C框架總圖

2 I2C接口

2.1 函數(shù)接口

/*注冊驅(qū)動*/
#define i2c_add_driver(driver) \
    i2c_register_driver(THIS_MODULE, driver)
/*注銷驅(qū)動*/
void i2c_del_driver(struct i2c_driver *driver)
/*承載實際的數(shù)據(jù)傳輸*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

2.2 結(jié)構(gòu)體

struct i2c_board_info {
    char        type[I2C_NAME_SIZE];
    unsigned short  flags;
    unsigned short  addr;
    void        *platform_data;
    struct dev_archdata *archdata;
    struct device_node *of_node;
    int     irq;
};
struct i2c_client {
    unsigned short flags;       /* div., see below      */
    unsigned short addr;        /* chip address - NOTE: 7bit    */
                    /* addresses are stored in the  */
                    /* _LOWER_ 7 bits       */
    char name[I2C_NAME_SIZE];
    struct i2c_adapter *adapter;    /* the adapter we sit on    */
    struct i2c_driver *driver;  /* and our access routines  */
    struct device dev;      /* the device structure     */
    int irq;            /* irq issued by device     */
    struct list_head detected;
};
struct i2c_driver {
    unsigned int class;

    /* Notifies the driver that a new bus has appeared or is about to be
     * removed. You should avoid using this, it will be removed in a
     * near future.
     */
    int (*attach_adapter)(struct i2c_adapter *) __deprecated;
    int (*detach_adapter)(struct i2c_adapter *) __deprecated;

    /* Standard driver model interfaces */
    int (*probe)(struct i2c_client *, const struct i2c_device_id *);
    int (*remove)(struct i2c_client *);

    /* driver model interfaces that don't relate to enumeration  */
    void (*shutdown)(struct i2c_client *);
    int (*suspend)(struct i2c_client *, pm_message_t mesg);
    int (*resume)(struct i2c_client *);

    /* Alert callback, for example for the SMBus alert protocol.
     * The format and meaning of the data value depends on the protocol.
     * For the SMBus alert protocol, there is a single bit of data passed
     * as the alert response's low bit ("event flag").
     */
    void (*alert)(struct i2c_client *, unsigned int data);

    /* a ioctl like command that can be used to perform specific functions
     * with the device.
     */
    int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

    struct device_driver driver;
    const struct i2c_device_id *id_table;

    /* Device detection callback for automatic device creation */
    int (*detect)(struct i2c_client *, struct i2c_board_info *);
    const unsigned short *address_list;
    struct list_head clients;
};
struct i2c_device_id {
    char name[I2C_NAME_SIZE];
    kernel_ulong_t driver_data  /* Data private to the driver */
            __attribute__((aligned(sizeof(kernel_ulong_t))));
};

3 硬件原理圖

使用風火輪出品的DVK521底板隅熙,其I2C硬件原理圖如下所示:


I2C接口

找到數(shù)據(jù)手冊中對應(yīng)引腳描述:


I2C引腳描述

從這里可以看出县袱,使用的是i2c1接口辉阶。

我在i2c1上外接的是FM24CL16芯片,該芯片容量為2KB晓殊。從機地址按照下圖所示:


image.png

該模組鏈接地址為: 鏈接
原理圖鏈接地址為: 鏈接

也就是如下圖所示:

I2C模組圖
原理圖

按照上圖,我們將短接帽設(shè)置在0上,也就是接地尔许。那么,訪問該芯片的地址就為0x50终娃。

這里就直接給出一個測試例程:

#include <stdio.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <string.h>  
#include <linux/i2c.h>  
#include <linux/i2c-dev.h>   

#define SLAVE_ADDRESS 0x50 //FM24CL16芯片地址為0x50
#define I2C_DEV "/dev/i2c-1"http://i2c_dev為i2c adapter創(chuàng)建的別名  
//讀操作先發(fā)Slaveaddr_W+Regaddr_H+Regaddr_L 3個字節(jié)來告訴設(shè)備操作器件及兩個byte參數(shù)  
//然后發(fā)送Slaveaddr_R讀數(shù)據(jù)  
static int iic_read(int fd, char buff[], int addr, int count)  
{  
    int res;  
    char sendbuffer1[2];  
    //sendbuffer1[0]=addr>>8;  
    //sendbuffer1[1]=addr;  
    sendbuffer1[0]=addr;

    write(fd,sendbuffer1,1);        
    res=read(fd,buff,count);  
    //printf("read %d byte at 0x%x\n", res, addr);  
    return res;  
} 

//在寫之前味廊,在數(shù)據(jù)前加兩個byte的參數(shù),根據(jù)需要解析  
static int iic_write(int fd, char buff[], int addr, int count)  
{  
    int res;
    int i,n;
    char sendbuffer[2048+3];  
    memcpy(sendbuffer+1, buff, count);  
    sendbuffer[0]=addr;  
    res=write(fd,sendbuffer,count+1);  
    //printf("write %d byte at 0x%x\n", res, addr);  
}  

unsigned char wbuf1[2048];
unsigned char wbuf2[2048];
unsigned char wbuf3[2048];
unsigned char wbuf4[2048];
unsigned char wbuf5[2048];
unsigned char wbuf6[2048];
unsigned char wbuf7[2048];
unsigned char wbuf8[2048];

unsigned char rbuf[2048];

int main(void){  
    int fd;  
    int res;  
    char ch;  
 
    char buf[50];  
    int regaddr,i,slaveaddr;  
    fd = open(I2C_DEV, O_RDWR);// I2C_DEV /dev/i2c-0  
    if(fd < 0){  
        printf("####i2c test device open failed####\n");  
        return -1;  
    }

    if(ioctl(fd,I2C_TENBIT,0)<0)
    {
        printf("---set i2c bit error---\r\n");
        return -1;
    }

    if(ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS)<0)
    {
        printf("--set i2c address error---\r\n");
        return -1;
    }
    
    /*write data as 512Bytes once*/
    for(i = 0 ; i < 256 ; i ++)
    {
        wbuf1[i] = i;   
        wbuf2[i] = 255-i;   
        wbuf3[i] = i%256;   
        wbuf4[i] = 255-i;   
        wbuf5[i] = i%256;   
        wbuf6[i] = 255-i;   
        wbuf7[i] = i%256;   
        wbuf8[i] = 255-i;   
    }

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+0); 
    iic_write(fd,wbuf1,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+1);
    iic_write(fd,wbuf2,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+2);
    iic_write(fd,wbuf3,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+3);
    iic_write(fd,wbuf4,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+4);
    iic_write(fd,wbuf5,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+5);
    iic_write(fd,wbuf6,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+6);
    iic_write(fd,wbuf7,0,256); 
    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+7);
    iic_write(fd,wbuf8,0,256); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS);
    iic_read(fd,rbuf,0,256); 
    printf("read page 0:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 


    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+1);
    iic_read(fd,rbuf,0,256); 
    printf("read page 1:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 


    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+2);
    iic_read(fd,rbuf,0,256); 
    printf("read page 2:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+3);
    iic_read(fd,rbuf,0,256); 
    printf("read page 3:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 


    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+4);
    iic_read(fd,rbuf,0,256); 
    printf("read page 4:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+5);
    iic_read(fd,rbuf,0,256); 
    printf("read page 5:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+6);
    iic_read(fd,rbuf,0,256); 
    printf("read page 6:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    ioctl(fd,I2C_SLAVE,SLAVE_ADDRESS+7);
    iic_read(fd,rbuf,0,256); 
    printf("read page 7:\r\n");
    for(i = 0 ; i <256 ; i ++)
    {
        printf("0x%0x ",rbuf[i]);
    }
    printf("\r\n"); 

    return 0;  
}  

在程序編寫上,需要著重注意的是訪問的寄存器地址余佛。由于我們的地址是8位的柠新,所以,訪問256B后面的數(shù)據(jù)辉巡,都是要兩個以上的字節(jié)了恨憎,這個時候,我們就要用上內(nèi)部的訪問地址了郊楣。

簡單的講憔恳,就是要變換page。

4 通過I2C驅(qū)動ZLG7290前面板

4.1 sys_config.fex文件的配置

配置內(nèi)容為:

[twi4_para]
twi4_used = 1
twi4_scl = port:PI02<3><default><default><default>
twi4_sda = port:PI03<3><default><default><default>
twi4配置

4.2 修改Kconfig和Makefile文件

在linux-sunxi/drivers/input/misc/目錄下净蚤,修改Kconfig內(nèi)容:

config INPUT_I2C7290
    tristate "I2C7290 Keyboard device"
    depends on I2C
    help
     Say Y here if you want to support a keypad connected via I2C
     with a ZLG7290(bad design by xxx).
     To compile this driver as a module, choose M here: the
     module will be called ZLG7290_keypad.

然后修改該目錄下的Makefile文件:

obj-$(CONFIG_INPUT_I2C7290)     += keyboard_i2c7290.o

然后:

$ make menuconfig 
選中I2C7290

在linux-sunxi/drivers/input/misc/目錄下钥组,編寫keyboard_i2c7290.c文件,內(nèi)容如下:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/uaccess.h>

//#define KEYBOARD_I2C7290_DEBUG

#ifdef KEYBOARD_I2C7290_DEBUG
#define keyboard_i2c7290_debug(fmt, ...) printk(KERN_INFO "[KEYBOARD_I2C7290][BUG][%d]"fmt, __LINE__, ##__VA_ARGS__)
#else
#define keyboard_i2c7290_debug(fmt, ...)
#endif /* KEYBOARD_I2C7290_DEBUG */

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

#define DRV_NAME "keyboard_i2c7290"

#define ZLG7290_SystemReg   0x00
#define ZLG7290_Key         0x01
#define ZLG7290_RepeatCnt   0x02
#define ZLG7290_FunctionKey 0x03
#define ZLG7290_CmdBuf      0x07
#define ZLG7290_CmdBuf0     0x07
#define ZLG7290_CmdBuf1     0x08
#define ZLG7290_FlashOnOff  0x0C
#define ZLG7290_ScanNum     0x0D
#define ZLG7290_DpRam       0x10
#define ZLG7290_DpRam0      0x10
#define ZLG7290_DpRam1      0x11
#define ZLG7290_DpRam2      0x12
#define ZLG7290_DpRam3      0x13
#define ZLG7290_DpRam4      0x14
#define ZLG7290_DpRam5      0x15
#define ZLG7290_DpRam6      0x16
#define ZLG7290_DpRam7      0x17

#define LED_ONOFF_CMD   0x01
#define LED_ON_MASK     0x80
#define LED_OFF_MASK        0x7F

#define LED_ON_CMD_U16(led_id)  (((((u16)(led_id | LED_ON_MASK)) << 8) | LED_ONOFF_CMD))
#define LED_OFF_CMD_U16(led_id) (((((u16)(led_id & LED_OFF_MASK)) << 8) | LED_ONOFF_CMD))

#define LED_IOCTL_ON        0
#define LED_IOCTL_OFF   1

#define I2C_DELAY_MS        2

struct UserKeyDataStru {
    unsigned int key_state : 8;     //按鍵狀態(tài)[1:有鍵按下,0:沒有按鍵按下(或功能鍵,此處不用)]
    unsigned int key : 8;           //按鍵鍵值
    unsigned int repeat : 8;        //連擊計數(shù)器
    unsigned int reserved : 8;      //預留
};

struct KeyboardI2C7290DataStru {
    char *name;
    struct i2c_client *client;
    struct miscdevice misc;
};

//LED與按鍵的對應(yīng)關(guān)系定義
typedef struct LedAndKeyInfoStru {
    unsigned char key;
    unsigned char led_id;
}LedAndKeyInfoStru_t;

struct KeyboardI2C7290DataStru kb = {.name = DRV_NAME};

const LedAndKeyInfoStru_t led_and_key[] = {
//  {.key = 1, .led_id = 0},
//  {.key = 2, .led_id = 8},
//  {.key = 3, .led_id = 16},
//  {.key = 4, .led_id = 24},
    {.key = 28, .led_id = 32},
    {.key = 27, .led_id = 40},
    {.key = 26, .led_id = 48},
    {.key = 25, .led_id = 56},
    {.key = 20, .led_id = 56},
    {.key = 19, .led_id = 4},
    {.key = 18, .led_id = 20},
    {.key = 5, .led_id = 24},
};

static int I2C_Gets(struct i2c_client *client, unsigned int SubAddr, char *dat)
{
    i2c_smbus_write_byte(client, SubAddr);

    *dat = (char)(0xFF & i2c_smbus_read_byte(client));

    return 0;
}

static int read_system_reg(struct KeyboardI2C7290DataStru *kb)
{
    char c = '\0';

    I2C_Gets(kb->client, ZLG7290_SystemReg, &c);

    return (int)(c & 0x01);
}

static int read_key(struct KeyboardI2C7290DataStru *kb)
{
    char c = '\0';

    I2C_Gets(kb->client, ZLG7290_Key, &c);

    return (int)c;
}

static int read_repeat_reg(struct KeyboardI2C7290DataStru *kb)
{
    char c = '\0';

    I2C_Gets(kb->client, ZLG7290_RepeatCnt, &c);

    return (int)c;
}

static void led_on(unsigned char key)
{
    int i = 0;
    u16 value = 0;

    for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
        if (led_and_key[i].key == key) {
            value = LED_ON_CMD_U16(led_and_key[i].led_id);
            i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
            keyboard_i2c7290_debug("value = 0x%04X\n", value);
        }
    }
}

static void led_off(unsigned char key)
{
    int i = 0;
    u16 value = 0;

    for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
        if (led_and_key[i].key == key) {
            value = LED_OFF_CMD_U16(led_and_key[i].led_id);
            i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
            keyboard_i2c7290_debug("value = 0x%04X\n", value);
        }
    }
}

static void led_off_all(void)
{
    int i = 0;
    u16 value = 0;

    for (i = 0; i < sizeof(led_and_key) / sizeof(LedAndKeyInfoStru_t); ++i) {
        value = LED_OFF_CMD_U16(led_and_key[i].led_id);
        i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
    //  keyboard_i2c7290_debug("value = 0x%04X\n", value);
        mdelay(I2C_DELAY_MS);
    }
}

static int keyboard_i2c7290_open(struct inode *inode, struct file *file)
{
    u16 value = 0;

    //關(guān)閉LED閃爍顯示
    value = 0x0070;
    i2c_smbus_write_word_data(kb.client, ZLG7290_CmdBuf, value);
    mdelay(I2C_DELAY_MS);

    led_off_all();

    return 0;
}

static int keyboard_i2c7290_close(struct inode *inode, struct file *file)
{
    led_off_all();

    return 0;
}

static ssize_t keyboard_i2c7290_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
    struct UserKeyDataStru user_data = {0};

    user_data.key_state = read_system_reg(&kb);
    if (user_data.key_state == 0) {
        //沒有鍵按下
    } else {
        mdelay(I2C_DELAY_MS);

        user_data.key = (unsigned char)read_key(&kb);
        mdelay(I2C_DELAY_MS);

        user_data.repeat = read_repeat_reg(&kb);
    }
#if 0
    keyboard_i2c7290_debug("SysReg:%d\n", user_data.key_state);
    keyboard_i2c7290_debug("KEY: %d\n", user_data.key);
    keyboard_i2c7290_debug("Repeat: %d\n", user_data.repeat);
#endif
    if (copy_to_user(buf, (const void *)&user_data, sizeof(struct UserKeyDataStru)) == 0) {
        //Empty
    }

    return sizeof(struct UserKeyDataStru);
}

static long keyboard_i2c7290_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned char key =  *((unsigned char *)arg);

    keyboard_i2c7290_debug("Cmd: %d, Key: %d\n", cmd, (unsigned int)key);
    switch (cmd) {
    case LED_IOCTL_ON:
        led_on(key);
        break;
    case LED_IOCTL_OFF:
        led_off(key);
        break;
    default:
        break;
    }

    return 0;
}

static const struct file_operations keyboard_i2c7290_fops = {
    .owner              = THIS_MODULE,
    .open               = keyboard_i2c7290_open,
    .release            = keyboard_i2c7290_close,
    .unlocked_ioctl     = keyboard_i2c7290_ioctl,
    .read      = keyboard_i2c7290_read,
//  .write     = keyboard_i2c7290_write,
};

static int keyboard_i2c7290_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
    struct miscdevice *misc = NULL;
    
    keyboard_i2c7290_debug("In %s\n", __FUNCTION__);

    keyboard_i2c7290_debug("Addr:0x%X, name:%s\n", client->addr, id->name);

    kb.client = client;

    misc = &kb.misc;
    misc->minor = MISC_DYNAMIC_MINOR;
    misc->name = DRV_NAME;
    misc->fops = &keyboard_i2c7290_fops;
    ret = misc_register(misc);
    if (ret) {
        keyboard_i2c7290_error("Unable to register a misc device\n");

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


    return ret;
}

static int keyboard_i2c7290_remove(struct i2c_client *client)
{
    struct miscdevice *misc = NULL;

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

    misc = i2c_get_clientdata(client);

    free_irq(client->irq, misc);
    misc_deregister(misc);


    return 0;
}

static const struct i2c_device_id keyboard_i2c7290_id[] = {
    {DRV_NAME, 0},
    { },
};

MODULE_DEVICE_TABLE(i2c, keyboard_i2c7290_id);

static struct i2c_driver keyboard_i2c7290_driver = {
    .driver = {
        .name   = DRV_NAME,
        .owner  = THIS_MODULE,
    },
    .probe      = keyboard_i2c7290_probe,
    .remove     = keyboard_i2c7290_remove,
    .id_table   = keyboard_i2c7290_id,
};

/*added by wit_yuan 2017-08-11*/
static struct i2c_board_info __initdata bfin_i2c_board_info4[] = {
#if defined(CONFIG_INPUT_I2C7290)
    {
        I2C_BOARD_INFO("keyboard_i2c7290", 0x38),
    //  .irq = IRQ_PE15,
    },
#endif
};


static int __init keyboard_i2c7290_init(void)
{
    printk("------keyboard_i2c7290_init----\r\n");
    i2c_register_board_info(4, bfin_i2c_board_info4, ARRAY_SIZE(bfin_i2c_board_info4));
    return 0;
}

static void __exit keyboard_i2c7290_exit(void)
{

    return ;
}


module_init(keyboard_i2c7290_init);
module_exit(keyboard_i2c7290_exit);



module_i2c_driver(keyboard_i2c7290_driver);

MODULE_AUTHOR("peace <whb_xxx@sina.com>");
MODULE_DESCRIPTION("Keyboard driver for I2c7290");
MODULE_LICENSE("GPL");

在樹莓派A20上查看是否有keyboard_i2c7290設(shè)備:

root@marsboard:~# ls /dev/keyboard_i2c7290
/dev/keyboard_i2c7290

到這一步今瀑,就可以寫測試程序keyTest.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>

#define KEY_DEV "/dev/keyboard_i2c7290"

struct UserKeyDataStru {
    unsigned int key_state : 8;         //按鍵狀態(tài)[1:有鍵按下,0:沒有按鍵按下(或功能鍵,此處不用)]
    unsigned int key : 8;               //按鍵鍵值
    unsigned int repeat : 8;            //連擊計數(shù)器
    unsigned int reserved : 8;          //預留
};

//按鍵對應(yīng)的LED狀態(tài)定義
typedef struct LedAndKeyInfoStru {
    unsigned int key : 8;
    unsigned int led_state : 8;
}KeyAndLedStateStru_t;

static int fd = -1;

KeyAndLedStateStru_t led_and_key[] = {
    {.key = 1, .led_state = 0},
    {.key = 2, .led_state = 0},
    {.key = 3, .led_state = 0},
    {.key = 4, .led_state = 0},
    {.key = 28, .led_state = 0},
    {.key = 27, .led_state = 0},
    {.key = 26, .led_state = 0},
    {.key = 25, .led_state = 0},
    {.key = 20, .led_state = 0},
    {.key = 19, .led_state = 0},
    {.key = 18, .led_state = 0},
};

#define LED_IOCTL_ON    0
#define LED_IOCTL_OFF   1

static void led_onoff(unsigned int onoff, unsigned int key)
{
    if (fd < 0) {
        return;
    }

    if (onoff == 0) { //ON
        ioctl(fd, LED_IOCTL_ON, &key);
    } else { //OFF
        ioctl(fd, LED_IOCTL_OFF, &key);
    }
}

#define LED_ON_FUN(key)     led_onoff(0, key)
#define LED_OFF_FUN(key)    led_onoff(1, key)

static void key_led_onoff(unsigned int key)
{
    int i = 0;

    if (fd < 0) {
        return;
    }

    for (i = 0; i < (sizeof(led_and_key) / sizeof(KeyAndLedStateStru_t)); ++i) {
        if (led_and_key[i].key == key) {
            break;
        }
    }

    if (i >= (sizeof(led_and_key) / sizeof(KeyAndLedStateStru_t))) {
        return;
    }

    if (led_and_key[i].led_state == 1) {
        LED_OFF_FUN(key);
        led_and_key[i].led_state = 0;
    } else { //OFF
        LED_ON_FUN(key);
        led_and_key[i].led_state = 1;
    }
}

int main()
{
    struct UserKeyDataStru user_key_data = {0};

    fd = open(KEY_DEV, O_RDONLY);
    if (fd < 0) {
        printf("Error open %s\n\n", KEY_DEV);
        
        return -1;
    }           
    printf("[%d]Open %s Ok\n", fd, KEY_DEV);

    while(1) {
        if (read(fd, &user_key_data, sizeof(user_key_data)) < 0) {
            perror("read error");
            break;
        }

        if (user_key_data.key_state != 0) {
            printf("key = %d, repeat = %d\n", user_key_data.key, user_key_data.repeat);
            key_led_onoff(user_key_data.key);
        }
        
        usleep(500);
    }
    
    close(fd);

    return 0;
}

在樹莓派A20上做測試程梦,效果如下:


root@marsboard:~# ./keyTest
[3]Open /dev/keyboard_i2c7290 Ok
key = 20, repeat = 1
key = 26, repeat = 1
key = 27, repeat = 1
key = 28, repeat = 1
key = 19, repeat = 1
key = 20, repeat = 1
key = 26, repeat = 1
key = 27, repeat = 1
key = 28, repeat = 1
key = 1, repeat = 1
key = 5, repeat = 1
key = 5, repeat = 1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市橘荠,隨后出現(xiàn)的幾起案子屿附,更是在濱河造成了極大的恐慌,老刑警劉巖哥童,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挺份,死亡現(xiàn)場離奇詭異,居然都是意外死亡如蚜,警方通過查閱死者的電腦和手機压恒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來错邦,“玉大人探赫,你說我怎么就攤上這事∏四兀” “怎么了伦吠?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長魂拦。 經(jīng)常有香客問我毛仪,道長,這世上最難降的妖魔是什么芯勘? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任箱靴,我火速辦了婚禮,結(jié)果婚禮上荷愕,老公的妹妹穿的比我還像新娘衡怀。我一直安慰自己棍矛,他們只是感情好,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布抛杨。 她就那樣靜靜地躺著够委,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怖现。 梳的紋絲不亂的頭發(fā)上茁帽,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音屈嗤,去河邊找鬼潘拨。 笑死,一個胖子當著我的面吹牛恢共,可吹牛的內(nèi)容都是我干的战秋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼讨韭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了癣蟋?” 一聲冷哼從身側(cè)響起透硝,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疯搅,沒想到半個月后濒生,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡幔欧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年罪治,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片礁蔗。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡觉义,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浴井,到底是詐尸還是另有隱情晒骇,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布磺浙,位于F島的核電站洪囤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏撕氧。R本人自食惡果不足惜瘤缩,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伦泥。 院中可真熱鬧剥啤,春花似錦何暮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至富腊,卻和暖如春坏逢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赘被。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工是整, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人民假。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓浮入,卻偏偏與公主長得像,于是被迫代替她去往敵國和親羊异。 傳聞我的和親對象是個殘疾皇子事秀,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容