自動創建設備節點


內核: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結尾)

發佈了25 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章