一、設備號
1.1. 什么是設備號
設備號是用來標記一類設備以及區分這類設備中具體個體的一組號碼。
設備號由主設備號和次設備號組成。主設備號的作用為標記一類設備、用于標識設備驅動程序,而次設備號的作用是為了區分這類設備中的具體個體設備及用于標識同一驅動程序下的具體設備;通過該區分,系統可以準確的識別和操作每一個設備和對設備的有效管理,提高設備的利用率和可擴展性。
在Linux中設備號的定義通常使用dev_t
,該類型需要包含頭文件include/linux/types.h
,查看其定義我們可以發現它其實就是一個32位的無符號整型變量;其中主設備號為高12位(同類型驅動個數為0~212?10~2^{12}-10~212?1),次設備號為低20位(掛載設備為0~220?10~2^{20}-10~220?1)。
Linux中為我們提供了相關宏用于處理設備號,這些宏位于include/linux/kdev_t.h
中:
#define MINORBITS 20 /* 次設備號位數 */
#define MINORMASK ((1U << MINORBITS) - 1)/* 獲取主設備號 */
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
/* 獲取次設備號 */
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
/* 主+次組成設備號 */
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
1.2. 設備號的獲取、釋放和查看
1.2.1. 獲取設備號
獲取設備號的方式有兩種:靜態分配和動態分配,都是Linux內核提供的接口,該接口位于linux/fs.h
中。
- 靜態分配
register_chrdev_region
函數原型:
/*** register_chrdev_region() - register a range of device numbers* @from: the first in the desired range of device numbers; must include the major number.* @count: the number of consecutive device numbers required* @name: the name of the device or driver.** Return value is zero on success, a negative error code on failure.
*/
int register_chrdev_region(dev_t from, unsigned count, const char *name);
- 動態分配
alloc_chrdev_region
函數原型:
/*** alloc_chrdev_region() - register a range of char device numbers* @dev: output parameter for first assigned number* @baseminor: first of the requested range of minor numbers* @count: the number of minor numbers required* @name: the name of the associated device or driver** Allocates a range of char device numbers. The major number will be* chosen dynamically, and returned (along with the first minor number)* in @dev. Returns zero or a negative error code.*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
1.2.2. 釋放設備號
- 釋放設備號
函數原型:
/*** unregister_chrdev_region() - return a range of device numbers* @from: the first in the range of numbers to unregister* @count: the number of device numbers to unregister** This function will unregister a range of @count device numbers,* starting with @from. The caller should normally be the one who* allocated those numbers in the first place...*/
void unregister_chrdev_region(dev_t from, unsigned count);
1.2.3. 查看設備號
- 指令
lsblk
待補充 - 查看文件
/proc/devices
通過cat /proc/devices
將所有的設備號全部打印出來,如下:
Character devices: # 字符設備1 mem4 /dev/vc/04 tty4 ttyS
Block devices: # 塊設備7 loop8 sd9 md
254 mdp
259 blkext
1.3. 栗子
驅動代碼
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/kdev_t.h>int Isalloc = 0; /* 是否動態申請設備號:0-靜態申請、非0-動態申請 */
int Major = 0;
int Minor = 0;module_param(Isalloc, int, S_IRUGO);
MODULE_PARM_DESC(Isalloc, "e.g.是否動態申請: 0-靜態申請(需輸入設備號),非0-動態申請(輸入設備號無效).");
module_param(Major, int, S_IRUGO);
MODULE_PARM_DESC(Major, "e.g.主設備號");
module_param(Minor, int, S_IRUGO);
MODULE_PARM_DESC(Minor, "e.g.次設備號");dev_t chrdev_region = 0;static int chrdev_region_init(void)
{if (0 == Isalloc){/* 靜態申請設備號 */chrdev_region = MKDEV(Major, Minor);/* zhf是驅動程序名稱 */int i32Ret = register_chrdev_region(chrdev_region, 1, "zhf");if (0 > i32Ret){printk("register_chrdev_region err %d \n", i32Ret);}}else{/* 動態申請設備號 zhf是驅動程序名稱 */int i32Ret = alloc_chrdev_region(&chrdev_region, 0, 1, "zhf");if (0 > i32Ret){printk("alloc_chrdev_region err %d \n", i32Ret);}}/* 設備號打印 */printk("chrdev region ok major:%d minor:%d\n", MAJOR(chrdev_region), MINOR(chrdev_region));return 0;
}static void chrdev_region_exit(void)
{/* 設備號銷毀 */unregister_chrdev_region(&chrdev_region, 1);printk("unregister_chrdev_region ok \n");
}module_init(chrdev_region_init);
module_exit(chrdev_region_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhf");
二、字符設備驅動
2.1. 什么是字符設備
字符設備是一種用于傳輸字符或字節流的設備。其實就是傳"acnah"
這樣的ASSIC
碼。常見的字符設備包括鍵盤、鼠標、串口等設備。字符設備以字節為單位進行讀取和寫入。
字符設備的交互方式:字符設備在系統中會被表示為設備文件,用戶可通過打開設備文件與字符設備進行交互。
2.2. 字符設備的操作
2.2.1. 注冊字符設備
定義字符類設備需要用到cd