linux驱动开发之字符设备--自动创建设备节点
来源:互联网 发布:vpn服务器域名填什么 编辑:程序博客网 时间:2024/04/30 03:20
mdev
在/dev下创建设备的方法有两种,一种是手动的使用 mknod 进行创建。另外一种是使用 mdev 进行自动的创建设备。
mdev集成在busybox中,mdev 会自动检测 /sys/class 和 /sys/block 的所有类设备目录;如果在目录中含有名为“dev”的文件,同时如果内容是设备号的话,mdev
就会利用这些信息,在/dev下创建这个设备节点。
内核API
创建类
#define class_create(owner, name) \({ \ static struct lock_class_key __key; \ __class_create(owner, name, &__key); \})
参数:
- owner: THIS_MODULE
- name :在/sys/class/下显示的name
创建设备
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)
参数:
- class : 创建的类,
- parent: 父类。通常为NULL
- devt : 设备号
- drvdata : 通常为NULL
- fmt: 可变参数,通常为 设备的名字
有类、设备的创建,就有类、设备的销毁
void class_destroy(struct class *cls)
void device_destroy(struct class *class, dev_t devt)
实例
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/device.h>#include <linux/sysfs.h>#include <linux/kobject.h>#include <linux/uaccess.h>//幻数#define IOCTL_TYPE 'b'#define COUNT 32struct ioctl_arg { int val; char buf[COUNT];};//定义的命令码#define CMDCTL _IO(IOCTL_TYPE,0)#define CMDR _IOR(IOCTL_TYPE,1,struct ioctl_arg)#define CMDW _IOW(IOCTL_TYPE,2,struct ioctl_arg)#define DEVICE_CLASS_NAME "cdev_demo_class"#define DEVICE_NAME "cdev_demo"static struct cdev *pdev = NULL;static int major = 0;static int minor = 0;static int count = 2;static struct class *cdev_demo_class;struct kobject *cdev_obj;#define BUF_SIZE (1024)static char kbuf[BUF_SIZE];static int buf_count = 0;static int cdev_demo_open(struct inode * inode, struct file * file){ printk("%s,%d\n",__func__,__LINE__); return 0;}static int cdev_demo_release(struct inode *inode, struct file * file){ printk("%s,%d\n",__func__,__LINE__); return 0;}static ssize_t cdev_demo_read(struct file * file, char __user * buffer, size_t size, loff_t * loff){ printk("%s,%d\n",__func__,__LINE__); if(0 == buf_count){ return -EAGAIN; } if(buf_count < size){ size = buf_count; } if(size == copy_to_user(buffer,kbuf,size)){ return -EAGAIN; } buf_count = 0; return size;}static ssize_t cdev_demo_write(struct file * file, const char __user * buffer, size_t size, loff_t * loff){ printk("%s,%d\n",__func__,__LINE__); printk("buffer=%s size=%d\n",buffer,size); if(size >BUF_SIZE){ return -ENOMEM; } if(size == copy_from_user(kbuf,buffer,size)){ return -EAGAIN; } buf_count = size; return size;}//ioctlstatic long cdev_demo_ioctl (struct file *filep, unsigned int cmd, unsigned long arg){ static struct ioctl_arg buf; printk("%s,%d\n",__func__,__LINE__); //分辨不同命令码 switch(cmd){ case CMDCTL: printk("do CMDCTL\n"); break; case CMDR: //使用 _IOC_SIZE()获得命令码中的数据长度 if(sizeof(buf) != _IOC_SIZE(cmd)){ return -EINVAL; } if(sizeof(buf) == copy_to_user((struct ioctl_arg*)arg,&buf,sizeof(struct ioctl_arg))){ return -EAGAIN; } printk("do CMDR\n"); break; case CMDW: if(sizeof(buf)!= _IOC_SIZE(cmd)){ return -EINVAL; } if(sizeof(buf) == copy_from_user(&buf,(struct ioctl_arg*)arg,sizeof(buf))){ return -EAGAIN; } printk("do CMDW\n"); printk("%d,%s \n",buf.val,buf.buf); break; default: break; } return 0;}static struct file_operations fops ={ .owner = THIS_MODULE, .open = cdev_demo_open, .release = cdev_demo_release, .read = cdev_demo_read, .write = cdev_demo_write, .unlocked_ioctl = cdev_demo_ioctl,};char cdev_buf[2] = "a";static ssize_t cdev_demo_show(struct device *dev,struct device_attribute *attr, char *buf) { char *s = buf; s = sprintf(s,"%s",cdev_buf); return sizeof(s);}static ssize_t cdev_demo_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ memcpy(cdev_buf,buf,count); return count;}static DEVICE_ATTR(cdev_demo, 0666, cdev_demo_show, cdev_demo_store);static struct attribute *g[] = { &dev_attr_cdev_demo.attr, NULL,};static struct attribute_group attr_group = { .attrs = g,};static int __init cdev_demo_init(void){ dev_t dev; int ret; int i; struct device * cdemo_device; printk("%s,%d\n",__func__,__LINE__); pdev = cdev_alloc(); if(NULL == pdev){ printk("cdev_alloc failed.\n"); return -ENOMEM; } cdev_init(pdev,&fops); ret = alloc_chrdev_region(&dev,minor,count,DEVICE_NAME); if(ret){ printk("alloc_chrdev_region failed.\n"); goto ERROR_CDEV; } major = MAJOR(dev); ret = cdev_add(pdev, dev,count); if(ret) { printk("cdev_add failed.\n"); goto ERROR_ADD; } cdev_obj = kobject_create_and_add("cdev_demo",NULL); if(!cdev_obj){ return -ENOMEM; } ret = sysfs_create_group(cdev_obj,&attr_group); if(ret) goto SYSFS_ERR; cdev_demo_class = class_create(THIS_MODULE,DEVICE_CLASS_NAME); if(IS_ERR(cdev_demo_class)){ ret = PTR_ERR(cdev_demo_class); printk("Unable to create class, err = %d\n", ret); goto CLASS_ERROR; } for(i = minor; i < minor + count; i ++){ cdemo_device = device_create(cdev_demo_class,NULL,MKDEV(major,i),NULL,"%s%d",DEVICE_NAME,i); if(NULL == cdemo_device){ ret = -EIO; goto DEVICE_ERROR; } } return 0;DEVICE_ERROR: for(i-- ; i >= minor ; i--){ device_destroy(cdev_demo_class, MKDEV(major,i)); } class_destroy(cdev_demo_class);CLASS_ERROR: sysfs_remove_group(cdev_obj,&attr_group);SYSFS_ERR: kobject_del(cdev_obj); kobject_put(cdev_obj);ERROR_ADD: unregister_chrdev_region(dev,count);ERROR_CDEV: cdev_del(pdev); return ret;}static void __exit cdev_demo_exit(void){ int i; printk("%s,%d\n",__func__,__LINE__); for(i = minor;i <count + minor;i ++){ device_destroy(cdev_demo_class, MKDEV(major,i)); } class_destroy(cdev_demo_class); sysfs_remove_group(cdev_obj,&attr_group); kobject_del(cdev_obj); kobject_put(cdev_obj); unregister_chrdev_region(MKDEV(major,minor),count); cdev_del(pdev);}module_init(cdev_demo_init);module_exit(cdev_demo_exit);MODULE_LICENSE("GPL");
结果:
//创建的类shell@tiny4412:/sys/class/cdev_demo_class # ls -lalrwxrwxrwx root root 2014-01-01 20:01 cdev_demo ->../../devices/virtual/cdev_demo_class/cdev_demo
// 类下/dev的内容shell@tiny4412:/sys/class/cdev_demo_class/cdev_demo # cat dev247:0
//在/dev/下创建的设备ls -la /dev/cdev_demo crw------- root root 247, 0 2014-01-01 20:01 cdev_demo
在创建设备的时候,没有指定parent,则设备创建在一下目录
/sys/device/vitual/cdev_demo_class/
参考文献
浅析为什么device_create()生成文件添加到/sys/devices/virtual/目录
阅读全文
0 0
- linux驱动开发之字符设备--自动创建设备节点
- linux驱动开发--字符设备:自动创建设备节点
- linux驱动开发--字符设备:自动创建设备节点
- linux字符设备驱动之设备节点的自动创建
- linux字符驱动之自动创建设备节点
- linux字符驱动之自动创建设备节点
- linux字符驱动之自动创建设备节点
- linux字符驱动之自动创建设备节点
- linux字符驱动之自动创建设备节点
- linux字符设备驱动中自动创建设备节点
- Linux字符设备驱动自动创建设备节点
- linux字符设备驱动中自动创建设备节点【转】
- linux字符设备驱动:自动创建设备及其节点
- linux驱动开发之自动创建设备节点
- linux驱动开发之自动创建设备节点
- linux驱动之自动创建设备节点
- linux驱动开发--字符设备:创建一组设备节点
- Linux驱动开发--自动创建设备文件节点
- quartzs每小时执行一次(整点整分)
- 使用drag与drop实现拖拽,(vue)
- 基于MFC的俄罗斯方块小游戏(二)
- C++ Primer Plus, Chapter 13, excercise
- 谈谈龙之谷手游兼容测试的一百个坑
- linux驱动开发之字符设备--自动创建设备节点
- deadline实用功能汇总,财主的粮仓
- android蓝牙电话监听状态
- java编程(Socket) 小结
- hadoop常用命令
- 彩色图像分割
- 初始想法
- Python入门书籍推荐
- 贝叶斯线性回归(单输出)