亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

蟲蟲首頁| 資源下載| 資源專輯| 精品軟件
登錄| 注冊

您現在的位置是:首頁 > 技術閱讀 >  linux驅動開發(2、第一個字符設備驅動)

linux驅動開發(2、第一個字符設備驅動)

時間:2024-06-01

文章目錄

  • 設備號

  • 常用接口

    • 設備號申請/釋放

      • register_chrdev_region函數

      • alloc_chrdev_region函數

      • unregister_chrdev_region函數

      • 其它宏定義

    • 字符設備的定義

      • cdev_alloc函數

    • 字符設備的綁定

      • cdev_init函數

    • 字符設備注冊/注銷

      • cdev_add函數

      • cdev_del函數

    • file_operations結構

  • 實現一個簡單的字符設備驅動

  • 以前的接口

    • register_chrdev函數

    • unregister_chrdev函數

  • 測試流程及結果

  • 總結


點擊下方閱讀原文可訪問文中超鏈接

設備號

設備號(統稱,由主設備號和次設備號組成)是一種資源,更是應用層與驅動層之間的紐帶,設備號由主設備號和次設備號組成,主設備號用于區分是哪類設備,次設備號用于區分某一類設備中的各個子設備;設備號的分配規則是從大往小分配,其中某些設備號是系統已經約定好了的預分配給指定設備;
當向內核申請了設備號后,就可以在/proc/devices文件中看到對應的主設備號及設備名,此時使用mknod也可以在/dev目錄生成設備節點,不過這個節點是個空節點,沒有任何用;設備號被注銷后,/proc/devices中也會自動刪除,如下:

常用接口

設備號申請/釋放

位于頭文件:include/linux/fs.h

register_chrdev_region函數

向內核申請指定的設備號,如果指定的設備號已存在則會申請失敗。

int register_chrdev_region(dev_t, unsigned, const char *);

示例用法:

//MKDEV是一個宏,用于將主次設備號合并成設備號
//第二個參數表示申請多少個設備號
//第三個參數是設備名
register_chrdev_region(MKDEV(247,0),1,"test_char_dev");

alloc_chrdev_region函數

向內核申請設備號,并且由內核自動分配可用的設備號。

int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);

示例用法:

//devno存儲申請的設備號
//第二個參數表示次設備號的起始值
//第三個參數表示申請多少個設備號
//第四個參數是設備名
alloc_chrdev_region(&devno,0,1,"test_char_dev");

unregister_chrdev_region函數

用于注銷由register_chrdev_regionalloc_chrdev_region申請的設備號,前面也說了設備號是一種資源,所以要養成良好的習慣,不用就要歸還。

void unregister_chrdev_region(dev_t, unsigned);

示例用法:

//devno申請的設備號
//第二個參數表示申請的個數,申請了多少就要注銷多少
unregister_chrdev_region(devno,1);

其它宏定義

位于頭文件:include/linux/kdev_t.h
用于提取設備號的主設備號。

#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))

用于提取設備號的次設備號。

#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))

字符設備的定義

cdev_alloc函數

位于頭文件:include/linux/cdev.h
使用動態內存的方式定義一個字符設備。

struct cdev *cdev_alloc(void);

或者直接定義為靜態全局變量

static struct cdev chr_dev;

字符設備的綁定

cdev_init函數

將一個字符設備與file_operations結構綁定起來。

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

字符設備注冊/注銷

cdev_add函數

向內核注冊字符設備。

int cdev_add(struct cdev *, dev_t, unsigned);

cdev_del函數

注銷一個字符設備。

void cdev_del(struct cdev *);

file_operations結構

位于頭文件:include/linux/fs.h
這個結構體包含了一系列的函數指針,基本上每一個函數指針都對應了應用層一個接口函數,比如調用應用層的open函數時,最終就會調用到這個結構體里面的open函數指針。我們就可以通過實現一些需要的函數來操作硬件。
示例代碼:

static int test_open (struct inode *inode, struct file *file)
{
return 0;
}

static int test_close (struct inode *inode, struct file *file)
{
return 0;
}

static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = test_open,
.release = test_close,
};

實現一個簡單的字符設備驅動

一個簡單的字符設備驅動大致分為以下幾個步驟:

  • 向內核申請設備號

  • 定義一個字符設備對象

  • 綁定字符設備對象與file_operations結構

  • 向內核注冊字符設備

  • 實現file_operations結構體內的部分接口

簡單源碼如下(注意未實現各種錯誤及邊界檢查,實際應用時應完善,以保證程序的健壯性):

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#define DEBUG(fmt, ...) \
do{ \
if(if_debug) \
printk(KERN_INFO "DEBUG > " fmt, ##__VA_ARGS__); \
}while(0)


bool if_debug = false;
/*定義一個bool類型的變量,作為一個模塊入參,在裝載模塊時可賦值*/
module_param(if_debug, bool, S_IRUSR);

#define DEV_COUNT 1

/*設備號*/
static dev_t devno;
/*定義一個字符設備*/
static struct cdev *char_dev;

static int test_open (struct inode *inode, struct file *file)
{
DEBUG("open test..\r\n");

return 0;
}

static int test_close (struct inode *inode, struct file *file)
{
DEBUG("close test..\r\n");

return 0;
}

static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = test_open,
.release = test_close,
};

static int __init test_init(void)
{
/*申請設備號*/
alloc_chrdev_region(&devno,0,DEV_COUNT,"test_char_dev");
/*使用動態內存定義一個字符設備*/
char_dev = cdev_alloc();
/*綁定字符設備和file_operations結構*/
cdev_init(char_dev,&fops);
/*注冊字符設備*/
cdev_add(char_dev,devno,DEV_COUNT);

return 0;
}

static void __exit test_exit(void)
{
/*注銷一個字符設備*/
cdev_del(char_dev);
/*注銷申請的設備號*/
unregister_chrdev_region(devno,DEV_COUNT);
}

/*此宏聲明內核模塊的初始化入口點*/
module_init(test_init);
/*此宏聲明內核模塊的退出入口點*/
module_exit(test_exit);

/*聲明開源協議*/
MODULE_LICENSE("GPL");
/*聲明作者*/

MODULE_AUTHOR("wei");
/*聲明模塊的描述*/
MODULE_DESCRIPTION("this is a test driver");

以前的接口

同樣是創建字符設備,但是內核還有兩個接口,可以大大簡化上面的代碼。

register_chrdev函數

此函數可一步到位,完成了設備號的申請,字符設備與file_operations結構的綁定以及字符設備的注冊全部操作,只不過這個函數會自動申請256個主設備號相同的設備號(次設備號為0到255),如果沒有這么多同類子設備的話會造成空間的浪費

int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)

示例代碼:

//第一個參數為主設備號,如果為0則內核自動分配
//第二個參數為設備名
//第三個參數為file_operations結構體
register_chrdev(247,"test_char_dev",fops);

unregister_chrdev函數

用于注銷由register_chrdev申請的資源。

void unregister_chrdev(unsigned int major, const char *name)

示例用法:

//第一個參數為主設備號
//第二個參數為設備名
unregister_chrdev(247,"test_char_dev");

第二種更簡潔的寫法:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#define DEBUG(fmt, ...) \
do{ \
if(if_debug) \
printk(KERN_INFO "DEBUG > " fmt, ##__VA_ARGS__); \
}while(0)


bool if_debug = false;
/*定義一個bool類型的變量,作為一個模塊入參,在裝載模塊時可賦值*/
module_param(if_debug, bool, S_IRUSR);

#define CHRDEV_NAME "test_char_dev"
/*主設備號*/
static dev_t major;

static int test_open (struct inode *inode, struct file *file)
{
DEBUG("open test..\r\n");

return 0;
}

static int test_close (struct inode *inode, struct file *file)
{
DEBUG("close test..\r\n");

return 0;
}

static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = test_open,
.release = test_close,
};

static int __init test_init(void)
{
major = register_chrdev(0,CHRDEV_NAME,&fops);

return 0;
}

static void __exit test_exit(void)
{
unregister_chrdev(major,CHRDEV_NAME);
}

/*此宏聲明內核模塊的初始化入口點*/
module_init(test_init);
/*此宏聲明內核模塊的退出入口點*/
module_exit(test_exit);

/*聲明開源協議*/
MODULE_LICENSE("GPL");
/*聲明作者*/
MODULE_AUTHOR("wei");
/*聲明模塊的描述*/
MODULE_DESCRIPTION("this is a test driver");

驅動寫好后,還需要讓應用程序能夠使用,而應用程序是通過設備節點來訪問的,所以接下來創建設備節點,以讓應用程序可以訪問寫好的驅動。使用mknod命令創建設備節點:

mknod 設備名 設備類型 主設備號 次設備號

示例用法:

mknod /dev/test_char_dev c 247 0

此程序沒有實現任何的硬件操作,下面寫個簡單的應用程序測試一下驅動是否能正常工作,因為只實現了openrelease接口,所以在應用程序中也只能使用這兩個接口。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <stdio.h>

int main(int argc,char *argv[])
{
int fd;

fd = open("/dev/test_char_dev",O_RDONLY);
if(fd < 0)
{
perror("open");

return -1;
}

close(fd);

return 0;
}

測試流程及結果

# 裝載驅動
insmod test.ko if_debug=1
# 查看申請的設備號
cat /proc/devices
# 創建設備節點(主設備號由上條命令查看,次設備號與驅動程序一致)
mknod /dev/test_char_dev c 247 0
# 執行應用程序
./app_test
# 運行結果會打印出驅動程序中的兩個調試信息
DEBUG > open test..
DEBUG > close test..
# 卸載驅動
rmmod test.ko
# 刪除設備節點
rm /dev/test_char_dev

總結

我根據自己的理解,畫了一個關系圖。

測試源碼獲取:點我

亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
亚洲人成人99网站| 欧美三级免费| 9l国产精品久久久久麻豆| 影音先锋久久久| 国产一区二区三区在线播放免费观看 | 久久国产一区二区| 性色一区二区三区| 久久久久久午夜| 免费成人黄色片| 欧美另类专区| 欧美性大战xxxxx久久久| 国产精品日韩专区| 国产欧美日韩在线| 在线观看日韩精品| 99国产精品99久久久久久粉嫩| 一区二区三区视频观看| 午夜伦欧美伦电影理论片| 久久动漫亚洲| 欧美福利视频在线| 国产精品二区三区四区| 国产一区二三区| 亚洲国产精品电影| 一区二区三区日韩欧美精品| 久久精品国产久精国产一老狼| 麻豆精品视频在线观看视频| 欧美日韩视频在线一区二区| 国一区二区在线观看| 最新国产拍偷乱拍精品| 中文在线资源观看视频网站免费不卡| 久久综合伊人| 欧美激情在线播放| 国产精品萝li| 亚洲大胆美女视频| 亚洲欧美激情视频| 你懂的成人av| 国产日韩综合| 一区二区视频免费完整版观看| 99精品欧美一区二区三区综合在线| 久久精品女人| 国产精品欧美激情| 久久婷婷蜜乳一本欲蜜臀| 欧美日韩大片| 欧美日韩精品系列| 国产精品卡一卡二卡三| 狠狠色伊人亚洲综合网站色| 99re6热在线精品视频播放速度| 亚洲视频在线观看视频| 久久国产一二区| 国产精品久久午夜| 极品尤物一区二区三区| 日韩天堂在线视频| 欧美一区网站| 欧美日韩精品是欧美日韩精品| 国产欧美一区二区在线观看| 亚洲人永久免费| 久久久国产亚洲精品| 国产精品久久久久久久久久妞妞| 亚洲精华国产欧美| 久久免费偷拍视频| 国产夜色精品一区二区av| 亚洲一区二区三区精品动漫| 国语自产精品视频在线看抢先版结局 | 欧美精品日韩www.p站| 国产精品综合| 一区二区三区四区五区精品视频| 欧美岛国激情| 亚洲国产经典视频| 欧美中文字幕在线观看| 欧美午夜寂寞影院| 亚洲日韩中文字幕在线播放| 欧美1区3d| 91久久国产综合久久蜜月精品 | 黑人操亚洲美女惩罚| 亚洲免费在线| 国产精品看片你懂得| 一本大道av伊人久久综合| 女人色偷偷aa久久天堂| **欧美日韩vr在线| 久久精品日产第一区二区三区| 国产欧美日韩激情| 亚洲一区免费看| 国产精品v亚洲精品v日韩精品| 一本综合久久| 国产精品久久久久久影视 | 欧美在线国产| 国产欧美精品xxxx另类| 午夜精品久久久久久久久久久| 欧美先锋影音| 亚洲一区精品电影| 国产精品毛片va一区二区三区| 亚洲免费中文| 国产亚洲二区| 久久久久久有精品国产| 在线看片第一页欧美| 欧美成人亚洲成人| 亚洲精品在线一区二区| 欧美视频中文一区二区三区在线观看 | 国产一区二区三区黄| 久久精品视频在线观看| 在线不卡视频| 欧美成人中文| 亚洲另类在线视频| 免费亚洲电影在线观看| 最新日韩欧美| 国产精品高精视频免费| 欧美呦呦网站| 亚洲第一精品久久忘忧草社区| 亚洲私拍自拍| 国产欧美日韩在线视频| 久久久亚洲欧洲日产国码αv | 一区二区三区欧美在线观看| 国产精品久久夜| 久久综合九色综合久99| 99视频超级精品| 国产日韩欧美不卡在线| 六十路精品视频| 一本大道av伊人久久综合| 国产精品一区二区久久久| 另类亚洲自拍| 亚洲伊人伊色伊影伊综合网| 揄拍成人国产精品视频| 欧美日韩视频第一区| 亚洲一区视频在线观看视频| 韩国v欧美v日本v亚洲v| 久久综合国产精品| 亚洲女性喷水在线观看一区| 在线日韩av永久免费观看| 欧美mv日韩mv国产网站app| 亚洲综合清纯丝袜自拍| 亚洲一区免费观看| 国模私拍一区二区三区| 欧美黄色一区| 久久成人精品无人区| 亚洲精品三级| 亚洲日本成人| 国产视频精品xxxx| 欧美午夜剧场| 欧美成人免费视频| 久久久久久久一区二区| 亚洲欧美国内爽妇网| 最新成人av在线| 黑丝一区二区三区| 国产精品亚洲美女av网站| 国产精品制服诱惑| 欧美午夜电影一区| 欧美日韩中文在线| 久久性色av| 亚洲欧美激情精品一区二区| 亚洲综合成人在线| 99亚洲精品| av不卡免费看| 亚洲精品国精品久久99热一| 亚洲成人影音| 国产亚洲欧美另类中文| 久久午夜av| 欧美高清视频一区二区| 久久美女性网| 男同欧美伦乱| 欧美成人免费va影院高清| 欧美日韩午夜| 欧美日韩国产一区| 欧美成人午夜视频| 久久久久久久久久久一区| 欧美在线一二三| 久久久91精品国产一区二区三区| 亚洲综合色噜噜狠狠| av成人动漫| 99视频日韩| 一本色道久久99精品综合 | 久久精品国语| 久久精品99国产精品| 欧美亚洲视频| 久久久久久久综合| 国产精品国产三级国产aⅴ9色| 欧美喷水视频| 欧美另类99xxxxx| 欧美日韩精品在线视频| 欧美日韩免费在线视频| 欧美gay视频| 欧美激情久久久久久| 欧美日韩精品免费看| 欧美天天视频| 国产欧美成人| 国内精品久久久久久久97牛牛| 一区二区在线免费观看| 亚洲大胆人体视频| 亚洲国产另类 国产精品国产免费| 亚洲欧洲另类| 中文日韩在线视频| 欧美一级播放| 免费观看成人www动漫视频| 欧美麻豆久久久久久中文| 国产精品成人在线观看| 国产一区二区黄色| 亚洲国产精品999| 在线视频精品一| 欧美一区二区三区在线观看视频| 久久在线免费| 欧美午夜片在线观看| 国产亚洲视频在线|