1.2 Linux 雜項裝置驅動模型
在目前的核心版本中,存在三種流行的字元裝置程式設計模型:雜項裝置驅動模型,早期經典標準字元裝置驅動模型, Linux 2.6 標準字元裝置驅動模型。
Linux 系統借鑑了面向物件的思想來管理裝置驅動 ,每一類裝置都都會有定義一個特定的結構體來描述它,這個結構體包含了裝置的基本資訊,以及操作裝置方法(函式指標),所以,編寫程式實際上就是實現核心結構,
然後把這結構註冊到核心中。
所以,學習一種裝置驅動,第一步就是要學習該裝置對應資料結構,弄清楚成員是什麼意思,什麼作用,以及是否一定需要實現成員。
1.2.1 雜項裝置的核心資料結構
1. 結構體:
標頭檔案路徑:
include\Linux\miscdevice.h
struct miscdevice {
int minor; //次裝置號
const char *name; //裝置名,/dev/下的裝置檔名
const struct file_operations *fops; //檔案操作方法集合指標
//以下是核心使用,使用者不需要關注
struct list_head list;//用於掛接到雜項裝置連結串列misc_list上。
struct device *parent;//指向父裝置
struct device *this_device;//在建立裝置節點時指向函式device_create()返回的裝置結構
const char *nodename;
umode_t mode;
};
上面結構中核心部分有三個成員: minor, name, fops這三個成員必須實現。
fops 成員對應的結構定義: struct file_operations。
它定義了一系列的操作裝置的函式指標 ,使用者根據自己需要實現所需要功能的指標成員。
include\Linux\fs.h
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int); //移動游標,對應 Linux 系統應用程式設計介面的 lseek 函式
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 *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
.....................
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
.....................
int (*release) (struct inode *, struct file *);
.....................
};
常用成員說明:
llseek: 移動檔案指標,對應 Linux 系統應用程式設計介面的 lseek 函式。
read: 從裝置檔案中讀取資料,對應 Linux 系統應用程式設計介面的 read 函式。
write: 向裝置檔案寫入資料,對應 Linux 系統應用程式設計介面的 write 函式。
poll: 輪詢函式,對應 Linux 系統應用程式設計介面的 poll 函式或 select 函式
unlocked_ioctl: i/o 控制,對應 Linux 系統應用程式設計介面的 ioctl 函式
mmap:記憶體對映, 對應 Linux 系統應用程式設計介面的 mmap 函式
open:開啟裝置,操作裝置的第一步,對應系統應用程式設計介面的 open 函式
release:關閉裝置,操作裝置的最後一步,對應系統應用程式設計介面的 close 函式
實際應用中只會實現一部分成員,不可能全部實現,也沒有必要實現全部成員。
1.2.2 雜項裝置的裝置號
主裝置號: 固定是 10
次裝置號: 0~255. (寫 255 時候核心會動態分配一個能用的次裝置號)
每個雜項裝置驅動次裝置不能相同。 當你不能確定哪一個次裝置號是可用的情況下需要使用 255,這樣核心可以幫你找一個可以使用的號。
(如果雜項裝置的裝置號被置為MISC_DYNAMIC_MINOR,則表明該裝置的裝置號要從新自動分配。)
1.2.3 雜項裝置特徵
安裝雜項裝置會自動在/dev 目錄生成裝置檔案。
早期經典標準字元裝置驅動模型和 Linux2.6 標準字元裝置驅動不會自動生成裝置檔案。
呼叫一次 misc_register 註冊函式,只會佔用一個次裝置號。
1.2.4 雜項設備註冊/登出函式
實現了 struct miscdevice 結構必須的成員後,還需要使用核心專用函式向系統註冊,這樣才可以完成一個驅動 的程式設計。
1. 註冊函式
int misc_register(struct miscdevice * misc);
功能:向核心註冊一個雜項字元裝置
引數:
misc 已經實現好 min,name, fops 三個成員的 struct miscdevice 結構變數的地址
返回: 0:註冊成功;
<0 :失敗,返回失敗錯誤碼
2. 登出函式
這個函式功能的 misc_register 函式相反。
int misc_deregister(struct miscdevice *misc);
功能:登出一個已經註冊到核心中雜項字元裝置
引數: misc 已經註冊的 struct miscdevice 結構變數的地址
返回: 0:註冊成功;
<0 :失敗,返回失敗錯誤碼
1.2.5 雜項裝置驅動模型的程式碼模板
1.2.5.1 編寫驅動程式的前奏,基礎理論
1. 驅動程式是以核心模組形式編寫,所以要編寫驅動,先編寫使用一個模組檔案做為起點。
2. 每類裝置都有一個核心結構,必須定義核心結構的變數
3. 編寫一類裝置驅動程式就是實現其核心結構必須的成員
4. 把實現好的核心結構變數向核心註冊---在模組載入函式中註冊
5. 在模組解除安裝函式中把核心結構登出
1.2.5.2 編寫雜項裝置驅動程式碼模板
驅動程式碼模板:
#include <linux/module.h>
#include <linux/init.h>
//包含必須的標頭檔案
#include <linux/fs.h>
#include <linux/miscdevice.h>
//以下是檔案操作方法的具體實現程式碼
static int xxx_open(struct inode *pinode, struct file *pfile )
{
printk(KERN_EMERG"line:%d, %s is call\n", __LINE__, __FUNCTION__);
return 0;
}
static ssize_t xxx_read(struct file *pfile,
char __user *buf, size_t count, loff_t *poff)
{
printk(KERN_EMERG"line:%d, %s is call\n", __LINE__, __FUNCTION__);
return count;
}
static ssize_t xxx_write(struct file *pfile,
const char __user *buf, size_t count, loff_t *poff)
{
printk(KERN_EMERG"line:%d, %s is call\n", __LINE__, __FUNCTION__);
return count;
}
static loff_t xxx_llseek(struct file *pfile, loff_t off, int whence)
{
printk(KERN_EMERG"line:%d, %s is call\n", __LINE__, __FUNCTION__);
return off;
}
static int xxx_release (struct inode *pinode, struct file *pfile)
{
printk(KERN_EMERG"line:%d, %s is call\n", __LINE__, __FUNCTION__);
return 0;
}
static long xxx_unlocked_ioctl (struct file *pfile,
unsigned int cmd, unsigned long args)
{
printk(KERN_EMERG"line:%d, %s is call\n", __LINE__, __FUNCTION__);
return 0;
}
//檔案操作方法集合指標
static const struct file_operations mymisc_fops = {
.open = xxx_open,
.read = xxx_read,
.write = xxx_write,
.llseek = xxx_llseek,
.release = xxx_release,
.unlocked_ioctl = xxx_unlocked_ioctl,
};
//定義核心結構
static struct miscdevice misc = {
.minor = 255,
.name = "mymisc", ///dev 目錄下的裝置名
.fops = &mymisc_fops,
};
static int __init mymisdevice_init(void)
{
int ret;
//註冊核心結構
ret = misc_register(&misc);
if(ret < 0) {
printk(KERN_EMERG"misc_register error\n");
return ret;
}
printk(KERN_EMERG"misc_register ok\n");
return 0;
}
static void __exit mymisdevice_exit(void)
{
int ret;
//登出核心結構
ret = misc_deregister(&misc);
if(ret < 0) {
printk(KERN_EMERG"misc_deregister error\n");
return ;
}
printk(KERN_EMERG"misc_deregister ok\n");
}
module_init(mymisdevice_init);
module_exit(mymisdevice_exit);
MODULE_LICENSE("GPL");
應用程式測試驅動:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> //lseek
#include <sys/ioctl.h> //ioctl
int fd; //存放檔案描述符號
char save_buf[1024]={0}; //存放資料使用
int main(void)
{
int ret;
fd = open("/dev/mymisc",O_RDWR); //以讀寫方式進行開啟
if(fd < 0){
printf("open error\r\n");
return -1;
}
printf("fd=%d\r\n",fd); //成功時候輸出檔案描述符
//讀操作
ret = read(fd, save_buf,1024);
if(ret < 0){
printf("read error\r\n");
return -1;
}
//寫操作
write(fd, "console out test\r\n", sizeof("console out test\r\n"));
//移動檔案指標操作
lseek(fd,0,SEEK_SET);
//i/o 控制操作
ioctl(fd,0,0);
//關閉檔案
close(fd);
return 0;
}
Makefile
# Makefile 2.6
#hello 是模組名,也是對應的 c 檔名。
obj-m += misc_device_module.o
# KDIR 核心原始碼路徑,根據自己需要設定
# X86 原始碼路徑統一是/lib/modules/$(shell uname -r)/build
#如果要編譯 ARM 的模組,則修改成 ARM 的核心原始碼路徑
#KDIR :=/lib/modules/$(shell uname -r)/build
KDIR := /root/work/linux-3.5_xyd_modversion/
all:
@make -C $(KDIR) M=$(PWD) modules
@rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.unsigned *.order *~ *.bak
arm-linux-gcc app.c -o app
cp app *.ko /root/work/rootfs/home
clean:
make -C $(KDIR) M=$(PWD) modules clean
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.markers *.unsigned *.order *~ *.bak
開發板測試結果:
[[email protected] home]# ls /dev/mymisc
ls: /dev/mymisc: No such file or directory
安裝後生成了裝置檔案,通過這個檔案可以找到這份驅動程式的檔案操作方法
[[email protected] home]# insmod misc_device_module.ko
[ 65.010000] misc_register ok
[[email protected] home]# ls /dev/mymisc
/dev/mymisc
解除安裝後,裝置檔案自動刪除:
[[email protected] home]# rmmod misc_device_module
[ 91.145000] misc_deregister ok
[[email protected] home]# ls /dev/mymisc
ls: /dev/mymisc: No such file or directory
檢視雜項裝置的主次裝置號: 主是 10,次 47---核心自動分配的(因為程式碼寫了 255)
[[email protected] home]# insmod misc_device_module.ko
[ 98.970000] misc_register ok
[[email protected] home]# ls /dev/mymisc -l
crw-rw---- 1 root root 10, 47 Sep 9 2016 /dev/mymisc
編寫使用者程式,通過使用者程式設計 API 介面呼叫驅動程式的檔案操作方法:
[[email protected] home]# lsmod
Tainted: G
misc_device_module 2079 0 - Live 0xbf004000 (O)
[[email protected] home]# ls
app misc_device_module.ko
[[email protected] home]# ./app
[ 732.400000] line:13, xxx_open is call
[ 732.400000] line:21, xxx_read is call
[ 732.400000] line:28, xxx_write is call
[ 732.400000] line:35, xxx_llseek is call
[ 732.400000] line:52, xxx_unlocked_ioctl is call
[ 732.400000] line:43, xxx_release is call
fd=3
[[email protected] home]#
相關推薦
1.2 Linux 雜項裝置驅動模型
在目前的核心版本中,存在三種流行的字元裝置程式設計模型:雜項裝置驅動模型,早期經典標準字元裝置驅動模型, Linux 2.6 標準字元裝置驅動模型。 Linux 系統借鑑了面向物件的思想來管理裝置驅動 ,每一類裝置都都會有定義一個特定的結構體來描述它,這個結構體包含了裝置的
Linux字元裝置驅動模型--字元裝置的註冊
當我們編寫字元裝置驅動程式的時候,在進行字元裝置物件cdev的分配、初始化,裝置號的註冊這些初始化階段之後,就可以將它加入到系統中,這樣才能使用這個字元裝置。將一個字元裝置加入到系統中呼叫的函式時cdev_add,核心原始碼如下: int cdev_add(struct cdev *
linux字元裝置驅動模型
一.雜項裝置驅動模型 雜項的主裝置號固定為10,只有255個次裝置號。可以直接生成驅動核心。 1.需要確定每個模型都會用到的檔案操作方法集合指標 2.確定核心的結構體 static struct miscdevice abc 確定三個引數,第一個為次裝置號,第二個是次裝
Linux之裝置驅動模型學習筆記
提供了對許多模組支援,包括但不限於裝置驅動 每個模組由目的碼組成(沒有連線成一個完整可執行程式) insmod將模組動態載入到正在執行的核心 rmmod程式移除模組 #include <linux/in
linux平臺裝置驅動模型
linux平臺裝置介紹 linux2.6以上的裝置驅動模型中,有三大實體:匯流排,裝置和驅動。匯流排負責將裝置和驅動繫結,在系統沒註冊一個裝置的時候,會尋找與之匹配的驅動:相反的,在系統每註冊一個驅動的時候,會尋找與之匹配的裝置,而匹配則由匯流排完成。 一個
Linux匯流排裝置驅動模型
Kobjec&Kset Sysfs檔案系統 proc檔案系統是提供一個介面給使用者,讓使用者能夠檢視系統執行的狀態資訊,讓使用者能夠修改核心的一些引數,比如說列印級別 sysfs是基於ram
Linux Kernel裝置驅動模型之匯流排查詢裝置
裝置驅動模型之匯流排查詢裝置: /** * bus_find_device - device iterator for locating a particular device. * @bus: bus type * @start: Device to begin w
面向物件地分析Linux核心裝置驅動(2)——Linux核心裝置模型與匯流排
Linux核心裝置模型與匯流排 - 核心版本 Linux Kernel 2.6.34, 與 Robert.Love的《Linux Kernel Development》(第三版)所講述的核心版本一樣 1. Linux核心裝置模型分析 1)
linux裝置驅動模型 - regmap
1. regmap介紹 regmap主要是為了方便操作暫存器而設計的,它將所有模組的暫存器(包括soc上模組的暫存器和外圍裝置的暫存器等) 抽象出來,用一套統一介面來操作暫存器 比如,如果要操作i2c裝置的暫存器,那麼就要呼叫i2c_transfer介面,要操作spi裝置的暫存
linux裝置驅動模型 - device/bus/driver
在linux驅動模型中,為了便於管理各種裝置,我們把不同裝置分別掛在他們對應的總線上,裝置對應的驅動程式也在總線上找,這樣就提出了deivce-bus-driver的模型,硬體上有許多裝置匯流排,那麼我們就在裝置模型上抽象出bus概念,相應的device就代表裝置,driver表示驅動,
linux裝置驅動模型 - sys/kobject
1. sysfs 1.1 sysfs檔案系統註冊 在系統啟動時會註冊sysfs檔案系統 (fs/sysfs/mount.c) int __init sysfs_init(void) { int err; sysfs_root = kernfs_creat
linux裝置驅動模型 - 驅動框架
linux驅動模型框架如圖所示: 1. kernfs 驅動最終是提供給使用者層使用,那麼其中的介面就是通過kernfs檔案系統來註冊,kernfs是一個通用的核心虛擬檔案系統 2. sysfs/kobject sysfs是裝置驅動檔案系統,裝置之間的各種關係會在在/
linux裝置驅動模型之Kobject、kobj_type、kset
一、sysfs檔案系統簡介: 1、sysfs概述 sysfs檔案系統是核心物件(kobject)、屬性(kobj_type)、及它們相互關係的一種表現。 sysfs非常重要的特徵:使用者可以從sysfs中讀出核心資料,也可以將使用者資料寫入核心。 2、核心結構與sysfs對應關係:
《5.linux驅動開發-第5部分-5.5.linux裝置驅動模型》
《5.linux驅動開發-第5部分-5.5.linux裝置驅動模型》 第一部分、章節目錄 5.5.1.linux裝置驅動模型簡介 5.5.2.裝置驅動模型的底層架構 5.5.3.匯流排式裝置驅動組織方式 5.5.4.platform平臺匯流排簡介1 5.5.5.platform平臺匯流排
LINUX裝置驅動模型之class
轉自 https://blog.csdn.net/qq_20678703/article/details/52754661 1、LINUX裝置驅動模型中的bus、device、driver,。其中bus:實際的匯流排,device:實際的裝置和介面,而driver:對應存在的驅動。 2、但
linux misc device字元雜項裝置驅動程式
雜項裝置也是在嵌入式系統中用得比較多的一種裝置驅動。miscdevice共享一個主裝置號MISC_MAJOR(即10),但次裝置號不同。misc裝置其實就是特殊的字元裝置,主裝置編號採用10,並且可自動生成裝置節點。 雜項裝置作為字元裝置的封裝,為字元裝置提供的簡單的程
Linux中的平臺裝置驅動模型
在 Linux 的裝置驅動模型中,關心匯流排、裝置和驅動這 3 個實體,匯流排將裝置和驅動繫結。在系統每註冊一個裝置的時候,會尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會尋找與之匹配的裝置,而匹配由匯流排完成。 平臺裝置匹配的依據是: 1
Linux usb 裝置驅動 (1)
在初始化了一些資源之後,可以看到第一個關鍵的函式呼叫——interface_to_usbdev。他通過一個usb_interface來得到該介面所在裝置的裝置描述結構。本來,要得到一個usb_device只要用interface_to_usbdev就夠了,但因為要增加對該usb_device的引用計數,我們
linux裝置驅動模型架構分析 一
概述LDD3中說:“Linux核心需要一個對系統結構的一般性描述。”這個描述就是linux裝置驅動模型(下面簡稱為LDDM)。LDDM不是獨立存在,其體系如下圖所示:對架構的每一部分本文都會開闢獨立的章節進行描述。暫且拋開這個架構,首先從總體上了解一下LDDM。LDDM與驅動
linux裝置驅動模型之匯流排、裝置、驅動三者的關係
匯流排、裝置、驅動,也就是bus、device、driver,在核心裡都有對應的結構體,在include/linux/device.h 裡定義。Device.h (linux-3.4.2\inclu