实现字符设备驱动框架
1.设定一个全局的设备对象
(全局)
(init函数中)
2.申请主设备号
3.创建设备节点文件
4.硬件的初始化——地址映射或者中断申请
5.实现file_operations
6.释放资源(exit函数中)
驱动中获取硬件数据并传递给用户的方法
a,硬件如何获取数据
key: 按下和抬起: 1/0
读取key对应的gpio的状态,可以判断按下还是抬起
读取key对应gpio的寄存器--数据寄存器
//读取数据寄存器
int value = readl(key_dev->reg_base + 4) & (1<<2);
//设计一个全局设备对象--描述按键信息
struct key_desc{
unsigned int dev_major;
struct class *cls;
struct device *dev;
int irqno;
void *reg_base;
};
//init函数中
// a,硬件如何获取数据--gpx1
key_dev->reg_base = ioremap(GPXCON_REG, 8);
b,驱动如何传递给用户
在中断处理中填充数据:
key_dev->event.code = KEY_ENTER;
key_dev->event.value = 0;
在xxx_read中奖数据传递给用户
ret = copy_to_user(buf, &key_dev->event, count);
// 设计一个描述按键的数据的对象
struct key_event{
int code; // 表示按键的类型: home, esc, Q,W,E,R,T, ENTER
int value; // 表示按下还是抬起 1 / 0
};
//设计一个全局设备对象--描述按键信息
struct key_desc{
unsigned int dev_major;
struct class *cls;
struct device *dev;
int irqno;
void *reg_base;
struct key_event event;
};
irqreturn_t key_irq_handler(int irqno, void *devid)
{
printk("-------%s-------------\n", __FUNCTION__);
//读取数据寄存器
int value = readl(key_dev->reg_base + 4) & (1<<2);
if(value){
// 抬起
printk("key3 up\n");
key_dev->event.code = KEY_ENTER;
key_dev->event.value = 0;
}else{
//按下
printk("key3 pressed\n");
key_dev->event.code = KEY_ENTER;
key_dev->event.value = 1;
}
return IRQ_HANDLED;
}
ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
//printk("-------%s-------------\n", __FUNCTION__);
int ret;
ret = copy_to_user(buf, &key_dev->event, count);
if(ret > 0)
{
printk("copy_to_user error\n");
return -EFAULT;
}
// 传递给用户数据之后,将数据清除掉
memset(&key_dev->event, 0, sizeof(key_dev->event));
return count;
}
//释放资源
static void __exit key_drv_exit(void)
{
iounmap(key_dev->reg_base);
free_irq(key_dev->irqno, NULL);
device_destroy(key_dev->cls