Android-驱动学习-入门

Android-驱动学习-⼊门
基础概念:
设备号 : 分为主设备号和次设备号。设备号是16bit, ⾼8bit为主设备号,低8bit为次设备号。当我们创建⼀个设备节点时需要指定主设备号和次设备号。应⽤程序通过名称访问设备,⽽设备号指定了对应的驱动程序和对应的设备。主设备号标识设备对应的驱动程序,次设备号由内核使⽤,⽤于确定设备节点所指设备。你可以通过/proc/devices⽂件来查看系统设备的主设备号。
设备节点: Linux中设备节点是通过“mknod”命令来创建的。⼀个设备节点其实就是⼀个⽂件,Linux中称为设备⽂件。⼀般都创建在dev/⽬录下。
在userspace中可以打开设备节点,并通过驱动向设备节点写⼊数据。具体怎么实现呢?
1.kernel层的实现
a) 到⼀个设备号devno,可以动态申请,也可以静态设定,假设静态设定为major,minor,通过宏MKDEV(major,minor)来⽣成
devno
b) 构建对设备的操作函数集file_opreation结构体,⾥⾯包含了的设备的操作:open、read、write、release、ioctl等
c) 构建cdev结构体,⾥⾯填充两个主要成员dev(设备号)、file_operation(对设备的操作)
d) 把cdev添加到cdev链表中:cdev_init、cdev_add
具体代码:
⾸先, 内核在初始化的时候会调⽤initcall.init中保存的⼀份函数指针,并在初始化完成之后释放整个init区段。
当需要把函数xxx_init放到initcall.init区段的函数指针表中时,只需要声明: core_initcall(xxx_init);即可。
module_exit(xxx_exit)和前⾯的过程相似,在退出的时候会执⾏所有放在exit表中的函数。
所以⼀个驱动,最先执⾏的代码就是放在init列表⾥⾯的xxx_init函数。
我们看看这个函数做了什么:
static int __init xxx_init(void)
清水植物黑发{
dev_t dev;
struct xxx_dev xxxdriver = kzalloc(sizeof(struct xxx_dev) + 5, GFP_KERNEL); // 先定义⼀个driver
  // 给driver中的变量赋值
xlogdriver->buf = kzalloc(XLOGBUF_SIZE, GFP_KERNEL);
xlogdriver->num = 1;
xlogdriver->name = "xxx";
xlogdriver->free_size = XLOGBUF_SIZE;
  alloc_chrdev_region(&dev, xlogdriver->minor_start, xlogdriver->num, xlogdriver->name);
xlogdriver->cdev = cdev_alloc();
ret = xxx_setup_cdev(dev); // 然后调⽤setup函数
}
// 构建对设备的操作函数集file_opreation结构体
static const struct file_operations xxxfops = {
.owner = THIS_MODULE,
.read = xxx_read,
.write = xxx_write,
.poll = xxx_poll,
.open = xxx_open,
.release = xxx_close
};
static int xxx_setup_cdev(dev_t devno)
{
cdev_init(xxxdriver->cdev, &xxxfops); // 初始化cdev
xxxdriver->cdev->owner = THIS_MODULE;
xxxdriver->cdev->ops = &xxxfops; // cdev的主要成员,对设备节点的操作
err = cdev_add(xxxdriver->cdev, devno, 1); // 把cdev添加到cdev链表中
xxxdriver->xxx_class = class_create(THIS_MODULE, "xxx");
管串xlogdriver->xlog_dev = device_create(xlogdriver->xxx_class,NULL, devno, (void *)xlogdriver, "xlog");
return 0;
}
然后重点实现的函数就是file_operations xxxfops中构建的函数xxx_read、xxx_write、xxx_poll、xxx_o
pen和xxx_close。实现完成之后userspace就可以通过这些函数去对xxx这个设备节点进⾏操作了。
eg:
static ssize_t xxx_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int err = 0;
size_t copy_bytes;
u64 temp = count;
mutex_lock(&xxxdriver->xxx_mutex); // 写⼊之前先上锁
if (xxxBUF_SIZE < xxxdriver->writeindex + count) {
copy_bytes = xxxBUF_SIZE - xxxdriver->writeindex;
1-甲基环戊醇
err = copy_from_user(xxxdriver->buf + xxxdriver->writeindex, buf, copy_bytes); // 从userspace的buf中读取数据写⼊xxxdriver->buf        err = copy_from_user(xxxdriver->buf, buf + copy_bytes, count - copy_bytes);
xxxdriver->writeindex = count - copy_bytes;
} else {
err = copy_from_user(xxxdriver->buf + xxxdriver->writeindex, buf, count);
xxxdriver->writeindex += count;
}
ebeam
xxxdriver->free_size -= count; // 更新剩余空间
mutex_unlock(&xxxdriver->xxx_mutex); // 写完之后解锁
wake_up_interruptible(&xxxdriver->wait_q);
return count;
}
2. userspace的操作
木纹铝扣板
int fd=open("/dev/xxx",O_RDWR)来打开设备⽂件,此设备对应有⼀个设备号,这是我们识别驱动和设备的桥梁。
打开 /dev/xxx时,根据设备号,在cdev链表中到cdev这个结构体,cdev⾥⾯包含了file_operation结构体,有设备的各种操作,打开时就调⽤⾥⾯的.open 函数。
字幕烟花具体代码:
例如此时app有⼀些数据需要写⼊设备节点:
void wirte_to_xxx(char* str){
int fd = open("/dev/xxx",O_RDWR); // 先打开设备节点,此处最终调⽤的就是xxx_open
write(fd, str, strlen(str)); // 写⼊数据, 此处最终调⽤的就是xxx_write
close(fd); // 写完之后关闭节点,此处最终调⽤的就是xxx_close
}

本文发布于:2024-09-23 14:35:13,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/3/329505.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:设备   节点   函数   操作   静态   需要   对应   设定
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议