自动创建设备节点


内核:3.8.0-19-generic
文件的管理使用的是 sysfs.(由udev制作的文件系统)


1. 创建字符设备 生成设备节点
2. busybox
  Linux System Utilities --->
  [*] mdev
  [*] Support /etc/mdev.conf
  [*] Support command execution at device addition/removal
3. kernel
  File systems --->
  Pseudo filesystems --->
  [*] sysfs file system support
  [*] Virtual memory file system support (former shm fs)
  [*] Tmpfs POSIX Access Control Lists
4. rootfs
  vi ./etc/init.d/rcS
  mount -t tmpfs mdev /dev
  mkdir /dev/pts
  mount -t devpts devpts /dev/pts
  mount -t sysfs sysfs /sys
  mount -a
  echo /sbin/mdev > /proc/sys/kernel/hotplug
  mdev -s


说明:

当使用利用udev制作的文件系统时,Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点。

内核中定义了struct class结构体,一个struct class结构体类型变量对应一个类(有待商榷),内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。


定义在<linux/device.h>中
class结构:该结构体类型变量对应一个设备类,被创建的类存放在/sys目录下面
device结构:该结构体类型变量对应设备,被创建的设备存放于/sys目录下面
在加载驱动模块时,用户空间中的udev会自动响应device_create()函数,在/sys下寻找对应的类,从而为这个设备在/dev目录下创建设备文件

内核版本问题:
在内核2.4版本中使用devfs_register
在内核2.6早起版本中使用class_device_register

2.6.35.7中使用class_create和device_create

类的创建和销毁
定义在<linux/device.h>中
实现在内核源码drivers/base/class.c中
类创建
为设备驱动创建一个设备类
struct class *class_create(struct module *owner, const char *name);
owner:创建设备类的驱动模块拥有者
name:待创建的设备类的类名称
返回:创建好的设备类的指针,失败返回NULL
类销毁
销毁设备驱动创建的对应设备类
void class_destroy(struct class *cls);
cls:待销毁的设备类

设备创建和销毁
定义在<linux/device.h>中
实现在内核源码drivers/base/core.c中
设备创建
为设备创建对应的设备文件
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
class:待创建的设备所属设备类
parent:指向可能存在的父设备的指针
devt:待创建设备的设备号(包括主设备号和次设备号)
drvdata:设备保留的驱动私有数据指针
fmt:待创建的设备文件名称
返回:创建好的device的指针,失败返回NULL
设备销毁
删除设备对应的设备文件
void device_destroy(struct class *class, dev_t devt);
class:待销毁的设备所属设备类
devt:待销毁设备的设备号(包括主设备号和次设备号)





示例程序(一个简单的字符驱动):

#include <linux/module.h>		/* For module specific items */
#include <linux/moduleparam.h>		/* For new moduleparam's */
#include <linux/types.h>		/* For standard types (like size_t) */
#include <linux/errno.h>		/* For the -ENODEV/... values */
#include <linux/kernel.h>		/* For printk/panic/... */
#include <linux/fs.h>			/* For file operations */
#include <linux/ioport.h>		/* For io-port access */
#include <linux/platform_device.h>	/* For platform_driver framework */
#include <linux/init.h>			/* For __init/__exit/... */
#include <linux/uaccess.h>		/* For copy_to_user/put_user/... */
#include <linux/io.h>			/* For inb/outb/... */

#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/kdev_t.h>

 
int hello_open(struct inode *inode, struct file *file)
{
	printk("this is hello_open\n");

	return 0;
}


ssize_t hello_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	printk("this is hello_read\n");
	return 0;
}


ssize_t hello_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
     

    printk("this is hello_write\n");


      return 0;
}

struct file_operations hello_ops = {
	.owner  = THIS_MODULE,
	.open   = hello_open,
	.read   = hello_read,
	.write  = hello_write
};


static struct cdev hello_devs;
static struct class *first_class;
int major = 200;   // 主设备号为200
/* 入口函数 */
static int __init hello_init(void)
{

     int result;

	//获得设备号
	dev_t dev=MKDEV(major, 0);
       if (major)   //如果major不为0,说明自己申请的主设备号可以用,这时可以静态分配 
	  result = register_chrdev_region(dev, 1, "xyz");
       else
	 {
		/* 设备号的动态分配 */
		result = alloc_chrdev_region(&dev, 0, 1, "xyz");   
		major = MAJOR(dev);
          }
   
    //初始cdev_init(),实现fops 与 struct cdev (字符设备结构体)的关联
  	cdev_init(&hello_devs, &hello_ops);
	hello_devs.owner = THIS_MODULE;
 	hello_devs.ops = &hello_ops;
   
   
   //添加cdev到内核  设备号 dev_t 与  struct cdev 的关联
       cdev_add(&hello_devs,dev,1);
       printk("The major of the gpio device is %d\n", major);
     

   // automatic create device node 
	first_class= class_create(THIS_MODULE, "xyz"); /* sysfs */
    /* register your own device in sysfs, and this will cause udev to create corresponding device node */  
	device_create(first_class, NULL, MKDEV(major, 0), NULL, "xyz");




	return 0;
}


//出口函数 
static void __exit hello_exit(void)
{

       	//删除设备与设备类 
	device_destroy(first_class, MKDEV(major, 0));
	class_destroy(first_class);

	//注销cdev 
	cdev_del(&hello_devs);

   

	//注销设备号
	unregister_chrdev_region(MKDEV(major, 0), 1);
	printk("Gpio device uninstalled\n");
  
}


Makefile 的写法:

ifneq ($(KERNELRELEASE),)
obj-m := led_drive.o 
else
KDIR  := /lib/modules/$(shell uname -r)/build
PWD   := $(shell pwd)
default:
	$(MAKE) -C $(KDIR) M=$(PWD) modules 
endif 

.PHONY:clean
clean:
	@rm -rf *.o *.ko .tmp_versions *~ Module.symvers .*.cmd *.mod.c *.order
执行命令:make

插入模块:sudo insmod led_drive.ko


插入模块成功的标志:


设备节点的查询:


移除模块:

rmmod led_drive (不用加.ko结尾)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值