編寫Linux裝置驅動

2021-04-19 00:15:07 字數 4473 閱讀 9740

核心版本: 2.4.22

閱讀此文的目的: 學會編寫linux裝置

驅動。

閱讀此文的方法: 閱讀以下2個

檔案: hello.c,asdf.c。

此文假設讀者:

已經能用c語言編寫linux應用程式,

理解"字元裝置檔案, 塊裝置檔案, 主裝置號, 次裝置號",

會寫簡單的shell指令碼和makefile。

1. "hello.c"

--------------------------------

/* * 這是我們的第乙個原始檔,

* 它是乙個可以載入的核心模組,

* 載入時顯示"hello,world!",

* 解除安裝時顯示"bye!"。

* 需要說明一點,寫核心或核心模組不能用寫應用程式時的

系統呼叫或函式庫,

* 因為我們寫的就是為應用程式提供系統呼叫的**。

* 核心有專用的函式庫,如, , 等,

* 現在還沒必要了解得很詳細,

* 這裡用到的printk的功能類似於printf。

* "/usr/src/linux"是你實際的核心原始碼目錄的乙個符號鏈結,

* 如果沒有現在就建立乙個,因為下面和以後都會用到。

* 編譯它用"gcc -c -i/usr/src/linux/include hello.c",

* 如果正常會生成檔案hello.o,

* 載入它用"in**od hello.o",

* 只有在文字終端下才能看到輸出。

* 解除安裝它用"rmmod hello"

*/ /*

* 小技巧: 在使用者目錄的.bashrc裡加上一行:

* alias mkmod='gcc -c -i/usr/src/linux/include'

* 然後重新

登陸shell,

* 以後就可以用"mkmod hello.c"的方式來編譯核心模組了。

*/ /* 開始例行公事 */

#ifndef __kernel__

# define __kernel__

#endif

#ifndef module

# define module

#endif

#include

#include

module_license("gpl");

#ifdef config_**p

#define __**p__

#endif

/* 結束例行公事 */

#include /* printk()在這個檔案裡 */

static int

init_module

() static void

cleanup_module

() ------------------------------------

2. "asdf.c"

------------------------------------

/* * 這個檔案是乙個核心模組。

* 核心模組的編譯,載入和解除安裝在前面已經介紹了。

* 這個模組的功能是,建立乙個字元裝置。

* 這個裝置是一塊4096位元組的共享

記憶體。

* 核心分配的主裝置號會在載入模組時顯示。

*/ /* 開始例行公事 */

#ifndef __kernel__

# define __kernel__

#endif

#ifndef module

# define module

#endif

#include

#include

#ifdef config_**p

#define __**p__

#endif

module_license("gpl");

/* 結束例行公事 */

#include /* copy_to_user(), copy_from_user */

#include /* struct file_operations, register_chrdev(), ... */

#include /* printk()在這個檔案裡 */

#include /* 和

任務排程有關 */

#include /* u8, u16, u32 ... */

/* * 關於核心功能庫,可以去網上搜尋詳細資料,

*/ /* 檔案被操作時的**功能 */

static int asdf_open (struct inode *inode, struct file *filp);

static int asdf_release (struct inode *inode, struct file *filp);

static ssize_t asdf_read (struct file *filp, char *buf, size_t count,loff_t *f_pos);

static ssize_t asdf_write (struct file *filp, const char *buf, size_t count,loff_t *f_pos);

static loff_t asdf_lseek (struct file * file, loff_t offset, int orig);

/* 申請主裝置號時用的結構, 在linux/fs.h裡定義 */

struct file_operations asdf_fops = ;

static int asdf_major; /* 用來儲存申請到的主裝置號 */

static u8 asdf_body[4096]="asdf_body/n"; /* 裝置 */

static int

init_module

() static void

cleanup_module

() /*

* 編譯這個模組然後載入它,

* 如果正常,會顯示你的裝置的主裝置號。

* 現在你的裝置就建立好了,我們可以測試一下。

* 假設你的模組申請到的主裝置號是254,

* 執行"mknod abc c 254 0",就建立了我們的裝置檔案abc。

* 可以把它當成乙個4096位元組的記憶體塊來測試一下,

* 比如"cat abc", "cp abc image", "cp image abc",

* 或寫幾個應用程式用它來進行通訊。

* 介紹一下兩個需要注意的事,

* 一是printk()的顯示只有在非圖形模式的終端下才能看到,

* 二是載入過的模組最好在不用以後解除安裝掉。

* 如果對linux環境的系統呼叫很陌生,建議先看apue這本書。

*/ static int

asdf_open /* open** */ (

struct inode *inode,

struct file *filp )

static int

asdf_release /* close** */ (

struct inode *inode,

struct file *filp )

static ssize_t

asdf_read /* read** */ (

struct file *filp,

char *buf,

size_t count,

loff_t *f_pos )

if (copy_to_user(buf, asdf_body *f_pos, count)) return -efault; /* 把資料寫到應用程式空間 */

*f_pos = pos; /* 改變檔案的讀寫位置 */

return count; /* 返回讀到的位元組數 */ }

static ssize_t

asdf_write /* write**,和read一一對應 */ (

struct file *filp,

const char *buf,

size_t count,

loff_t *f_pos )

if (copy_from_user(asdf_body *f_pos, buf, count)) return -efault;

*f_pos = pos;

return count; }

static loff_t

asdf_lseek /* lseek** */ (

struct file * file,

loff_t offset,

int orig )

if ((pos>4096) || (pos<0))

return file->f_pos = pos; }

linux裝置驅動編寫 tasklet機制

在編寫裝置驅動時,tasklet機制是一種比較常見的機制,通常用於減少中斷處理的時間,將本應該是在中斷服務程式中完成的任務轉化成軟中斷完成。為了最大程度的避免中斷處理時間過長而導致中斷丟失,有時候我們需要把一些在中斷處理中不是非常緊急的任務放在後面執行,而讓中斷處理程式盡快返回。在老版本的 linu...

linux2 6 裝置驅動編寫

從2.6版本開始引入了platform這個概念,在開發底層驅動程式時,首先要確認的就是裝置的資源資訊,例如裝置的位址,在2.6核心中將每個裝置的資源用結構platform device來描述,該結構體定義在kernel include linux platform device.h中,struct ...

關於如何編寫linux裝置驅動

關於如何編寫linux裝置驅動 1 首先確定硬體介面使用的匯流排,然後確定要實現的功能,是網絡卡 sensor還是什麼,2 再確定對上層應用暴露的介面,從而選擇子系統,例如iio input子系統等。由於linux只有字元裝置 塊裝置 網路裝置三種裝置,其實iio input子系統都是字元裝置,只是...