导航:首页 > 版本升级 > 创建设备文件cdevadd

创建设备文件cdevadd

发布时间:2023-03-29 20:55:09

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

linux下生成驱动设备节点文件的方法有3个:1、手动mknod;2、利用devfs;3、利用udev
在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点。
在2.6.17以前,在/dev目录下生成设备文件很容易,
devfs_mk_bdev
devfs_mk_cdev
devfs_mk_symlink
devfs_mk_dir
devfs_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
不会用可以给此参数赋NULL
struct 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_class
if(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); //设备名为memdev
if (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 us
printk (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

㈥ 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 *dev

dev->owner = THIS_MODULE;

dev->ops = fops;//关衫野联fops

err = 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个或念喊,设备名simple

simple_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(),内核也就知道你添加的是块设备了

阅读全文

与创建设备文件cdevadd相关的资料

热点内容
linuxdeb文件安装 浏览:153
word如何在箭头上写字 浏览:821
安全删除数据为什么要重写硬盘 浏览:873
税务系统网络与信息安全应急保障工作框架 浏览:407
淘宝背景代码生成 浏览:649
小学特色托管编程图形如何 浏览:748
编程实验分析怎么写 浏览:58
鼠标编程宏怎么设置 浏览:100
怎么清除百度登录过网站 浏览:503
linuxl2 浏览:116
苹果升级一直重启怎么解决 浏览:827
农商银行app怎么登录不上去 浏览:47
查看已连接宽带密码 浏览:822
日本创建购物网站需要什么 浏览:723
数据拐点什么时候出来 浏览:640
怎么做到彻底理解编程语言 浏览:167
机器人和程序编程哪个好 浏览:563
怎么改苹果手机icloud账号和密码 浏览:526
什么是P2P数据库系统 浏览:494
js遍历标签数组长度 浏览:705

友情链接