04 字元裝置的註冊和kmalloc的故事

2021-07-13 04:40:12 字數 3957 閱讀 9848

1、字元裝置註冊的兩種方法

(1)早期經典

int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

void unregister_chrdev(unsigned int major, const char *name); ( 注:書上寫的是int型,我在3.2核心上編譯並檢視原型為void)

宣告fops

struct file_operations fops ;

register_chrdev的呼叫:為給定的主裝置號註冊0~255作為次裝置號,為每個裝置建立乙個對應的預設cdev結構。

unregister_chrdev:其中major、name 必須與傳遞給register_chrdev函式的值保持一致,否則會呼叫失敗。

一些驅動程式通過此類方法註冊字元裝置,也省去了register_chrdev_region的呼叫。

8 int major = 250;

9 int minor = 25;

10 unsigned int dev_num = 1;

11 char *dev_name = "scull";

12 13 static struct file_operations fops = ;

16 17 static int __init scull_init(void)

18 26 printk(kern_info "register_chrdev ok!\n");

27 28 return 0;

29 30 reg_fail:

31 return ret;

32

33 }

34 static void __exit scull_exit(void)

35 39 40 module_init(scull_init);

41 module_exit(scull_exit);

(2)cdev結構

#include

執行時動態分配cdev結構

struct cdev cdev = cdev_alloc();         

cdev->owner = this_module;

cdev->ops = &cdev_fops;

靜態分配cdev

struct cdev cdev;

void cdev_init(struct cdev *cdev, struct file_operations *fops);

cdev.owner = this_module;

cdev設定好後,通過cdev_add告訴核心,裝置可以操作了

int cdev_add(struct cdev *cdev, dev_t num, unsigned int count);

void cdev_del(struct cdev *cdev);

呼叫cdev_del後,就不能再訪問cdev結構了。所以該操作常在exit時呼叫。

13 struct cdev my_cdev;

14 struct file_operations scull_fops = ;

17 18 static void init_cdev(void)

19 30 printk(kern_info "cdev_add ok\n");

31 err1:

32 unregister_chrdev_region(devno, dev_num);

33 }

34 static int __init scull_init(void)

35 44 init_cdev();

45 46 printk(kern_info "scull init ok\n");

47 48 return 0;

49 err1:

50 return ret;

51 }

52 static void __exit scull_exit(void)

53 61 module_init(scull_init);

62 module_exit(scull_exit);

注:驅動程式中習慣將裝置封裝為乙個結構體:(這是今天糾結最久的一件事,甚至引爆了oops,當然最主要的原因在於c語言指標基礎不牢,一定要好好記錄出的幾種錯)

首先,封裝乙個裝置結構體:(這個應該沒有什麼問題,很好地體現了驅動中物件導向的思想)

struct scull_dev ;

2、定義變數:(開始出錯)

struct scull_dev *dev;

我最開始定義的不是指標,而是struct scull_dev dev。所以呼叫時&dev->my_cdev,編譯出錯:

invalid type argument of '->'(不是指標,怎麼能用 ->呢)

後來我用了指標,直接呼叫;(很開心,編譯通過,但是大灰狼來了。。。)

指標不給他分配空間怎麼能直接用呢???當發生了這種錯誤,你修改後想解除安裝重新insmod恐怕也不行了,估計只能重啟咯

3、後來我意識到應該kmalloc(可是我在函式外面定義的時候同時呼叫malloc,編譯報錯,我很糾結,查malloc的用法明明就是這麼寫的啊。)

struct scull_dev *dev = kmalloc(sizeof(struct scull_dev), gfp_kernel);

error: initializer element is not constant

4、我接著檢視linux原始碼中的一些kmalloc例子用法,發現malloc之後,都會進行檢查如下:

30         if (!dev)     

突然意識到我不在函式中寫的話,return**啊,return毛線啊,於是仔細參考原始碼中使用kmalloc的用法,終於明白了應該怎麼辦。我被自己蠢哭了。

5、為了養成好習慣,在exit時,新增了kfree釋放:kfree(&dev);結果大灰狼又來了,(基礎不牢,真的地動山搖啊)明明是

kfree(dev);就可以了,非要畫蛇添足。完全被自己蠢哭。

最後附上正確用法:

#include //kmalloc需要的標頭檔案
27 struct scull_dev *dev;

37 static void init_cdev(void)

......

} 77 static void __exit scull_exit(void)

(2)cdev結構

#include

執行時動態分配cdev結構

struct cdev cdev = cdev_alloc();         

cdev->owner = this_module;

cdev->ops = &cdev_fops;

靜態分配cdev

struct cdev cdev;

void cdev_init(struct cdev *cdev, struct file_operations *fops);

cdev.owner = this_module;

cdev設定好後,通過cdev_add告訴核心,裝置可以操作了

int cdev_add(struct cdev *cdev, dev_t num, unsigned int count);

void cdev_del(struct cdev *cdev);

呼叫cdev_del後,就不能再訪問cdev結構了。所以該操作常在exit時呼叫。

2 4 2 6字元裝置註冊對比

但大多新書早已經是講2.6的介面了,如ldd3 國嵌 宋寶華的書 1 早期版本的字元裝置註冊。早期版本的裝置註冊使用函式 register chrdev 呼叫該函式後就可以向系統申請 主裝置號,如果 register chrdev 操作成功,裝置名就會出現在 proc devices 檔案裡。在關閉...

04字元和字串

字串一旦賦值了,就不能修改了。字串的兩種表示方式 雙引號和反引號,反引號以原生形式輸出 rune s2 將s2強制轉換為切片,strings s3 將切片轉換為字串 len str 求長度 或fmt.sprintf 拼接字串 strings.split 分割strings.contains 判斷是否...

2 6字元裝置驅動

chardev.c include include for file f op include include for copy to user include for cdev cdev init,cdev add module license gpl module author helight ...