imx6ull字元裝置驅動(1)
字元裝置驅動(1)
基於imx6ull以及其使用手冊
linux驅動
外設主要分為
- 字元裝置
感覺就是簡單的i/o?- 以位元組驅動為單位,順序訪問,字元裝置面向流裝置,
- 蜂鳴器,led,滑鼠,鍵盤
- 塊裝置
- 訪問塊裝置時候,是以扇區過著塊為基礎,屬於無序訪問
- 網路裝置
- 網路裝置就是網路介面卡等用來上網的裝置
- 網絡卡分為有線和無線兩種
字元裝置驅動
- 字元裝置驅動在linux系統中有其規定的框架
常規字元裝置驅動
為裝置定義一個相關結構體
初始化函式 xxx_init
- 向系統申請裝置號
- 申請裝置記憶體
- 呼叫cdev_init()初始化
- 呼叫cdev_add()向系統註冊裝置
解除安裝函式 xxx_exit的定義
- 釋放裝置號
- 呼叫cdev_add()
定義 file_operations
- 實現write()
- 實現read()
- 根據需要實現其他函式
//機構體模組
struct A{
struct cdev cdev;
};
struct A *dev;//建立一個裝置結構體指標
dev_t devno;//裝置號結構體
//讀裝置
ssize_t xxx_read(struct file *p,char __user *buf,size_t count,loff_t* f_pos)
{
copy_to_user(buf, , , );
}
//寫裝置
ssize_t xxx_write (struct file *filp, const char __user *buf, size_t count, loff_t* f_pos)
{
copy_from_user(..., buf, ...);
}
//檔案操作函式file_operations
struct file_operations xxx_fops = {
.owner = THIS_MODULE,
.read = xxx_read,
.write = xxx_write,
};
//裝置驅動模組載入函式
static int __init xxx_init(void)
{
...
devno = MKDEV(xxx_major, 0);
//(1)申請裝置號
if(xxx_major)
{
register_chrdev_region(devno, 1, "xxx_dev");
}
else
{
alloc_chrdev_region(&devno, 0, 1, "xxx_dev");
}
//(2)為裝置結構體申請記憶體(推薦使用devm_kzalloc)
dev = kzalloc(sizeof(struct xxx_dev_t), GFP_KERNEL);
//(3)初始化cdev
cdev_init(&dev.cdev, &xxx_fops);
dev.cdev.owner = THIS_MODULE;
//(4)向系統註冊裝置
cdev_add(dev.cdev, dev_no, 1);
}
module_init(xxx_init);
//裝置驅動模組解除安裝函式
static void __exit xxx_exit(void)
{
//釋放裝置號
unregister_chrdev_region(dev_no, 1);
//登出裝置
cdev_del(&dev.cdev);
...
}
module_exit(xxx_exit);
MODULE_LICENSE("GPL v2");
程式碼解釋
-
首先定義了機構體,直接定義了結構體cdev
struct cdev { struct kobject kobj; //內嵌的kobject 物件 struct module *owner; //所屬模組 const struct file_operations *ops; //檔案操作結構體 struct list_head list; dev_t dev; //裝置號 unsigned int count; };
-
然後定義了裝置號機構體,並在第37行申請了裝置號、
-
實現了檔案操作函式總的部分功能。
file_operations
中的成員函式似乎字元裝置驅動程式的主要內容 -
裝置驅動模組載入函式
-
為此函式註冊為裝置驅動的入口函式
-
初始化cdev,向系統註冊裝置
簡化版字元裝置驅動框架
可以使用這個兩個函式對上面的函式進行簡化
static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
//註冊字元裝置,返回申請的主裝置號
static inline void unregister_chrdev(unsigned int major, const char *name)
//登出字元裝置
//通過這兩個函式就不用一步一步的去註冊裝置了
兩個檔案就實現註冊裝置了,具體檔案於fs/char_dev.c
裝置號
· 各種裝置都以檔案的形式放在/dev 目錄下,稱為裝置檔案,應用程式可以開啟,關閉,讀寫這些裝置檔案,完成對應的裝置的操作。
組成
-
一個字元裝置或者塊裝置都有一個主次裝置號。
-
主裝置號都用來表示一個特定的驅動程式。
-
次裝置號永安裡表示該驅動程式的各個裝置
-
-
dev_t的資料型別表示裝置號
typedef __u32 __kernel_dev_t; typedef __kernel_dev_t dev_t;
-
dev_t是一個32位變數
linux裝置號範圍是0 - 4095
-
分配
-
寫好驅動之後,執行驅動
-
驅動編譯到linux核心中,linux核心執行時候會自動執行驅動程式
-
驅動程式編譯字尾為.ko的模組檔案
-
安裝和解除安裝.ko的命令
insmod xxx.ko
安裝驅動rmmod xxx.ko
解除安裝驅動實際上是呼叫module_init函式,這個函式會註冊一個載入函式模組,使用上述命令的時候就呼叫了函式
-
安裝和解除安裝驅動
modprobe xxx.ko
//安裝模組modprobe -r xxx.ko
//解除安裝模組這個命令在載入模組時候,會同時載入該模組所依賴的其他模組
-
-
實驗課題
(2)