Linux驱动开发之字符设备
来源:互联网 发布:js获取所有span 编辑:程序博客网 时间:2024/05/16 03:04
字符设备是驱动开发中最简单的一种设备(通过字符设备来写寄存器,从而起到一个驱动的作用),struct cdev结构体是内核用来描述一个字符设备的,是内核已经封装好的,程序员只需要直接定义一个这样的结构体变量即可。
struct cdev {
struct kobject kobj; // 每个cdev 都有一个 kobject
struct module *owner; // 指向实现驱动的模块
const struct file_operations *ops; // 操纵这个字符设备文件的方法
struct list_head list; // 与cdev 对应的字符设备文件的 inode->i_devices 的链表头
dev_t dev; // 起始设备编号
unsigned int count; // 设备范围号大小
};
struct file_operations是操纵这个字符设备的一些方法
struct file_operations {
struct module *owner; //它是一个指向拥有这个结构的模块的指针
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
};
接下来在虚拟机上写一个字符设备,代码如下:
chardevice.cpp
#include<linux/module.h>#include<linux/fs.h>#include<linux/init.h>#include<linux/cdev.h>#include<linux/slab.h>#include<linux/uaccess.h>#define GLOBALMEM_SIZE 0x1000#define MEM_CLEAR 0x1#define GLOBALMEM_MAJOR 230 //设备号
static int globalmem_major = GLOBALMEM_MAJOR;module_param(globalmem_major,int,S_IRUGO);struct globalmem_dev{ struct cdev cdev; //描述字符设备的结构体 unsigned char mem[GLOBALMEM_SIZE];};
struct globalmem_dev* globalmem_devp;static int globalmem_open(struct inode* inode,struct file* filp){ filp->private_data = globalmem_devp; return 0;}static int globalmem_release(struct inode* inode,struct file* filp){ return 0;}
static long globalmem_ioctl(struct file* filp,unsigned int cmd,unsigned long arg){ struct globalmem_dev* dev = filp->private_data; switch(cmd) { case MEM_CLEAR: memset(dev->mem,0,GLOBALMEM_SIZE); printk(KERN_INFO"globalmem is set to zero\n"); break; default: return -EINVAL; } return 0;}
static ssize_t globalmem_read(struct file* filp,char __user* buf,size_t size,loff_t* ppos){ unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev* dev = filp->private_data; if(p >= GLOBALMEM_SIZE) return 0; if(count> GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p; if(copy_to_user(buf,dev->mem + p,count) ) ret = -EFAULT; else { *ppos = *ppos + count; ret = count; printk(KERN_INFO"read %u bytes(s) from %lu\n",count,p); } return ret;}
static ssize_t globalmem_write(struct file* filp,const char __user* buf,size_t size,loff_t * ppos){ unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev* dev = filp->private_data; if(p >= GLOBALMEM_SIZE) return 0; if(count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p; if( copy_from_user(dev->mem+p, buf, count) ) ret = -EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO"write %u bytes(s) from %lu\n",count,p); } return ret;}
static const struct file_operations globalmem_fops = { .owner = THIS_MODULE, .read = globalmem_read, .write = globalmem_write, .unlocked_ioctl = globalmem_ioctl, .open = globalmem_open, .release = globalmem_release,};static void globalmem_setup_cdev(struct globalmem_dev* dev,int index){ int err, devno = MKDEV(globalmem_major,index); cdev_init(&dev->cdev,&globalmem_fops); //初始化字符设备 dev->cdev.owner = THIS_MODULE; err = cdev_add(&dev->cdev,devno,1); //向系统添加一个cdev if(err) { printk(KERN_NOTICE"Error %d adding globalmem%d",err,index); }}
static int __init globalmem_init(void){ int ret; dev_t devno = MKDEV(globalmem_major,0); if(globalmem_major) { ret = register_chrdev_region(devno,1,"globalmem"); //申请设备号(知道起始设备号) }
else { ret = alloc_chrdev_region(&devno,0,1,"gobalmem");//申请设备号(不知道起始设备号) globalmem_major = MAJOR(devno); } if(ret < 0) return ret; globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);//为设备申请空间 if(!globalmem_devp) { ret = -ENOMEM; goto fail_malloc; } globalmem_setup_cdev(globalmem_devp,0); return 0; fail_malloc:
unregister_chrdev_region(devno,1); return ret;}module_init(globalmem_init);
static void __exit globalmem_exit(void){ cdev_del(&globalmem_devp->cdev); //释放cdev kfree(globalmem_devp); unregister_chrdev_region( MKDEV(globalmem_major,0), 1); //释放设备号}module_exit(globalmem_exit);MODULE_AUTHOR("liwanchao");
MODULE_LICENSE("GPL");
Makefile如下:
ifneq ($(KERNELRELEASE),)param-objs:= chardevice.oobj-m := chardevice.oelseKDIR := /lib/modules/$(shell uname -r)/buildall: make -C $(KDIR) M=$(PWD) modulesclean: rm -f *.ko *.o *.mod.o *.mod.c *.symversendif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
如何把这个模块加载到内核呢?
Makefile写好了之后,直接make,这时候可以看到生成了chardevice.ko文件。
运用insmod chardevice.ko,就加载进内核了。(root用户)
这个时候vim /proc/devices就可以看到刚才那个设备的设备号和设备名字:(root用户)
设备号为230,名字为globalmem
然后运用卸载工具rmmod chardevice 就卸载了这个设备。(root)
- Linux驱动开发之字符设备
- linux驱动开发之字符设备框架
- linux驱动开发之字符设备框架
- linux驱动开发之字符设备--自动创建设备节点
- Linux设备驱动之《字符设备驱动》
- Linux设备驱动之字符设备驱动
- Linux设备驱动之字符设备驱动
- Linux设备驱动之字符设备驱动
- Linux设备驱动之字符设备驱动
- Linux设备驱动之字符设备驱动
- linux设备驱动之字符设备驱动
- linux驱动开发-字符设备
- linux字符设备驱动开发
- Linux驱动之字符设备
- linux驱动之字符设备
- Hasen的linux设备驱动开发学习之旅--支持多设备的字符设备驱动
- linux设备驱动开发学习之旅--支持多设备的字符设备驱动
- Linux 驱动开发-字符设备驱动
- Gson使用指南(1)
- Windows Server 2012 R2 或 2016 无法安装 .Net 3.5.1
- 今天我们来说说项目管理
- android studio运行出现失败,提示java jdk找不到,javaMaxHeapSize "4g" error 解决办法
- wpf
- Linux驱动开发之字符设备
- Merge into使用详解-你Merge了没有
- Linux中变量#,@,0,1,2,*,$$,$?的含义
- Python Django基础教程(五)(表单)
- Oracle trunc()函数的用法
- sql变量使用总结
- 安装Activemq5.9.0异常
- 自定义View进阶之实现狂拽酷炫的3D效果
- 三探Android嵌套滑动 NestedScrolling机制 本质以及源码解析