日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

第一个Linux驱动

發布時間:2024/1/18 linux 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第一个Linux驱动 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 建立工程

2. 建立.vscode

c_pp_properties.json

{"configurations": [{"name": "Linux","includePath": ["${workspaceFolder}/**","/home/szm/linux/IMX6ULL/szm_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga/include", "/home/szm/linux/IMX6ULL/szm_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include", "/home/szm/linux/IMX6ULL/szm_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include/generated/"],"defines": [],"compilerPath": "/usr/bin/gcc","cStandard": "c11","cppStandard": "c++17","intelliSenseMode": "gcc-x64"}],"version": 4

settings.json

{"search.exclude": {"**/node_modules": true,"**/bower_components": true,"**/*.o":true,"**/*.su":true, "**/*.cmd":true,"Documentation":true, },"files.exclude": {"**/.git": true,"**/.svn": true,"**/.hg": true,"**/CVS": true,"**/.DS_Store": true, "**/*.o":true,"**/*.su":true, "**/*.cmd":true,"Documentation":true, } }

3.Makefile

# KERNELDIR表示內核源碼路徑 KERNELDIR := /home/szm/linux/IMX6ULL/szm_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga # 表示當前路徑,即pwd CURRENT_PATH := $(shell pwd)# 將chadevbase.c編譯成模塊 obj-m := chadevbase.obuild : kernel_modules# 具體的編譯命令,后面的 modules 表示編譯模塊,-C 表示將當前的工作目錄切 # 換到指定目錄中,也就是 KERNERLDIR 目錄。M 表示模塊源碼目錄,“make modules”命令 # 中加入 M=dir 以后程序會自動到指定的 dir 目錄中讀取模塊的源碼并將其編譯為.ko 文件。 kernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modulesclean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

4.代碼

4.1 驅動模塊加載與卸載

模塊編譯完成之后擴展名為ko,有兩種命令可以加載模塊:insmod和modprobe。insmod是最簡單的模塊加載命令,此命令用于加載指定的.ko 模塊。
insmod 命令不能解決模塊的依賴關系,比如 drv.ko 依賴 first.ko 這個模
塊,就必須先使用insmod 命令加載 first.ko 這個模塊,然后再加載 drv.ko這個模塊。但是 modprobe 就不會存在這個問題,modprobe 會分析模塊的依賴關系,然后會將所有的依賴模塊都加載到內核中,因此modprobe 命令相比insmod 要智能一些。modprobe 命令主要智能在提供了模塊的依賴性分析、錯誤檢查、錯誤報告等功能,推薦使用 modprobe 命令來加載驅動。modprobe 命令默認會去/lib/modules/kernel-version目錄中查找模塊,比如本書使用的 Linux kernel 的版本號為 4.1.15,因此 modprobe 命令默認會到/lib/modules/4.1.15 這個目錄中查找相應的驅動模塊,一般自己制作的根文件系統中是不會有這個目錄的,所以需要自己手動創建。
我們把編譯好的ko文件放到nfs中
在加載模塊驅動之前要先加demod
然后使用加載命令,加載成功后可以用lsmod查看驅動
使用rmmod卸載驅動

4.2 字符設備的注冊與注銷

  • 我們需要向系統注冊一個字符設備,使用函數register_chrdev
  • 卸載驅動的時候,需要注銷掉,前面注冊的字符設備unregister_chrdev

4.3 設備號

  • linux內核使用dev_t
    typedef __ kernel_dev_t dev_t
    typedef __ u32 __ kernel_dev_t
    typedef unsigned int __ u32
  • Linux內核將設備號分成兩部分,主設備號和次設備號。主設備號占用前12位,次設備號占用后20位
  • 設備號的操作函數
    從dev_t獲取主設備號和次設備號,MAJOR(dev_t), MINOR(dev_t)。也可以使用主設備號和次設備號,通過mkdev(major,minor), 所以一定保證驅動的主設備號和次設備號一定是唯一的,不能沖突
    查看當前主設備號的使用情況:
    cat /proc/devices
    我們看到200沒有用

4.4 file_opterations開發,驅動框架

#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h>#define CHRDEVBASE_MAJOR 200 /* 主設備號 */ #define CHRDEVBASE_NAME "chrdevbase" /* 名字 */static int chrdevbase_open(struct inode *inode, struct file *filp) {printk("chrdevbase_open\r\n");return 0; }/* 對應的驅動關閉注意和原來的區別 */ static int chrdevbase_release(struct inode *inode, struct file *filp) {printk("chrdevbase_release\r\n");return 0; }static ssize_t chrdevbase_read(struct file *filp, __user char *buf, size_t count, loff_t *ppos) {printk("chrdevbase_read\r\n");return 0; }static ssize_t chrdevbase_write(struct file *filp, __user const char *buf, size_t count, loff_t *ppos) {printk("chrdevbase_write\r\n");return 0; }static struct file_operations chrdevbase_fops={.owner = THIS_MODULE,.open = chrdevbase_open,.release = chrdevbase_release,.read = chrdevbase_read,.write = chrdevbase_write, };static int __init chrdevbase_init(void) { int ret = 0;printk("module init\r\n"); //linux內核的打印函數/* 注冊字符設備 *//* file_opterations就是要實現的 */ret = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);if(ret < 0){printk("chrdevbase init failed\r\n");}return 0; } static void __exit chrdevbase_exit(void) {printk("module exit\r\n");/* 注銷字符設備 */unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);return ; }/* 模塊入口與出口 */ module_init(chrdevbase_init); /* 入口 */ /* 當裝載的時候自動執行這個函數,卸載執行下面的函數 */ module_exit(chrdevbase_exit); /* 出口 */ /* 括號里填寫驅動入口函數 */MODULE_LICENSE("GPL"); MODULE_AUTHOR("Shao Zheming");

4.5 應用程序編寫

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h>/* * argc: 應用程序參數個數* argv[]: 參數是什么,具體的參數,說明參數是字符串的形式* .chrdevbaseApp <filename> 調用情況* */ int main(int argc, char *argv[]) {int ret = 0;int fd = 0; //文件描述符char *filename;char readBuf[100], writeBuf[100];// 當輸入這個命令時,.chrdevbaseApp <filename> // 第一個參數,也就是argv[0]就是.chrdevbaseApp// 第二個參數,也就是argv[1]就是<filename>filename = argv[1];// O_RDWR可讀可寫fd = open(filename, O_RDWR);if(fd < 0){printf("Can't open file %s \r\n", filename); //應用測試就要用printf了return -1;}/* 讀和寫測試 *//* read */// 50指的是從驅動里面讀多少個字節// 返回的是你讀的字節數, -1是錯了,如果小于50,說明驅動只能給你小于50,沒錯ret = read(fd, readBuf, 50);if(ret < 0){printf("read file %s failed \r\n", filename);}else{}/* write */ret = write(fd, writeBuf, 50);if(ret < 0){printf("write file %s failed \r\n", filename);}else{}/* write */ret = close(fd);if(ret < 0){printf("close file %s failed \r\n", filename);}return 0; }

注意是arm架構,所以在Ubuntu上運行肯定報錯

5. 測試

進入dev查看chrdevbase,發現沒有這個東西,需要手動創建
c是字符設備的意思

6. 完善這個驅動

要求可以讀寫程序
chrdevbase.c

#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h>#define CHRDEVBASE_MAJOR 200 /* 主設備號 */ #define CHRDEVBASE_NAME "chrdevbase" /* 名字 *//* 和應用層一致 */ static char readBuf[100]; /* 讀緩沖 */ static char writeBuf[100]; /* 寫緩沖 */ static char kernel_data[] = {"kernel data!\r\n"};static int chrdevbase_open(struct inode *inode, struct file *filp) {//printk("chrdevbase_open\r\n");return 0; }/* 對應的驅動關閉注意和原來的區別 */ static int chrdevbase_release(struct inode *inode, struct file *filp) {//printk("chrdevbase_release\r\n");return 0; }static ssize_t chrdevbase_read(struct file *filp, __user char *buf, size_t count, loff_t *ppos) {int ret = 0;//printk("chrdevbase_read\r\n");/* 應用程序不能直接訪問內核數據,必須借用其他的函數 */memcpy(readBuf, kernel_data, sizeof(kernel_data));//count是由用戶決定的ret = copy_to_user(buf, readBuf, count);if(ret == 0){}else{}return 0; }static ssize_t chrdevbase_write(struct file *filp, __user const char *buf, size_t count, loff_t *ppos) {int ret = 0;//printk("chrdevbase_write\r\n");/* 應用程序不能直接訪問內核數據,必須借用其他的函數 *///count和buf是由用戶決定的ret = copy_from_user(writeBuf, buf, count);if(ret == 0){printk("kernel recevice data:%s \r\n", writeBuf);}else{}return 0; }static struct file_operations chrdevbase_fops={.owner = THIS_MODULE,.open = chrdevbase_open,.release = chrdevbase_release,.read = chrdevbase_read,.write = chrdevbase_write, };static int __init chrdevbase_init(void) { int ret = 0;printk("module init\r\n"); //linux內核的打印函數/* 注冊字符設備 *//* file_opterations就是要實現的 */ret = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);if(ret < 0){printk("chrdevbase init failed\r\n");}return 0; } static void __exit chrdevbase_exit(void) {printk("module exit\r\n");/* 注銷字符設備 */unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);return ; }/* 模塊入口與出口 */ module_init(chrdevbase_init); /* 入口 */ /* 當裝載的時候自動執行這個函數,卸載執行下面的函數 */ module_exit(chrdevbase_exit); /* 出口 */ /* 括號里填寫驅動入口函數 */MODULE_LICENSE("GPL"); MODULE_AUTHOR("Shao Zheming");

測試APP文件
chrdevbaseApp.c

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h>/* * argc: 應用程序參數個數* argv[]: 參數是什么,具體的參數,說明參數是字符串的形式* .chrdevbaseApp <filename> <1:2> 1表示讀,2表示寫* .chrdevbaseApp /dev/chrdevbase 1 從這個驅動里面讀數據* .chrdevbaseApp /dev/chrdevbase 2 從這個驅動里面寫數據* */ int main(int argc, char *argv[]) {int ret = 0;int fd = 0; //文件描述符char *filename;char readBuf[100], writeBuf[100];static char user_data[] = {"I write an user data to kernel!\r\n"};// 當輸入這個命令時,.chrdevbaseApp <filename> // 第一個參數,也就是argv[0]就是.chrdevbaseApp// 第二個參數,也就是argv[1]就是<filename>if(argc != 3){/* 表示參數不是3個 */printf("Error usage! \r\n");return -1;}filename = argv[1];// O_RDWR可讀可寫fd = open(filename, O_RDWR);if(fd < 0){printf("Can't open file %s \r\n", filename); //應用測試就要用printf了return -1;}if(atoi(argv[2]) == 1){/* 表示讀 *//* 讀和寫測試 *//* read */// 50指的是從驅動里面讀多少個字節// 返回的是你讀的字節數, -1是錯了,如果小于50,說明驅動只能給你小于50,沒錯ret = read(fd, readBuf, 50);if(ret < 0){printf("read file %s failed \r\n", filename);}else{printf("APP read data:%s \r\n", readBuf);}}if(atoi(argv[2]) == 2){ /* 表示寫 *//* write */memcpy(writeBuf, user_data, sizeof(user_data));ret = write(fd, writeBuf, 50);if(ret < 0){printf("write file %s failed \r\n", filename);}else{}}/* write */ret = close(fd);if(ret < 0){printf("close file %s failed \r\n", filename);}return 0; }

總結

以上是生活随笔為你收集整理的第一个Linux驱动的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 性做爰裸体按摩视频 | 国产又爽又黄又嫩又猛又粗 | 一区二区三区在线观看 | 午夜一区 | 久草青青视频 | 好吊视频一区二区三区四区 | 用力插视频 | 2017天天干 | 久久综合九色综合网站 | 中文字幕专区 | 午夜视频在线网站 | 国产高清视频免费在线观看 | 97国产超碰| 久久久天堂国产精品女人 | 全国最大色| 国产欧美综合一区二区三区 | 男男gay同性三级 | 国产天堂资源 | 日韩毛片儿 | 天天艹天天爽 | 欧美一区二区三区视频 | 亚洲欧美国产一区二区三区 | 羞羞网站在线观看 | 影音先锋亚洲成aⅴ人在 | 天海翼一二三区 | 一个色综合导航 | www污污| 韩日免费av | 影音先锋波多野结衣 | 日韩精品视频网站 | 欧美乱欲视频 | 一级色网站 | 丁香花电影高清在线阅读免费 | 黄色三级图片 | 波多野结衣调教 | 偷偷操网站 | 中文字幕在线观看视频免费 | 亚洲精品国产一区 | 三级a视频| 亚洲女成人图区 | 国产精品sm | 亚洲欧美一二三区 | 日韩在线中文字幕视频 | 欧美一区二区三区影院 | wwwxxx亚洲| 亚洲123区 | 青青视频免费看 | 久久中文字幕视频 | 激情啪啪网站 | 永久免费精品 | 无码国产伦一区二区三区视频 | 免费播放av| 五月婷婷激情综合网 | 精品丰满少妇一区二区三区 | www黄色com| 国产精品嫩草69影院 | 久久久精品一区 | 国产乱淫av一区二区三区 | 欧美激情国产精品 | 成年丰满熟妇午夜免费视频 | 久久大陆| 久久久成人免费 | 欧美激情片一区二区 | 狠狠躁夜夜躁av无码中文幕 | 插我舔内射18免费视频 | 狠狠操狠狠插 | 95看片淫黄大片一级 | 一级大片在线观看 | 欧美成人精品欧美一级乱 | 国产精品免费一区二区区 | 青青国产在线观看 | 女人叉开腿让男人桶 | 东北少妇露脸无套对白 | 国产免费av网址 | 午夜影院0606 | 欧美成人免费一级人片100 | 黄色99视频| 波多野结衣在线免费视频 | 深夜福利网址 | www.久色| 在线观看国产视频 | 国产乱码精品一区二区 | 亚洲成人av免费观看 | 视频网站在线观看18 | 我们好看的2018视频在线观看 | 一本一道av无码中文字幕 | 精品久久一二三区 | 国产精品美女久久久久图片 | 欧美视频在线观看免费 | 免费人成| 午夜av一区二区三区 | 成人综合社区 | 美女被草出白浆 | 亚洲av永久无码精品三区在线 | 亚洲熟女少妇一区 | 刘亦菲毛片 | 涩涩视频免费观看 | 日日日插插插 | 精品国产乱码久久久久久久软件 |