日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

 

關(guān)注“技術(shù)簡說”,一步一步教你開發(fā)linux內(nèi)核和驅(qū)動

hello world!是廣大程序員入門一門新語言的第一步。

今天,我們來看一個hello驅(qū)動,希望這是大家入門linux內(nèi)核驅(qū)動的良好開局。

我的環(huán)境是ubuntu 14.04,內(nèi)核版本 4.4.0-31-generic,本節(jié)我會開發(fā)一個基于ubuntu 14.04下的最簡單的hello驅(qū)動,帶大家領(lǐng)略驅(qū)動的魅力。

開發(fā)linux內(nèi)核驅(qū)動需要以下4個步驟:

  1. 編寫hello驅(qū)動代碼
  2. 編寫makefile
  3. 編譯和加載hello驅(qū)動
  4. 編寫應(yīng)用程序測試hello驅(qū)動
linux內(nèi)核驅(qū)動第1講:帶你編寫一個最簡單的字符設(shè)備驅(qū)動

 

驅(qū)動代碼如下 helloDev.c,這是一個最小、最簡單的驅(qū)動,我去掉了其他的不相干代碼,盡量讓大家能了解驅(qū)動本身。

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>

#define BUFFER_MAX    (10)
#define OK            (0)
#define ERROR         (-1)

struct cdev *gDev;
struct file_operations *gFile;
dev_t  devNum;
unsigned int subDevNum = 1;
int reg_major  =  232;    
int reg_minor =   0;
char *buffer;
int flag = 0;
int hello_open(struct inode *p, struct file *f)
{
    printk(KERN_EMERG"hello_openrn");
    return 0;
}

ssize_t hello_write(struct file *f, const char __user *u, size_t s, loff_t *l)
{
    printk(KERN_EMERG"hello_writern");
    return 0;
}
ssize_t hello_read(struct file *f, char __user *u, size_t s, loff_t *l)
{
    printk(KERN_EMERG"hello_readrn");      
    return 0;
}
int hello_init(void)
{
    
    devNum = MKDEV(reg_major, reg_minor);
    if(OK == register_chrdev_region(devNum, subDevNum, "helloworld")){
        printk(KERN_EMERG"register_chrdev_region ok n"); 
    }else {
    printk(KERN_EMERG"register_chrdev_region error n");
        return ERROR;
    }
    printk(KERN_EMERG" hello driver init n");
    gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
    gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
    gFile->open = hello_open;
    gFile->read = hello_read;
    gFile->write = hello_write;
    gFile->owner = THIS_MODULE;
    cdev_init(gDev, gFile);
    cdev_add(gDev, devNum, 3);
    return 0;
}

void __exit hello_exit(void)
{
    cdev_del(gDev);
    unregister_chrdev_region(devNum, subDevNum);
    return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
linux內(nèi)核驅(qū)動第1講:帶你編寫一個最簡單的字符設(shè)備驅(qū)動

 

有了驅(qū)動文件之后,我們還需要一個Makefile才能把驅(qū)動編譯出來:

ifneq ($(KERNELRELEASE),)
obj-m := helloDev.o
else
PWD := $(shell pwd)
KDIR:= /lib/modules/4.4.0-31-generic/build
#KDIR := /lib/modules/`uname -r`/build
all:
	make -C $(KDIR) M=$(PWD)
clean:	
	rm -rf *.o *.ko *.mod.c *.symvers *.c~ *~
endif

linux應(yīng)用層程序在編譯的時候,需要鏈接c運(yùn)行時庫和glibc庫。那驅(qū)動需不需要呢?

驅(qū)動也需要,但是驅(qū)動不能鏈接和使用應(yīng)用層的任何lib庫,驅(qū)動需要引用內(nèi)核的頭文件和函數(shù)。所以,編譯的時候需要指定內(nèi)核源碼的地址。為了開發(fā)方便,也可以安裝內(nèi)核開發(fā)包,之后引用這個內(nèi)核開發(fā)包的目錄也可以。本例為:/lib/modules/4.4.0-31-generic/build

linux內(nèi)核驅(qū)動第1講:帶你編寫一個最簡單的字符設(shè)備驅(qū)動

 

驅(qū)動文件和Makefile都有了,那么接下來就可以編譯和加載驅(qū)動了!

在驅(qū)動目錄下,執(zhí)行make進(jìn)行編譯:

linux內(nèi)核驅(qū)動第1講:帶你編寫一個最簡單的字符設(shè)備驅(qū)動

 

編譯出來的驅(qū)動文件,名稱為:helloDev.ko

接下來把這個驅(qū)動加載到內(nèi)核:

linux內(nèi)核驅(qū)動第1講:帶你編寫一個最簡單的字符設(shè)備驅(qū)動

 

helloDriver加載成功,打印出了:

[11837.379638] register_chrdev_region ok

[11837.379642] hello driver init

可見,執(zhí)行insmod的時候,驅(qū)動文件里的hello_init被調(diào)用了。

那驅(qū)動文件里的hello_exit什么時候會被調(diào)用呢?

可能聰明的你已經(jīng)猜到了,那就是執(zhí)行 rmmod helloDev.ko的時候。

linux內(nèi)核驅(qū)動第1講:帶你編寫一個最簡單的字符設(shè)備驅(qū)動

 

本節(jié)來看驅(qū)動的測試。

我們需要編寫一個應(yīng)用層的程序來對hello驅(qū)動進(jìn)行測試:(test.c)

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>


#define DATA_NUM    (64)
int main(int argc, char *argv[])
{
    int fd, i;
    int r_len, w_len;
    fd_set fdset;
    char buf[DATA_NUM]="hello world";
    memset(buf,0,DATA_NUM);
    fd = open("/dev/hello", O_RDWR);
	printf("%drn",fd);
    if(-1 == fd) {
      	perror("open file errorrn");
		return -1;
    }	
	else {
		printf("open successern");
	}
    
    w_len = write(fd,buf, DATA_NUM);
    r_len = read(fd, buf, DATA_NUM);
    printf("%d %drn", w_len, r_len);
    printf("%srn",buf);

    return 0;
}

編譯并執(zhí)行,發(fā)現(xiàn)錯誤,找不到設(shè)備文件:

linux內(nèi)核驅(qū)動第1講:帶你編寫一個最簡單的字符設(shè)備驅(qū)動

 

這是因為還沒有創(chuàng)建hello驅(qū)動的設(shè)備文件,我們?yōu)閔ello驅(qū)動手動創(chuàng)建設(shè)備文件:

root@ubuntu:/home/jinxin/drivers/helloDev# mknod /dev/hello c 232 0

備注:這里的232和0要跟驅(qū)動文件里定義的主次設(shè)備號對應(yīng)起來!

然后再次執(zhí)行測試程序,發(fā)現(xiàn)成功了:

root@ubuntu:/home/jinxin/drivers/helloDev# ./test 
3
open successe
0 0

root@ubuntu:/home/jinxin/drivers/helloDev# 

然后再次執(zhí)行dmesg查看驅(qū)動輸出,發(fā)現(xiàn)驅(qū)動里的hell_open, hello_write, hello_read被依次調(diào)用了。

linux內(nèi)核驅(qū)動第1講:帶你編寫一個最簡單的字符設(shè)備驅(qū)動

 

這就是一個完整的、最簡單的驅(qū)動的開發(fā)和測試的流程。

我想大家可能會有幾個問題:

1.驅(qū)動測試的時候為什么要有設(shè)備文件,設(shè)備文件的作用是什么?hello驅(qū)動的設(shè)備文件創(chuàng)建的時候為什么要指定主設(shè)備號為232, 此設(shè)備號為0?

2.對/dev/hello執(zhí)行write()調(diào)用的時候,怎么就調(diào)用到了驅(qū)動里的hello_write()里去了?

3.驅(qū)動代碼里的register_chrdev_region這些函數(shù)都是干什么的?實現(xiàn)的地方在哪里?

4.測試程序的read和write的返回值為什么都是0?

針對以上可能的問題,敬請期待《linux內(nèi)核驅(qū)動第2講》,我會一一回答以上問題。

關(guān)注“技術(shù)簡說”,一步一步教你開發(fā)linux內(nèi)核和驅(qū)動

分享到:
標(biāo)簽:linux
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定