1. 程式人生 > >1.2 Linux 雜項裝置驅動模型

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