亚洲成精品动漫久久精久,九九在线精品视频播放,黄色成人免费观看,三级成人影院,久碰久,四虎成人欧美精品在永久在线

掃一掃
關注微信公眾號

入門文章:教你學會編寫Linux設備驅動
2006-06-21   linux寶庫

  內核版本: 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,

* 加載它用"insmod 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_SMP

#define __SMP__

#endif

/* 結束例行公事 */

#include /* printk()在這個文件里 */

static int

init_module

(){

printk("Hello,World!n");

return 0; /* 如果初始工作失敗,就返回非0 */

}

static void

cleanup_module

(){

printk("Bye!n");

}

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

2. "asdf.c"

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

/*

* 這個文件是一個內核模塊。

* 內核模塊的編譯,加載和卸載在前面已經介紹了。

* 這個模塊的功能是,創建一個字符設備。

* 這個設備是一塊4096字節的共享內存。

* 內核分配的主設備號會在加載模塊時顯示。

*/

/* 開始例行公事 */

#ifndef __KERNEL__

# define __KERNEL__

#endif

#ifndef MODULE

# define MODULE

#endif

#include

#include

#ifdef CONFIG_SMP

#define __SMP__

#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 = {

open: asdf_open,

release: asdf_release,

read: asdf_read,

write: asdf_write,

llseek: asdf_lseek,

};

static int asdf_major; /* 用來保存申請到的主設備號 */

static u8 asdf_body[4096]="asdf_bodyn"; /* 設備 */

static int

init_module

(){

printk ("Hi, This' A Simple Device File!n");

asdf_major = register_chrdev (0, "A Simple Device File", &asdf_fops); /* 申請字符設備的主設備號 */

if (asdf_major < 0) return asdf_major; /* 申請失敗就直接返回錯誤編號 */

printk ("The major is:%dn", asdf_major); /* 顯示申請到的主設備號 */

return 0; /* 模塊正常初始化 */

}

static void

cleanup_module

(){

unregister_chrdev(asdf_major, "A Simple Device File"); /* 注銷以后,設備就不存在了 */

printk("A Simple Device has been removed,Bye!n");

}

/*

* 編譯這個模塊然后加載它,

* 如果正常,會顯示你的設備的主設備號。

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

* 假設你的模塊申請到的主設備號是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

){

printk("^_^ : open %sn ",

current->comm);

/*

* 應用程序的運行環境由內核提供,內核的運行環境由硬件提供。

* 這里的current是一個指向當前進程的指針,

* 現在沒必要了解current的細節。

* 在這里,當前進程正打開這個設備,

* 返回0表示打開成功,內核會給它一個文件描述符。

* 這里的comm是當前進程在Shell下的command字符串。

*/

return 0;

}

static int

asdf_release /* close回調 */

(

struct inode *inode,

struct file *filp

){

printk("^_^ : closen ");

return 0;

}

static ssize_t

asdf_read /* read回調 */

(

struct file *filp,

char *buf,

size_t count,

loff_t *f_pos

){

loff_t pos;

pos = *f_pos; /* 文件的讀寫位置 */

if ((pos==4096) || (count>4096)) return 0; /* 判斷是否已經到設備尾,或寫的長度超過設備大小 */

pos += count;

if (pos > 4096) {

count -= (pos - 4096);

pos = 4096;

}

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

){

loff_t pos;

pos = *f_pos;

if ((pos==4096) || (count>4096)) return 0;

pos += count;

if (pos > 4096) {

count -= (pos - 4096);

pos = 4096;

}

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

){

loff_t pos;

pos = file->f_pos;

switch (orig) {

case 0:

pos = offset;

break;

case 1:

pos += offset;

break;

case 2:

pos = 4096+offset;

break;

default:

return -EINVAL;

}

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

printk("^_^ : lseek error %dn",pos);

return -EINVAL;

}

return file->f_pos = pos;

}

熱詞搜索:

上一篇:為系統減肥:精減Windows XP SP2系統
下一篇:Linux實時內存數據庫eXtremeDB性能

分享到: 收藏