• 正文
    • 1. 什么是驅(qū)動
    • 2. 各分態(tài)的詳解
    • 3. 字符設備驅(qū)動工作原理
    • 基于框架編寫驅(qū)動代碼:
    • 字符設備驅(qū)動框架代碼
    • 驅(qū)動框架執(zhí)行流程:
    • 驅(qū)動模塊代碼編譯
    • 加載內(nèi)核驅(qū)動
  • 相關推薦
申請入駐 產(chǎn)業(yè)圖譜

Linux中級——“驅(qū)動” 控制硬件必須學會的底層知識

02/03 11:45
261
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

1. 什么是驅(qū)動

驅(qū)動就是對底層硬件設備的操作進行封裝,并向上層提供函數(shù)接口。

設備分類:linux系統(tǒng)將設備分為3類:字符設備、塊設備、網(wǎng)絡設備。

    • 字符設備:指只能一個字節(jié)一個字節(jié)讀寫的設備,不能隨機讀取設備內(nèi)存中的某一數(shù)據(jù),讀取數(shù)據(jù)需要按照先后順序。字符設備是面向流的設備,常見的字符設備有鼠標、鍵盤、串口、控制臺和LED設備等,字符設備驅(qū)動程序通常至少要實現(xiàn)open、close、read和write的系統(tǒng)調(diào)用,字符終端(/dev/console)和串口(/dev/ttyS0以及類似設備)就是兩個字符設備,它們能很好的說明“流”這種抽象概念。塊設備:指可以從設備的任意位置讀取一定長度數(shù)據(jù)的設備。塊設備包括硬盤、磁盤、U盤和SD卡等。網(wǎng)絡設備:網(wǎng)絡設備可以是一個硬件設備,如網(wǎng)卡; 但也可以是一個純粹的軟件設備,
    • 比如回環(huán)接口(lo).一個網(wǎng)絡接口負責發(fā)送和接收數(shù)據(jù)報文。

我們來舉一個例子來說一下整體的調(diào)用過程

    1. 在上層我們調(diào)用 c語言 open函數(shù)open("/dev/pin4",O_RDWR);
    1. 調(diào)用/dev下的pin4以可讀可寫的方式打開,**==對于上層open調(diào)用到內(nèi)核時會發(fā)生一次軟中斷中斷號是0X80,從用戶空間進入到內(nèi)核空間==**open會調(diào)用到system_call
    1. (內(nèi)核函數(shù)),system_call會根據(jù)/dev/pin4設備名,去找出你要的設備號。再調(diào)到虛擬文件VFS (為了上層調(diào)用到確切的硬件統(tǒng)一化),調(diào)用VFS里的sys_open
    ,sys_open會找到在驅(qū)動鏈表里面,根據(jù)主設備號和次設備號找到引腳4里的open函數(shù),我們在引腳4里的open是對寄存器操作

我們寫驅(qū)動無非就是做添加驅(qū)動:添加驅(qū)動做哪些事呢?

    設備名設備號設備驅(qū)動函數(shù) (操作寄存器 來驅(qū)動 IO口)

==綜上所述==如果想要打開dev下面的pin4引腳,過程是:用戶態(tài)調(diào)用open(“/de/pin4”,O_RDWR),對于內(nèi)核來說,上層調(diào)用open函數(shù)會觸發(fā)一個軟中斷(系統(tǒng)調(diào)用專用,中斷號是0x80,0x80代表發(fā)生了一個系統(tǒng)調(diào)用),系統(tǒng)進入內(nèi)核態(tài),并走到system_call,可以認為這個就是此軟中斷的中斷服務程序入口,然后通過傳遞過來的系統(tǒng)調(diào)用號來決定調(diào)用相應的系統(tǒng)調(diào)用服務程序(在這里是調(diào)用VFS中的sys_open)。sys_open會在內(nèi)核的驅(qū)動鏈表里面根據(jù)設備名和設備號查找到相關的驅(qū)動函數(shù)(每一個驅(qū)動函數(shù)是一個節(jié)點),**==驅(qū)動函數(shù)里面有通過寄存器操控IO口的代碼,進而可以控制IO口實現(xiàn)相關功能==**。

2. 各分態(tài)的詳解

用戶態(tài):

    • 是指用戶編寫程序、運行程序的層面,用戶態(tài)在開發(fā)時需要C的基礎和C庫,C庫講到文件,進程,進程間通信,線程,網(wǎng)絡,界面(GTk)。C庫(是linux標準庫一定有):就是Clibary,提供了程序支配內(nèi)核干活的接口,調(diào)用的

open,read,write,fork,pthread,socket

    由此處封裝實現(xiàn),由寫的應用程序調(diào)用,C庫中的各種API調(diào)用的是內(nèi)核態(tài),支配內(nèi)核干活。

內(nèi)核態(tài):

用戶要使用某個硬件設備時,需要內(nèi)核態(tài)的設備驅(qū)動程序,進而驅(qū)動硬件干活,就比如之前文章里面所提到的wiringPi庫,就是提供了用戶操控硬件設備的接口,在沒有wiringPi庫時就需要自己實現(xiàn)wiringPi庫的功能,就是自己寫設備驅(qū)動程序。這樣當我們拿到另一種類型的板子時,同樣也可以完成開發(fā)。

在linux中一切皆文件,各種的文件和設備(比如:鼠標、鍵盤、屏幕、flash、內(nèi)存、網(wǎng)卡、如下圖所示:)都是文件,那既然是文件了,就可以使用文件操作函數(shù)來操作這些設備。

有一個問題,open、read等這些文件操作函數(shù)是如何知道打開的文件是哪一種硬件設備呢?①在open函數(shù)里面輸入對應的文件名,進而操控對應的設備。②通過 ==設備號(主設備號和次設備號)== 。除此之外我們還要了解這些驅(qū)動程序的位置,和如何實現(xiàn)這些驅(qū)動程序,每一種硬件設備對應不同的驅(qū)動(這些驅(qū)動有我們自己來實現(xiàn))。

Linux的設備管理是和文件系統(tǒng)緊密結(jié)合的,各種設備都以文件的形式存放在/dev目錄下,稱為 ==設備文件==。應用程序可以打開、關閉和讀寫這些設備文件,完成對設備的操作,就像操作普通的數(shù)據(jù)文件一樣。為了管理這些設備,系統(tǒng)為設備編了號,每個設備號又分為==主設備號== 和 ==次設備號==(如下圖所示:)。

主設備號用來區(qū)分不同種類的設備,而次設備號用來區(qū)分同一類型的多個設備。對于常用設備,Linux有約定俗成的編號,如硬盤的主設備號是3。一個字符設備或者塊設備都有一個主設備號和次設備號。**==主設備號和次設備號統(tǒng)稱為設備號==**。

主設備號用來表示一個特定的驅(qū)動程序。
次設備號用來表示使用該驅(qū)動程序的各設備。

例如一個嵌入式系統(tǒng),有兩個LED指示燈,LED燈需要獨立的打開或者關閉。那么,可以寫一個LED燈的字符設備驅(qū)動程序,可以將其主設備號注冊成5號設備,次設備號分別為1和2。這里,次設備號就分別表示兩個LED燈。

==驅(qū)動鏈表==

管理所有設備的驅(qū)動,添加或查找
添加是發(fā)生在我們編寫完驅(qū)動程序,加載到內(nèi)核。
查找是在調(diào)用驅(qū)動程序,由應用層用戶空間去查找使用open函數(shù)。

驅(qū)動插入鏈表的順序由設備號檢索,就是說主設備號和次設備號除了能區(qū)分不同種類的設備和不同類型的設備,還能起到將驅(qū)動程序加載到鏈表的某個位置,在下面介紹的驅(qū)動代碼的開發(fā)無非就是添加驅(qū)動(添加設備號、設備名和設備驅(qū)動函數(shù))和調(diào)用驅(qū)動。

    system_call函數(shù)是怎么找到詳細的系統(tǒng)調(diào)用服務例程的呢?通過系統(tǒng)調(diào)用號查找系統(tǒng)調(diào)用表sys_call_table! 軟中斷指令INT 0x80運行時,系統(tǒng)調(diào)用號會被放入 eax寄存器中,system_call函數(shù)能夠讀取eax寄存器獲取,然后將其乘以4,生成偏移地址,然后以sys_call_table為基址?;芳由掀频刂?,就能夠得到詳細的系統(tǒng)調(diào)用服務例程的地址了!然后就到了系統(tǒng)調(diào)用服務例程了。

補充:

    每個系統(tǒng)調(diào)用都對應一個系統(tǒng)調(diào)用號,而系統(tǒng)調(diào)用號就對應內(nèi)核中的相應處理函數(shù)。所有系統(tǒng)調(diào)用都是通過中斷0x80來觸發(fā)的。使用系統(tǒng)調(diào)用時,通過eax 寄存器將系統(tǒng)調(diào)用號傳遞到內(nèi)核,系統(tǒng)調(diào)用的入?yún)⑼ㄟ^ebx、ecx……依次傳遞到內(nèi)核和函數(shù)一樣,系統(tǒng)調(diào)用的返回值保存在eax中,所有要從eax中取出

3. 字符設備驅(qū)動工作原理

字符設備驅(qū)動工作原理在linux的世界里一切皆文件,所有的硬件設備操作到應用層都會被抽象成文件的操作。我們知道如果應用層要訪問硬件設備,它必定要調(diào)用到硬件對應的驅(qū)動程序。Linux內(nèi)核有那么多驅(qū)動程序,應用怎么才能精確的調(diào)用到底層的驅(qū)動程序呢?

==必須知道的知識:==

在Linux文件系統(tǒng)中,每個文件都用一個 struct inode結(jié)構(gòu)體來描述,這個結(jié)構(gòu)體記錄了這個文件的所有信息,例如文件類型,訪問權(quán)限等。

在linux操作系統(tǒng)中,每個驅(qū)動程序在應用層的/dev目錄或者其他如/sys目錄下都會有一個文件與之對應。

在linux操作系統(tǒng)中, 每個驅(qū)動程序都有一個設備號。

在linux操作系統(tǒng)中,每打開一次文件,Linux操作系統(tǒng)會在VFS層分配一個struct file結(jié)構(gòu)體來描述打開的文件。

(1) 當open函數(shù)打開設備文件時,可以根據(jù)設備文件對應的struct inode結(jié)構(gòu)體描述的信息,可以知道接下來要操作的設備類型(字符設備還是塊設備),還會分配一個struct file結(jié)構(gòu)體。

(2) 根據(jù)struct inode結(jié)構(gòu)體里面記錄的設備號,可以找到對應的驅(qū)動程序。這里以字符設備為例。在Linux操作系統(tǒng)中每個字符設備都有一個struct cdev結(jié)構(gòu)體。此結(jié)構(gòu)體描述了字符設備所有信息,其中最重要的一項就是字符設備的操作函數(shù)接口。

(3) 找到struct cdev結(jié)構(gòu)體后,linux內(nèi)核就會將struct cdev結(jié)構(gòu)體所在的內(nèi)存空間首地址記錄在struct inode結(jié)構(gòu)體i_cdev成員中,將struct cdev結(jié)構(gòu)體中的記錄的函數(shù)操作接口地址記錄在struct file結(jié)構(gòu)體的f_ops成員中。

(4) 任務完成,VFS層會給應用返回一個文件描述符(fd)。這個fd是和struct file結(jié)構(gòu)體對應的。接下來上層應用程序就可以通過fd找到struct file,然后在struct file找到操作字符設備的函數(shù)接口file_operation了。

其中,cdev_init和cdev_add在驅(qū)動程序的入口函數(shù)中就已經(jīng)被調(diào)用,分別完成字符設備與file_operation函數(shù)操作接口的綁定,和將字符驅(qū)動注冊到內(nèi)核的工作。

基于框架編寫驅(qū)動代碼:

    上層調(diào)用代碼:操作驅(qū)動的上層代碼(pin4test.c):
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/stat.h>
#include?<fcntl.h>

void?main()
{
????????int?fd,data;
????????fd?=?open("/dev/pin4",O_RDWR);
????????if(fd<0){
????????????????printf("open?failn");
????????????????perror("reson:");
????????}
????????else{
????????????????printf("open?successfuln");
????????}
????????fd=write(fd,'1',1);
}

-內(nèi)核驅(qū)動
**==最簡單的字符設備驅(qū)動框架==**:

字符設備驅(qū)動框架代碼

#include?<linux/fs.h>???//file_operations聲明
#include?<linux/module.h>????//module_init??module_exit聲明
#include?<linux/init.h>??????//__init??__exit?宏定義聲明
#include?<linux/device.h>??//class??devise聲明
#include?<linux/uaccess.h>???//copy_from_user?的頭文件
#include?<linux/types.h>?????//設備號??dev_t?類型聲明
#include?<asm/io.h>??????????//ioremap?iounmap的頭文件

static?struct?class?*pin4_class;??
static?struct?device?*pin4_class_dev;

static?dev_t?devno;????????????????//設備號,devno是用來接收創(chuàng)建設備號函數(shù)的返回值,銷毀的時候需要傳這個參數(shù)
static?int?major?=231;???????//主設備號
static?int?minor?=0;??????//次設備號
static?char?*module_name="pin4";???//模塊名

//led_open函數(shù)
static?int?pin4_open(struct?inode?*inode,struct?file?*file)
{
????printk("pin4_openn");??//內(nèi)核的打印函數(shù)和printf類似???
????return?0;
}

//led_write函數(shù)
static?ssize_t?pin4_write(struct?file?*file,const?char?__user?*buf,size_t?count,?loff_t?*ppos)
{
?
?printk("pin4_writen");??//內(nèi)核的打印函數(shù)和printf類似
????return?0;
}
//將上面的函數(shù)賦值給一個結(jié)構(gòu)體中,方便下面加載到到驅(qū)動鏈表中去
static?struct?file_operations?pin4_fops?=?{
//static防止其他文件也有同名pin4_fops
//static限定這個結(jié)構(gòu)體的作用,僅僅只在這個文件。
????.owner?=?THIS_MODULE,
????.open??=?pin4_open,
????.write?=?pin4_write,
};
/*
上面的代碼等同于以下代碼(但是在單片機keil的編譯環(huán)境里面不允許以上寫法):
里面的每個pin4_fops結(jié)構(gòu)體成員單獨賦值
static?struct?file_operations?pin4_fops;??
????pin4_fops.owner?=?THIS_MODULE;
????pin4_fops.open??=?pin4_open;
????pin4_fops.write?=?pin4_write;
*/
//static限定這個結(jié)構(gòu)體的作用,僅僅只在這個文件。


int?__init?pin4_drv_init(void)???//真實的驅(qū)動入口
{

????int?ret;
????devno?=?MKDEV(major,minor);??//2.?創(chuàng)建設備號
????ret???=?register_chrdev(major,?module_name,&pin4_fops);??
????//3.?注冊驅(qū)動??告訴內(nèi)核,把這個驅(qū)動加入到內(nèi)核驅(qū)動的鏈表中

????pin4_class=class_create(THIS_MODULE,"myfirstdemo");//由代碼在dev下自動生成設備,創(chuàng)建一個類
????pin4_class_dev?=device_create(pin4_class,NULL,devno,NULL,module_name);?
?????//創(chuàng)建設備文件,先有上面那一行代碼,創(chuàng)建一個類然后這行代碼,類下面再創(chuàng)建一個設備。

?
????return?0;
}

void?__exit?pin4_drv_exit(void)
{

????device_destroy(pin4_class,devno);//先銷毀設備
????class_destroy(pin4_class);//再銷毀類
????unregister_chrdev(major,?module_name);??//卸載驅(qū)動

}

module_init(pin4_drv_init);??//入口,內(nèi)核加載驅(qū)動的時候,這個宏(不是函數(shù))會被調(diào)用,去調(diào)用pin4_drv_init這個函數(shù)
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL?v2");

手動創(chuàng)建設備名

    • 上面這個字符設備驅(qū)動代碼里面有讓代碼自動的在dev下面生成設備除此之外我們還可以手動創(chuàng)建設備名。使用指令:

sudo mknod +設備名字 +設備類型(c表示字符設備驅(qū)動) +主設備號+次設備號

    • ?b :create a block

 

    • (buffered) pecial file。c, u:create a character (unbuffered)

 

    • special file。? p:create a FIFO, ? 刪除手動創(chuàng)建的設備名直接rm就好。如下圖所示:

驅(qū)動框架執(zhí)行流程:

通過上層程序打開某個設備,如果沒有驅(qū)動,執(zhí)行就會報錯,在內(nèi)核驅(qū)動中,上層系統(tǒng)調(diào)用open,wirte函數(shù)會觸發(fā)sys_call、sys_call會調(diào)用sys_open,sys_write、sys_open,和sys_write通過主設備號在內(nèi)核的驅(qū)動鏈表里把設備驅(qū)動找出來,執(zhí)行里面的open和write、我們?yōu)榱苏麄€流程順利進行,我們要先準備好驅(qū)動(設備驅(qū)動文件)。

設備驅(qū)動文件有固定框架:module_init(pin4_drv_init);

//入口 去調(diào)用pin4_drv_init函數(shù)int __init pin4_drv_init(void)

//真實的驅(qū)動入口驅(qū)動入口devno = MKDEV(major,minor); // 創(chuàng)建設備號 register_chrdev(major, module_name,&pin4_fops);

//注冊驅(qū)動 ?告訴內(nèi)核,把上面準備好的結(jié)構(gòu)體加入到內(nèi)核驅(qū)動的鏈表中pin4_class=class_create(THIS_MODULE,"myfirstdemo");

//由代碼在dev下自動生成設備,創(chuàng)建一個類pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name);

//創(chuàng)建設備文件。主要是要讓/dev下多了個文件供我們上層可以open如果沒有,也可以手動sudo mknod +設備名字 +設備類型(c表示字符設備驅(qū)動) +主設備號+次設備號的去創(chuàng)造設備

驅(qū)動模塊代碼編譯

驅(qū)動模塊代碼編譯

驅(qū)動模塊代碼編譯(模塊的編譯需要配置過的內(nèi)核源碼,編譯、連接后生成的內(nèi)核模塊后綴為.ko,編譯過程首先會到內(nèi)核源碼目錄下,讀取頂層的Makefile文件,然后再返回模塊源碼所在目錄。):

    使用下面的的代碼:(就是上面的驅(qū)動架構(gòu)代碼)
#include?<linux/fs.h>????????????//file_operations聲明
#include?<linux/module.h>????//module_init??module_exit聲明
#include?<linux/init.h>??????//__init??__exit?宏定義聲明
#include?<linux/device.h>????????//class??devise聲明
#include?<linux/uaccess.h>???//copy_from_user?的頭文件
#include?<linux/types.h>?????//設備號??dev_t?類型聲明
#include?<asm/io.h>??????????//ioremap?iounmap的頭文件


static?struct?class?*pin4_class;
static?struct?device?*pin4_class_dev;

static?dev_t?devno;????????????????//設備號
static?int?major?=231;?????????????????????//主設備號
static?int?minor?=0;???????????????????????//次設備號
static?char?*module_name="pin4";???//模塊名

//led_open函數(shù)
static?int?pin4_open(struct?inode?*inode,struct?file?*file)
{
????????printk("pin4_openn");??//內(nèi)核的打印函數(shù)和printf類似

????????return?0;
}
//read函數(shù)
static?int?pin4_read(struct?file?*file,char?__user?*buf,size_t?count,loff_t?*ppos)
{
????????printk("pin4_readn");??//內(nèi)核的打印函數(shù)和printf類似

????????return?0;
}

//led_write函數(shù)
static?ssize_t?pin4_write(struct?file?*file,const?char?__user?*buf,size_t?count,?loff_t?*ppos)
{

????????printk("pin4_writen");??//內(nèi)核的打印函數(shù)和printf類似
????????return?0;
}

static?struct?file_operations?pin4_fops?=?{

????????.owner?=?THIS_MODULE,
????????.open??=?pin4_open,
????????.write?=?pin4_write,
????????.read??=?pin4_read,
};
//static限定這個結(jié)構(gòu)體的作用,僅僅只在這個文件。
int?__init?pin4_drv_init(void)???//真實的驅(qū)動入口
{

????????int?ret;
????????devno?=?MKDEV(major,minor);??//創(chuàng)建設備號
??ret???=?register_chrdev(major,?module_name,&pin4_fops);??//注冊驅(qū)動??告訴內(nèi)核,把這個驅(qū)動加入到內(nèi)核驅(qū)動的鏈表中

????????pin4_class=class_create(THIS_MODULE,"myfirstdemo");//讓代碼在dev下自動>生成設備
????????pin4_class_dev?=device_create(pin4_class,NULL,devno,NULL,module_name);??//創(chuàng)建設備文件


????????return?0;
}

void?__exit?pin4_drv_exit(void)
{

????????device_destroy(pin4_class,devno);
????????class_destroy(pin4_class);
????????unregister_chrdev(major,?module_name);??//卸載驅(qū)動
}
module_init(pin4_drv_init);??//入口,內(nèi)核加載驅(qū)動的時候,這個宏會被調(diào)用,去調(diào)用pin4_drv_init這個函數(shù)
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL?v2");
    • 在導入虛擬機的內(nèi)核代碼中找到字符設備驅(qū)動的那一個文件夾:

/SYSTEM/linux-rpi-4.19.y/drivers/char

    • 將以上代碼復制到一個文件中,然后下一步要做的是就是:將上面的驅(qū)動代碼編譯生成模塊,再修改Makefile。(你放那個文件下,就改哪個文件下的Makefile)文件內(nèi)容如下圖所示:(-y表示編譯進內(nèi)核,-m表示生成驅(qū)動模塊,CONFIG_表示是根據(jù)config生成的)
    • 所以只需要將

obj-m += pin4drive.o

    • 添加到Makefile中即可。下圖:Makefile文件圖

編譯生成驅(qū)動模塊,將生成的.ko文件發(fā)送給樹莓派然后回/SYSTEM/linux-rpi-4.19.y下使用指令:ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules進行編譯生成驅(qū)動模塊。然后將生成的.ko文件發(fā)送給樹莓派:scp drivers/char/pin4driver.ko pi@192.168.0.104:/home/pi編譯生成驅(qū)動模塊會生成以下幾個文件:

.o的文件是object文件,.ko是kernel object,與.o的區(qū)別在于其多了一些sections,比如.modinfo.modinfo section是由kernel source里的modpost工具生成的,
包括MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_LICENSE, device ID table以及模塊依賴關系等等。depmod 工具根據(jù).modinfo section生成modules.dep, modules.*map等文件,以便modprobe更方便的加載模塊。

    編譯過程中,經(jīng)歷了這樣的步驟:
    先進入Linux內(nèi)核所在的目錄,并編譯出pin4drive.o文件運行MODPOST會生成臨時的pin4drive.mod.c文件, ?而后根據(jù)此文件編譯出pin4drive.mod.o,之后連接pin4drive.o和pin4drive.mod.o文件得到模塊目標文件pin4drive.ko,最后離開Linux內(nèi)核所在的目錄。

將pin4test.c (上層調(diào)用代碼) 進行 交叉編譯后發(fā)送給樹莓派,就可以看到pi目錄下存在發(fā)送過來的.ko文件pin4test這兩個文件,如下圖所示:

加載內(nèi)核驅(qū)動

然后使用指令:sudo insmod pin4drive.ko加載內(nèi)核驅(qū)動(相當于通過insmod調(diào)用了module_init這個宏,然后將整個結(jié)構(gòu)體加載到驅(qū)動鏈表中)
加載完成后就可以在dev下面看到名字為pin4的設備驅(qū)動(這個和驅(qū)動代碼里面static char *module_name="pin4"; //模塊名這行代碼有關),設備號也和代碼里面相關。

lsmod可以查看驅(qū)動已經(jīng)裝進去了。

    • 我們再執(zhí)行./pin4test 執(zhí)行上層代碼 執(zhí)行上層代碼出現(xiàn)以下錯誤:表示沒有權(quán)限

使用指令:sudo chmod 666 /dev/pin4為pin4賦予權(quán)限,讓所有人都可以打開成功。

然后再次執(zhí)行pin4test表面上看沒有任何信息輸出,其實內(nèi)核里面有打印信息只是上層看不到如果想要查看內(nèi)核打印的信息可以使用指令:dmesg |grep pin4。如下圖所示:表示驅(qū)動調(diào)用成功

在裝完驅(qū)動后可以使用指令:sudo rmmod +驅(qū)動名(不需要寫ko)將驅(qū)動卸載。

為什么生成驅(qū)動模塊需要在虛擬機上生成

為什么生成驅(qū)動模塊需要在虛擬機上生成?樹莓派不行嗎?

生成驅(qū)動模塊需要編譯環(huán)境(linux源碼并且編譯,需要下載和系統(tǒng)版本相同的Linux內(nèi)核源代碼),也可以在樹莓派上面編譯,但在樹莓派里編譯,效率會很低,要非常久。這篇文章有講樹莓派驅(qū)動的本地編譯。

相關推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設計資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

公眾號『一口Linux』號主彭老師,擁有15年嵌入式開發(fā)經(jīng)驗和培訓經(jīng)驗。曾任職ZTE,某研究所,華清遠見教學總監(jiān)。擁有多篇網(wǎng)絡協(xié)議相關專利和軟件著作。精通計算機網(wǎng)絡、Linux系統(tǒng)編程、ARM、Linux驅(qū)動、龍芯、物聯(lián)網(wǎng)。原創(chuàng)內(nèi)容基本從實際項目出發(fā),保持原理+實踐風格,適合Linux驅(qū)動新手入門和技術(shù)進階。