分配和釋放設備號
如果沒有指定設備號的話就使用如下函數來 申請設備號:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
函數 alloc_chrdev_region 用於申請設備號,此函數有 4 個參數:
dev: 保存申請到的設備號。
baseminor: 次設備號起始地址, alloc_chrdev_region 可以申請一段連續的多個設備號,這些設備號的主設備號一樣,但是次設備號不同,次設備號以 baseminor 爲起始地址地址開始遞增。一般 baseminor 爲 0,也就是說次設備號從 0 開始。
count: 要申請的設備號數量。
name:設備名字
如果給定了設備的主設備號和次設備號就使用如下所示函數來註冊設備號即可:
int register_chrdev_region(dev_t from, unsigned count, const char *name)
from: 是要申請的起始設備號,也就是給定的設備號;
count :是要申請的數量,一般都是一個;
name: 是設備名字
註銷字符設備之後要釋放掉設備號
void unregister_chrdev_region(dev_t from, unsigned count)
新的字符設備註冊方法
1.字符設備結構
在linux中使用cdev結構體表示一個字符設備,cdev結構體在include/linux/cdev.h文件中的定義如下:
12 struct cdev {
13 struct kobject kobj;
14 struct module *owner;
15 const struct file_operations *ops;
16 struct list_head list;
17 dev_t dev;
18 unsigned int count;
19 };
在cdev中有兩個重要的成員變量:ops和dev,這兩個就是字符設備文件操作函數集合file_operations以及設備號dev_t
編寫字符設備驅動之前需要定義一個 cdev 結構體變量,這個變量就表示一個字符設備,如下所示:
struct cdev test_cdev;
2.cdev_init函數
定義好cdev變量以後就要使用cdev_init函數對其進行初始化,cdev_inti函數原型如下:
void cdev_init(struct cdev *cdev, const struct file_operations *fops);
舉個栗子
struct cdev cdev;
/*設備操作函數*/
static struct file_operation test_fops = {
.owner = THIS_MODULE,
....
};
cdev.owner = THIS_MODULE;
cdev_init(&cdev,&test_fops); //初始化cdev結構體變量
3.cdev_add 函數
cdev_add函數用於向linux系統添加字符設備(cdev結構體變量),首先使用cdev_init函數完成對cdev結構體變量的初始化,然後使用cdev_add函數向linux系統添加這個字符設備。cdev_add函數原型如下:
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
p: 指向要添加的字符設備(cdev結構體變量)
dev: 就是設備所使用的設備號
count:要添加的設備數量
struct cdev cdev;
/*設備操作函數*/
static struct file_operations test_fops = {
.owner = THIS_MODULE;
/*其他具體的初始項*/
};
testcdev.owner = THIS_MODULE;
cdev_init(&cdev, &test_fops); /* 初始化 cdev 結構體變量 */
cdev_add(&cdev, devid, 1); /* 添加字符設備 */
4.cdev_del函數
卸載驅動的時候一定要使用 cdev_del 函數從 Linux 內核中刪除相應的字符設備, cdev_del函數原型如下:
void cdev_del(struct cdev *p)
p:就是要刪除的字符設備
cdev_del(&testcdev); /* 刪除 cdev */
自動創建設備節點
在”老“的字符設備驅動中,當使用modprobe加載驅動程序以後還要使用命令“mknod”手動創建設備節點,但是在xx版本以後的內核可以使用mdev機制,當使用modprobe加載驅動模塊成功之後就會自動在/dev目錄下創建對應的設備文件。
1. mdev機制
udev 是一個用戶程序,在 Linux 下通過 udev 來實現設備文件的創建與刪除, udev 可以檢測系統中硬件設備狀態,可以根據系統中硬件設備狀態來創建或者刪除設備文件。比如使用modprobe 命令成功加載驅動模塊以後就自動在/dev 目錄下創建對應的設備節點文件,使用rmmod 命令卸載驅動模塊以後就刪除掉/dev 目錄下的設備節點文件。 使用 busybox 構建根文件系統的時候, busybox 會創建一個 udev 的簡化版本—mdev,所以在嵌入式Linux 中我們使用mdev 來實現設備節點文件的自動創建與刪除(複製粘貼過來的)
2.創建和刪除類
自動創建設備節點的工作是在驅動入口函數完成的,一般在cdev_add函數後面添加自動創建設備節點。
首先要創建一個class類,class是個結構體,定義在文件include/linux/device.h裏面
353 struct class {
354 const char *name;
355 struct module *owner;
356
357 struct class_attribute *class_attrs;
358 const struct attribute_group **dev_groups;
359 struct kobject *dev_kobj;
360
361 int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
362 char *(*devnode)(struct device *dev, umode_t *mode);
363
364 void (*class_release)(struct class *class);
365 void (*dev_release)(struct device *dev);
366
367 int (*suspend)(struct device *dev, pm_message_t state);
368 int (*resume)(struct device *dev);
369
370 const struct kobj_ns_type_operations *ns_type;
371 const void *(*namespace)(struct device *dev);
372
373 const struct dev_pm_ops *pm;
374
375 struct subsys_private *p;
376 };
class_create是類創建函數,class_create是宏定義,內容如下:
480 extern struct class * __must_check __class_create(struct module *owner,
481 const char *name,
482 struct lock_class_key *key);
487 #define class_create(owner, name) \
488 ({ \
489 static struct lock_class_key __key; \
490 __class_create(owner, name, &__key); \
491 })
將宏class_create展開以後內容如下:
struct class * class_create(struct module *owner,const char *name)
owne r: 一般爲THIS_MODULE
name:類名字
返回值:指向結構體 class 的指針,也就是創建的類。
卸載驅動程序的時候需要刪除掉類,類刪除函數爲 class_destroy,函數原型如下:
void class_destroy(struct class *cls);
參數 cls 就是要刪除的類。
3.創建設備
創建好類以後還不能實現自動創建設備節點,還要在這個類下創建一個設備。使用device_create函數在類下面創建設備,這個函數定義在include/linux/device.h
中,device_create函數原型如下:
struct device *device_create(struct class *class,struct device *parent,dev_t devt,void *drvdata,const char *fmt, ...)
device_create是一個可變參數函數。
class: 設備要創建哪個類下面;
parent:父設備,一般爲NULL
devt:設備號
drvdata:設備可能會使用的一些數據,一般爲NULL
fmt:設備名字,如果設置fmt=xxx的話,就會生成/dev/xxx這個設備文件
返回值:創建好的設備
卸載驅動的時候需要刪除創建的設備,設備刪除函數爲device_destroy,函數原型如下:
void device_destroy(struct class *class, dev_t devt)
參數 classs 是要刪除的設備所處的類,參數 devt 是要刪除的設備號
舉個栗子
//說明:xxx指的是設備名字
struct class *class; //類
struct device *device; //設備
dev_t devid; //設備號
//驅動入口函數
static int __init xxx_init(void)
{
//創建類
class = class_create(THIS_MODULE,"xxx");
//創建設備
device = device_create(class,NULL,devid,NULL,"xxx");
return 0;
}
//驅動出口函數
static void __exit led_exit(void)
{
//刪除設備
device_destroy(class,devid);
//刪除類
class_destroy(class);
}
module_init(xxx_init);
module_exit(xxx_exit);