1. 程式人生 > >linux字符設備驅動--基本知識介紹

linux字符設備驅動--基本知識介紹

方法 src lin bdc || makefile 要求 進程虛擬地址 編譯內核

一、設備驅動的分類

1.字符設備

字符設備是指那些能一個字節一個字節讀取數據的設備,如LED燈、鍵盤、鼠標等。字符設備一般需要在驅動層實現open()、close()、read()、write()、ioctl()等函數。

2.塊設備

塊設備與字符設備類似,一般是像磁盤一樣的設備。在塊設備中還可以容納文件系統,並存儲大量的信息。在linux系統中,進行塊設備讀寫時,每次只能傳輸一個或者多個塊。linux也可以讓應用程序像訪問字符設備一樣訪問塊設備,一次只讀取一個字節。

3.網絡設備

網絡設備主要負責主機之間的數據交換,與字符設備和塊設備完全不同,網絡設備主要是面向數據包的接收和發送而設計的。網絡設備沒有實現類似塊設備和字符設備的read()、write()、ioctl()等函數,但是實現了一種套接字接口,任何網絡數據傳輸都可以通過套接字來完成。

二、基礎知識介紹

1.直接將模塊編譯進內核(主要修改兩個文件:Kconfig Makefile)

1.1將編寫好的模塊程序復制到內核代碼中(一般根據驅動內容來選擇合適的路徑)

1.2進入到該路徑,打開Kconfig文件:vi Kconfig

說明:Kconfig文件描述了所屬目錄源文件相關的內核配置菜單

1.3添加:config HELLO_WORLD

 bool "helloworld"

則在menuconfig菜單中出現新的目錄:helloworld

1.4修改該目錄下的Makefile文件:obj -$(CONFIG_HELLO_WORLD) += hello.o

1.5編譯內核

三、字符設備驅動程序設計

1.概念介紹

1.1主次設備號

主設備號用來標識與設備文件相連的驅動程序;次設備號被驅動程序用來辨別操作的是哪個設備。

linux內核中通過dev_t類型描述主次設備號,dev_t其實質為unsigned int 32位整數,高12位為主設備號,低20位為次設備號。通過宏MAJOR(dev_t dev)獲得主設備號,MINOR(dev_t dev)獲得次設備號。

1.2分配主設備號

靜態申請:確定一個系統沒有使用的設備號,使用register_chrdev_region函數註冊。但是該方式在驅動較多的情況下,很容易導致設備號沖突,而使驅動程序無法註冊。

動態分配:通過linux內核自動分配一個未使用的主設備號。使用alloc_chrdev_region()分配設備號。但是該方式無法在安裝驅動前創建設備文件,因為安裝前驅動程序還沒有分配到主設備號。

1.3創建設備文件

使用mknod命令手動創建

mknod用法:mknod filename type major minor

filename:設備文件名

type:設備文件類型(字符設備:c 塊設備:b)

major:主設備號

minor:次設備號

自動創建:

2.重要結構

2.1 struct file

代表一個打開的文件,系統中每個打開的文件在內核空間都有一個關聯的struct file,它是由內核在打開文件時創建,在文件關閉時釋放。

重要成員:loff_t f_pos /*文件讀寫位置*/

struct file_operations *f_op

2.2 struct inode

用來記錄文件的物理上的信息,因此它和代表打開文件的file結構是不同的,一個文件可以對應多個file結構,但只有一個inode結構。

重要成員:dev_t i_rdev:設備號

2.3 struct file_operations

一個函數指針的集合,定義能在設備上進行的操作。結構中的成員指向驅動中的函數,這些函數實現一個特別的操作,對於不支持的操作保留為NULL。

3.應用程序訪問驅動程序

當應用程序使用read函數時,傳入要操作的文件file,系統會調用vfs_read函數,根據file去內核中查找相應的file_operations中指定的read函數,vfs_read函數(在read_write.c中)代碼如下:

技術分享圖片
 1 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
 2 {
 3     ssize_t ret;
 4 
 5     if (!(file->f_mode & FMODE_READ))
 6         return -EBADF;
 7     if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
 8         return -EINVAL;
 9     if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
10         return -EFAULT;
11 
12     ret = rw_verify_area(READ, file, pos, count);
13     if (ret >= 0) {
14         count = ret;
15         if (file->f_op->read)
16             ret = file->f_op->read(file, buf, count, pos);
17         else
18             ret = do_sync_read(file, buf, count, pos);
19         if (ret > 0) {
20             fsnotify_access(file);
21             add_rchar(current, ret);
22         }
23         inc_syscr(current);
24     }
25 
26     return ret;
27 }
View Code

4.設備註冊

在linux2.6的內核中,字符設備使用struct cdev來描述。

字符設備的註冊過程可分為三步:1.分配cdev;2.初始化cdev;3.添加cdev;

四、函數解析

1.分配主設備號相關函數

int register_chrdev_region(dev_t from,unsigned count,coust char *name)

功能說明:申請使用從from開始的count個設備號(主設備號不變,次設備號增加)

參數:from:希望申請使用的設備號

   count:希望申請使用的設備號數目

   name:設備號(體現在/proc/devices)

int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name)

功能說明:請求內核動態分配count個設備號,且次設備號從baseminor開始。

參數:dev:分配完返回的設備號

   baseminor:起始次設備號

   count:需要分配的設備號數目

   name:設備名(體現在/proc/devices)

void unregister_chrdev_region(dev_t from,unsigned count)

功能說明:釋放從from開始的count個設備號

參數:from:需要釋放的設備號

   count:希望釋放的設備號數目

2.設備註冊相關函數

struct cdev *cdev_alloc(void)

功能說明:分配cdev

返回值:分配的cdev指針

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

功能說明:初始化字符設備

參數:cdev:待初始化的cdev結構

   fops:設備對應的操作函數集

int cdev_add(struct cdev *p,dev_t dev,unsigned count)

功能說明:添加字符設備

參數:p:待添加到內核的字符設備結構

   dev:設備號

   count:添加的設備個數

int cdev_del(struct cdev *p)

功能說明:設備註銷

參數:p:要註銷的字符設備結構

3.設備操作函數

int (*open)(struct inode *,struct file *)

功能說明:在設備文件上的第一個操作,並不要求驅動程序一定要實現這個方法。如果該項為NULL,設備的打開操作永遠成功。系統中通過fs/open.c中的do_sys_open函數實現。

void (*release)(struct inode *,struct file *)

功能說明:當設備文件被關閉時調用這個操作,與open相同,release也可以沒有。

ssize_t (*read)(struct file *,char __user *,size_t,loff_t *)

功能說明:從設備中讀取數據。

ssize_t (*write)(struct file *,const char __user *,size_t,loff_t *)

功能說明:向設備發送數據。

unsigned int (*poll)(struct file *,struct poll_table_struct *)

功能說明:對應select系統調用。

int (*ioctl)(struct inode *,struct file *,unsigned int,unsigned long)

功能說明:控制設備。

int (*mmap)(struct file *,struct vm_area_struct *)

功能說明:將設備映射到進程虛擬地址空間中。

off_t (*Ilseek)(struct file *,loff_t,int)

功能說明:修改文件的當前讀寫位置,並將新位置作為返回值。

linux字符設備驅動--基本知識介紹