创建设备文件cdevadd|嵌入式linux设备驱动无法打开设备文件

㈠ 如何手动创建一个设备节点,写出主要命令及参数

linux下生成驱动设备节点文件的方法有3个:1、手动mknod;2、利用devfs;3、利用udev在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点。在2.6.17以前,在/dev目录下生成设备文件很容易,devfs_mk_bdevdevfs_mk_cdevdevfs_mk_symlinkdevfs_mk_dirdevfs_remove这几个是纯devfs的api,2.6.17以前可用,但后来devfs被sysfs+udev的形式取代,同时期sysfs文件系统可以用的api:class_device_create_file,在2.6.26以后也不行了,现在,使用的是device_create ,从2.6.18开始可用struct device *device_create(struct class *class, struct device *parent,dev_t devt, const char *fmt, …)从2.6.26起又多了一个参数drvdata: the data to be added to the device for callbacks不会用可以给此参数赋NULLstruct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, …) 下面着重讲解第三种方法udev在驱动用加入对udev的支持主要做的就是:在驱动初始化的代码里调用class_create(…)为该设备创建一个class,再为每个设备调用device_create(…)( 在2.6较早的内核中用class_device_create)创建对应的设备。内核中定义的struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用 device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应 device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。struct class和class_create(…) 以及device_create(…)都包含在在/include/linux/device.h中,使用的时候一定要包含这个头文件,否则编译器会报错。struct class定义在头文件include/linux/device.h中class_create(…)在/drivers/base/class.c中实现device_create(…)函数在/drivers/base/core.c中实现class_destroy(…),device_destroy(…)也在/drivers/base/core.c中实现调用过程类似如下:static struct class *spidev_class; /*————————————————————————-*/ static int __devinit spidev_probe(struct spi_device *spi){ …. dev =device_create(spidev_class, &spi->dev, spidev->devt, spidev, "spidev%d.%d", spi->master->bus_num, spi->chip_select); …} static int __devexit spidev_remove(struct spi_device *spi){ …… device_destroy(spidev_class, spidev->devt); ….. return 0;} static struct spi_driver spidev_spi = { .driver = { .name = "spidev", .owner = THIS_MODULE, }, .probe = spidev_probe, .remove = __devexit_p(spidev_remove), }; /*————————————————————————-*/ static int __init spidev_init(void){ …. spidev_class =class_create(THIS_MODULE, "spidev"); if (IS_ERR(spidev_class)) { unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); return PTR_ERR(spidev_class); } ….}mole_init(spidev_init); static void __exit spidev_exit(void){ …… class_destroy(spidev_class); ……}mole_exit(spidev_exit); MODULE_DESCRIPTION("User mode SPI device interface");MODULE_LICENSE("GPL"); 下面以一个简单字符设备驱动来展示如何使用这几个函数 #include <linux/mole.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h> int HELLO_MAJOR = 0;int HELLO_MINOR = 0;int NUMBER_OF_DEVICES = 2; struct class *my_class;//struct cdev cdev;//dev_t devno; struct hello_dev {struct device *dev;dev_t chrdev;struct cdev cdev;};static struct hello_dev *my_hello_dev = NULL;struct file_operations hello_fops = { .owner = THIS_MODULE}; static int __init hello_init (void){int err = 0;struct device *dev;my_hello_dev = kzalloc(sizeof(struct hello_dev), GFP_KERNEL);if (NULL == my_hello_dev) {printk("%s kzalloc failed!\n",__func__);return -ENOMEM;}devno = MKDEV(HELLO_MAJOR, HELLO_MINOR);if (HELLO_MAJOR)err= register_chrdev_region(my_hello_dev->chrdev, 2, "memdev");else{err = alloc_chrdev_region(&my_hello_dev->chrdev, 0, 2, "memdev");HELLO_MAJOR = MAJOR(devno);} if (err) {printk("%s alloc_chrdev_region failed!\n",__func__);goto alloc_chrdev_err;}printk("MAJOR IS %d\n",HELLO_MAJOR);cdev_init(&(my_hello_dev->cdev), &hello_fops);my_hello_dev->cdev.owner = THIS_MODULE;err = cdev_add(&(my_hello_dev->cdev), my_hello_dev->chrdev, 1);if (err) {printk("%s cdev_add failed!\n",__func__);goto cdev_add_err;}printk (KERN_INFO "Character driver Registered\n");my_class =class_create(THIS_MODULE,"hello_char_class"); //类名为hello_char_classif(IS_ERR(my_class)) {err = PTR_ERR(my_class);printk("%s class_create failed!\n",__func__);goto class_err;}dev = device_create(my_class,NULL,my_hello_dev->chrdev,NULL,"memdev%d",0); //设备名为memdevif (IS_ERR(dev)) {err = PTR_ERR(dev);gyro_err("%s device_create failed!\n",__func__);goto device_err;}printk("hello mole initialization\n");return 0; device_err:device_destroy(my_class, my_hello_dev->chrdev);class_err:cdev_del(my_hello_dev->chrdev);cdev_add_err:unregister_chrdev_region(my_hello_dev->chrdev, 1);alloc_chrdev_err:kfree(my_hello_dev);return err;} static void __exit hello_exit (void){cdev_del (&(my_hello_dev->cdev));unregister_chrdev_region (my_hello_dev->chrdev,1);device_destroy(my_class, devno); //delete device node under /dev//必须先删除设备,再删除class类class_destroy(my_class); //delete class created by usprintk (KERN_INFO "char driver cleaned up\n");} mole_init (hello_init);mole_exit (hello_exit); MODULE_LICENSE ("GPL");这样,模块加载后,就能在/dev目录下找到memdev这个设备节点了。 例2:内核中的drivers/i2c/i2c-dev.c在i2cdev_attach_adapter中调用device_create(i2c_dev_class, &adap->dev, MKDEV(I2C_MAJOR, adap->nr), NULL, "i2c-%d", adap->nr);这样在dev目录就产生i2c-0 或i2c-1节点 接下来就是udev应用,udev是应用层的东西,udev需要内核sysfs和tmpfs的支持,sysfs为udev提供设备入口和uevent通道,tmpfs为udev设备文件提供存放空间udev的源码可以在去相关网站下载,然后就是对其在运行环境下的移植,指定交叉编译环境,修改Makefile下的CROSS_COMPILE,如为mipsel-linux-,DESTDIR=xxx,或直接make CROSS_COMPILE=mipsel-linux-,DESTDIR=xxx 并install把主要生成的udevd、udevstart拷贝rootfs下的/sbin/目录内,udev的配置文件udev.conf和rules.d下的rules文件拷贝到rootfs下的/etc/目录内并在rootfs/etc/init.d/rcS中添加以下几行:echo “Starting udevd…”/sbin/udevd –daemon/sbin/udevstart(原rcS内容如下:# mount filesystems/bin/mount -t proc /proc /proc/bin/mount -t sysfs sysfs /sys/bin/mount -t tmpfs tmpfs /dev# create necessary devices/bin/mknod /dev/null c 1 3/bin/mkdir /dev/pts/bin/mount -t devpts devpts /dev/pts/bin/mknod /dev/audio c 14 4/bin/mknod /dev/ts c 10 16)这样当系统启动后,udevd和udevstart就会解析配置文件,并自动在/dev下创建设备节点文件

㈡ arm linux驱动程序和应用程序之间的一些问题

我不知道你用的那个版本的kernel,但是据我所知,ioctl的cmd参数的定义,不是你那么简单的….需要用到ioctl的命令字定义的几个宏定义…自己定义是没有用的,因为ioctl需要知道你的命令是io读还是io写..比如在我的程序里面我这样定义命令字…你自己查一下_IOW,_IO这两个宏…#include <linux/ioctl.h>//使用下面的宏#define DEVICE_NAME "/dev/test_device"#define TEST_MAGIC_NUM 'k'#define PORT_SET _IOW(TEST_MAGIC_NUM,1,int)#define PORT_GET _IO(TEST_MAGIC_NUM,2)#define PORT_LOCK _IO(TEST_MAGIC_NUM,3) 你的应用程序中,也应该把这样定义的命令字给包含进去…这两个个宏的意义是,不要和系统已经使用ioctl的cmd重复…因为ioctl接口并不是仅仅给你使用的.你自己写的命令字会把系统原有的给覆盖…

㈢ Linux下codeblocks如何调用Linux中的设备注册函数例如cdev_add()函数

struct cdev *my_cdev = cdev_alloc( );my_cdev->ops = &my_fops;void cdev_init(struct cdev *cdev, struct file_operations *fops);int cdev_add(struct cdev *dev, dev_t num, unsigned int count);struct scull_dev { struct scull_qset *data; /* Pointer to first quantum set */ int quantum; /* the current quantum size */ int qset; /* the current array size */ unsigned long size; /* amount of data stored here */ unsigned int access_key; /* used by sculluid and scullpriv */ struct semaphore sem; /* mutual exclusion semaphore */ struct cdev cdev; /* Char device structure */};

㈣ 写linux驱动的请帮我看看,我这个程序怎么创建不了设备文件

参考答案智者不惑,仁者不忧,勇者不惧。–孔子

㈤ 字符驱动设备中几个重要的结构体(cdev,file

1. cdev结构体

[cpp]view plain

structcdev{

structkobjectkobj;//内嵌的kobject对象

structmole*owner;//所属模板

conststructfile_operations*ops;//文件操作的结构体

structlist_headlist;

dev_tdev;//设备号

unsignedintcount;

};

1.1 cdev的相关操作

[cpp]view plain

voidcdev_init(structcdev*,conststructfile_operations*);//初始化使其和文件操作结构相连接

structcdev橡冲巧*cdev_alloc(void);//为cdev分配内存

intcdev_add(structcdev*,dev_t,unsigned);//向内核注册一个设备

voidcdev_del(structcdev*);//从内梁键核删除一个设备

1.2 设备号的分配

1.21 主次设备号和dev_t的相互转换

由dev_t号获取主次设备号

[cpp]view plain

MAJOR(dev_tdev)

MINOR(dev_tdev)

由主次设备号获得dev_t

[cpp]view plain

MKDEV(intmajor,intminor)

1.22 获取及注销设备号

[cpp]view plain

<spanstyle="font-size:14px;">intregister_chrdev_region(dev_tfrom,unsignedcount,constchar*name);//手动注册

intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,constchar*name);//由内核分配

voinregion_chrdev_region(dev_tfrom,unsignedcount);//注销设判纳备号</span>

㈥ cdev结构代表着什么

代表字符设备

㈦ 两个注册设备驱动的函数有什么区别

register_chrdev的作用是向内核申请分配一个单独渣脊核主设备号和范围在 0 ~ 255 的次设如掘备号,野笑如果申请的主设备号为 0 则内核会动态分配一个;cdev_add是向内核添加一个cdev结构;完全两码事。 查看原帖>>

㈧ android gpio 怎么分配

驱动程序初始化和退出static int simple_major = 250;//默认的设备号码,如果为0则尝试自动分配……/** Set up the cdev structure for a device.*/static void simple_setup_cdev(struct cdev *dev, int minor,struct file_operations *fops)//自编的函高烂数,注册字符设备{int err, devno = MKDEV(simple_major, minor);//建立设备号cdev_init(dev, fops);//初始化设备结构体struct cdev *devdev->owner = THIS_MODULE;dev->ops = fops;//关衫野联fopserr = cdev_add (dev, devno, 1);//注册一个字符设备/* Fail gracefully if need be */if (err)//注册失败处理printk (KERN_NOTICE "Error %d adding simple%d", err, minor);}/** Our various sub-devices.*//* Device 0 uses remap_pfn_range */static struct file_operations simple_remap_ops = { //定义设备的fops.owner = THIS_MODULE,.open = simple_open,.release = simple_release,.read = simple_read,.write = simple_write,.ioctl = simple_ioctl,};/** We export two simple devices. There's no need for us to maintain any* special housekeeping info, so we just deal with raw cdevs.*/static struct cdev SimpleDevs;/** Mole housekeeping.*/static struct class *my_class;static int simple_init(void){int result;dev_t dev = MKDEV(simple_major, 0);//将设备号转化为dev_t的结构/* Figure out our device number. */if (simple_major)result = register_chrdev_region(dev, 1, "simple");//尝试申请主设备号else {result = alloc_chrdev_region(&dev, 0, 1, "simple");//请求自动分配主设备号,起始值是0,总共分配1个或念喊,设备名simplesimple_major = MAJOR(dev);//将分配成功的设备号保存在simple_major变量中}if (result < 0) {//分配主设备号失败printk(KERN_WARNING "simple: unable to get major %d\n", simple_major);return result;}if (simple_major == 0)//将返回值记录为主设备号。需要么?simple_major = result;/* Now set up two cdevs. */simple_setup_cdev(&SimpleDevs, 0, &simple_remap_ops);//调用自编的函数注册字符设备,有Bug没有返回注册是否成功。printk("simple device installed, with major %d\n", simple_major);//Bug:打印前应该检查注册是否成功?my_class= class_create(THIS_MODULE, "simple");//建立一个叫simple的内核class,目的是下一步创建设备节点文件device_create(my_class, NULL, MKDEV(simple_major, 0),NULL, "led");//创建设备节点文件return 0;}static void simple_cleanup(void){cdev_del(&SimpleDevs);//删除字符设备unregister_chrdev_region(MKDEV(simple_major, 0), 1);//注销主设备号device_destroy(my_class,MKDEV(simple_major,0));//删除设备节点printk("simple device uninstalled\n");}mole_init(simple_init);mole_exit(simple_cleanup);

㈨ 嵌入式linux设备驱动,无法打开设备文件

1. ls /dev/* 看看有没有你的LED节点2.cat /proc/devices 看看有没有相关LED驱动信息。 ===============================static const struct file_operations fops_led ={.owner = THIS_MODULE,//.open = open_led,.unlocked_ioctl = unlocked_ioctl_led,};都屏蔽了open函数,内怎么打开容?

㈩ 请问linux2.6内核驱动程序的自动创建设备节点的 class_create device_create 创建设备问题。

是这么回事,当你自己要写一个字符设备或者看别人写的是字符设备时内,要定义一个字符容设备的结构体struct cdev{/*里面是一些字符设备的相关属性,包括file_operations结构体,设备号等等*/},然后调用register_chrdev_region(),申请设备号,再用cdev_add()想内核注册设备,这里,内核就知道你要注册的就是字符设备了,同理,如果是块设备的话用register_blkdev()来注册块设备,经过一系列的初始化后添加add_disk(),内核也就知道你添加的是块设备了


赞 (0)