linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

<code>關注“技術簡說”,一步一步教你開發linux內核和驅動。/<code> 

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

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

我的環境是ubuntu 14.04,內核版本 4.4.0-31-generic,本節我會開發一個基於ubuntu 14.04下的最簡單的hello驅動,帶大家領略驅動的魅力。

開發linux內核驅動需要以下4個步驟:

  1. 編寫hello驅動代碼
  2. 編寫makefile
  3. 編譯和加載hello驅動
  4. 編寫應用程序測試hello驅動
linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

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

<code> 
 
 
 
 
 
 
 

 
 
 

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_open\r\n"

);

return

0

; }

ssize_t

hello_write(struct file *f,

const

char

__user *u,

size_t

s,

loff_t

*l) { printk(KERN_EMERG

"hello_write\r\n"

);

return

0

; }

ssize_t

hello_read(struct file *f,

char

__user *u,

size_t

s,

loff_t

*l) { printk(KERN_EMERG

"hello_read\r\n"

);

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"

);/<code>
linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

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

<code>

ifneq

(

$(KERNELRELEASE)

,) obj-m := helloDev.o

else

PWD :=

$(

shell

pwd)

KDIR:= /lib/modules/4.4.0-31-generic/build

all:

make -C

$(KDIR)

M=

$(PWD)

clean:

rm -rf *.o *.ko *.mod.c *.symvers *.c~ *~

endif

/<code>

linux應用層程序在編譯的時候,需要鏈接c運行時庫和glibc庫。那驅動需不需要呢?

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

linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

驅動文件和Makefile都有了,那麼接下來就可以編譯和加載驅動了!

在驅動目錄下,執行make進行編譯:

linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

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

接下來把這個驅動加載到內核:

linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

helloDriver加載成功,打印出了:

[11837.379638] register_chrdev_region ok

[11837.379642] hello driver init

可見,執行insmod的時候,驅動文件裡的hello_init被調用了。

那驅動文件裡的hello_exit什麼時候會被調用呢?

可能聰明的你已經猜到了,那就是執行 rmmod helloDev.ko的時候。

linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

本節來看驅動的測試。

我們需要編寫一個應用層的程序來對hello驅動進行測試:(test.c)

<code> 
 
 
 


 

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

(

"%d\r\n"

,fd);

if

(

-1

== fd) { perror(

"open file error\r\n"

);

return

-1

; }

else

{

printf

(

"open successe\r\n"

); } w_len = write(fd,buf, DATA_NUM); r_len = read(fd, buf, DATA_NUM);

printf

(

"%d %d\r\n"

, w_len, r_len);

printf

(

"%s\r\n"

,buf);

return

0

; }/<code>

編譯並執行,發現錯誤,找不到設備文件:

linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

這是因為還沒有創建hello驅動的設備文件,我們為hello驅動手動創建設備文件:

<code>root@ubuntu

:/home/jinxin/drivers/helloDev

/<code>

備註:這裡的232和0要跟驅動文件裡定義的主次設備號對應起來!

然後再次執行測試程序,發現成功了:

<code>root@ubuntu

:/home/jinxin/drivers/helloDev

3

open successe

0

0

root@ubuntu

:/home/jinxin/drivers/helloDev

/<code>

然後再次執行dmesg查看驅動輸出,發現驅動裡的hell_open, hello_write, hello_read被依次調用了。

linux驅動開發第1講:帶你編寫一個最簡單的字符設備驅動

這就是一個完整的、最簡單的驅動的開發和測試的流程。

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

1.驅動測試的時候為什麼要有設備文件,設備文件的作用是什麼?hello驅動的設備文件創建的時候為什麼要指定主設備號為232, 此設備號為0?

2.對/dev/hello執行write()調用的時候,怎麼就調用到了驅動裡的hello_write()裡去了?

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

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

<code>關注“技術簡說”,一步一步教你開發linux內核和驅動。/<code>


分享到:


相關文章: