驅動模塊設備節點的自動創建,不再需要 mknod
.
背景.
Linux 2.6 引入了動態設備管理, 用 udev
作爲設備管理器(應用在x86), 相比之前的靜態設備管理,在使用上更加方便靈活。udev
根據 sysfs
系統提供的設備信息實現對/dev
目錄下設備節點的動態管理,包括設備節點的創建、刪除等
引入 udev
自動創建設備節點後,比如在我們使用的 insmod led_drv.ko
時候,udev
自動幫我們在 /dev
目錄下創建設備節點;
使用 rmmod led_drv
時候,udev
自動幫我們在 /dev
目錄下刪除設備節點;
這裏並不需要我們再人爲的mknod /dev/led_dev c 239 0
來生成爲該設備在/dev目錄下創建設備文件了。
如要編寫一個能夠使用 udev
管理的設備驅動,需要在驅動代碼中調用 class_create()
爲設備創建一個 class 類
,再調用 device_create()
爲每個設備創建對應的設備即可,從此告別需要繁瑣的 mknod ....
。
根據源碼解析.
設備類的申請等都在初始化函數中完成,故取前面的led_dev.c
代碼中的初始化函數來解析
static struct class *led_class;
static struct device *led_dev_device;
...
...
...
//入口函數
static int __init gec6818_led_init(void)
{
int ret = 0;
ret=alloc_chrdev_region(&led_dev_num,0,1,"myled"); //動態申請設備號,這裏的“myled”相當於代號,並不重要
if (ret < 0)
{
printk("<3>""register chrdev region error\n");
return -1;
}
//字符設備的初始化 void cdev_init(struct cdev *cdev, const struct file_operations *fops)
cdev_init(&led_cdev, &led_fops);
//將設備加入到內核 int cdev_add(struct cdev *p, dev_t dev, unsigned count)
ret = cdev_add(&led_cdev, led_dev_num, 1);
if(ret < 0)
{
printk("<3>""cdev_add error\n");
goto err_cdev_add;
}
led_class=class_create(THIS_MODULE, "myled"); //這裏的“myled”會顯示在/sys/class目錄當中
if (IS_ERR(led_class)) //判斷當前指針是否爲錯誤碼指針,大於0爲錯誤碼指針
{
ret = PTR_ERR(led_class); //將指針轉爲錯誤碼
printk("class_create led device fail\n");
goto err_class_create;
}
led_dev_device = device_create(led_class, NULL, led_dev_num, NULL, "myled");//這裏的“myled”是設備的名字,如果創建成功,就可以在/dev目錄看到該設備的名字
if (IS_ERR(led_dev_device)) //創建設備失敗
{
ret = PTR_ERR(led_dev_device);
printk("device_create led fail\n");
goto err_device_create;
}
printk("<3>""device num: %d\n", MAJOR(led_dev_num));
printk("<3>""device last num: %d\n", MINOR(led_dev_num));
return 0;
err_device_create:
class_destroy(led_class); //創建led類失敗,釋放內存資源
err_class_create:
cdev_del(&led_cdev); //從系統刪除字符設備
err_cdev_add:
unregister_chrdev_region(led_dev_num, 1); //註銷設備號
return ret;
}
類的創建 class_create() 頭文件: #include <linux/device.h>函數解析.
代碼原型:
參數 | 作用 |
---|---|
owner | class的所有者,默認寫THIS_MODULE |
name | 自定義class的名字,會顯示在/sys/class目錄當中 |
返回值 | 成功:就返回創建好的class指針,失敗:就返回錯誤碼指針 |
設備的創建 device_create() 頭文件: #include <linux/device.h>
代碼原型:
參數 | 作用 |
---|---|
class | 創建device是屬於哪個類 |
parent | 默認爲NULL |
devt | 設備號,設備號必須正確,因爲這個函數會在/dev目錄下幫我們自動創建設備文件 |
drvdata | 默認爲NULL |
fmt | 設備的名字,如果創建成功,就可以在/dev目錄看到該設備的名字 |
返回值 | 成功:就返回創建好的設備指針,失敗:就返回錯誤碼指針 |
類的銷燬 class_destroy() 頭文件: #include <linux/device.h>
代碼原型:
參數 | 作用 |
---|---|
class | 創建device是屬於哪個類 |
設備的銷燬 device_destroy() 頭文件: #include <linux/device.h>
代碼原型:
參數 | 作用 |
---|---|
class | 創建device是屬於哪個類 |
devt | 設備號 |
錯誤碼.
錯誤碼指針的判斷
static inline long __must_check IS_ERR(const void *ptr) { return IS_ERR_VALUE((unsigned long)ptr); }
將錯誤碼指針轉換爲數值(即錯誤碼)static inline long __must_check PTR_ERR(const void *ptr) { return (long) ptr; }