Linux Device Driver Sum Up 2
Linux Device Driver Sum Up 2
1.
2. Useful Functions
Function are for doing device i/o, to/from the i/o ports
#include <asm/io.h>
char inb(int port);
char inw(int port);
char outb(char val, int port);
char outw(char val, int port);
#include <linux/malloc.h>
void *kmalloc(int size, int priority);
void kfree_s(void *obj, int size);
void kfree(void *obj);
the priority is either:
GFP_KERNEL - for normal cases
GFP_ATOMIC - for allocating mem inside interrupts
#include <linux/mm.h>
void *vmalloc(long size);
void vfree(void *obj);
#include <linux/kernel.h>
int printk(char *fmt, ...);
#include <asm/segment.h>
unsigned char get_fs_byte(const char *addr);
unsigned short get_fs_word(const short *addr);
unsigned long get_fs_long(const int *addr);
void put_fs_byte(char val, char *addr);
void put_fs_word(short val, short *addr);
void put_fs_long(long val, int *addr);
void memcpy_fromfs(void *to, void *from, unsigned long len);
void memcpy_tofs(void *to, void *from, unsigned long len);
#include <asm/system.h>
void sti();
void cli();
void save_flags(unsigned long flags);
void restore_flags(unsigned long flags);
3. Driver Basics
1 In order that the device driver is correctly initialized when the operating
system is booted, the xxx_init() routine must be executed.
2 To ensure this happens, add the following line to the end of the
chr_drv_init() function in the
/usr/src/linux/driver/char/mem.c file:
mem_start = xxx_init(mem_start);
4. Using Interrupts
need to write an interrupt service routine (ISR)
5. Kernel modules
from a source file mod.c of a kernel module, you compile it with gcc -Wall -O2
-c mod.c
Once you get the compiled mod.o, you can become root and install it to a
running kernel using insmod mod.o, and remove it from the kernel using rmmod
mod.
Most modules does not do a lot of things when being loaded. They just register
some functions to the kernel, so that when the functionalities are needed, those
functions are called
/* define functions of the module */
int init_module(void) {
register_something(...);
return 0; /* should return 0 if succeed, non-zero if failure */
}
void cleanup_module(void) {
unregister_something(...);
}
/* extra information of the module */
Before you unload the module, you must unregister its major number. This can
be done by calling the function unregister_chrdev(unsigned int major, const
char *name). Again, negative values indicate error. The only possible error is
EINVAL
6. The in-kernel file structure
/*<linux/fs.h>*/
Represents open files in the kernel
similar to a FILE* in userspace. The current position in the file is stored here.
Created by the kernel on open call. Tuc la khi chung ta goi ham
open thi kernel se tao ra 1 file structure.
When a device is opened, a file structure is allocated and filled by the kernel to
keep information like
1 current access pointer
2 associated directory entry
3 open mode
4 file operations functions
The kernel will keep this structure until all references1 to it are removed, by
process being terminated, explicitly close() the file, or used dup2() which
implicitly closed the file.
At that time the release method is called, and the kernel deallocate the file
structure.
The file structure is defined in <linux/fs.h>
1 loff_t f_pos: The current file position.
2 struct file_operations *f_op; The operations associated with the file
3 void *private_data;
If the device driver writerwants to keep some data specific for the file
structure, it will allocate a structure (using kmalloc) and put the
pointer to the structure here when the device is first opened.
The open system call sets this pointer to null before calling the open
method for the driver.
private_data is a useful resource for preserving state information
across system call
7. The file operations
/*<linux/fs.h>*/
Connects system calls with our drivers code by providing pointers
to the drivers functions.
static int foo_open(struct inode *inode, struct file *filp)
1 Called when the file is opened.
2 The function should return 0 if it decides that the file opening is valid, and
return an error code (like EPERM) otherwise, explaining why the call
failed.
3 The device number can be found in the inode passed to this function, using
inode->i_rdev.
static ssize_t foo_read(struct file *file, char * buffer, size_t count, loff_t *filp);
1 This is called when the user program tries to read from the file.
2 At most count bytes should be written to the user-provided buffer,
probably using copy_to_user or one of its variants
3 The code should increment the number *filp by the number of bytes read.
4 The return value of this function should be the number of bytes read, or 0
if it reaches the end of file, or a negative error code to indicate an error.
static ssize_t foo_write(struct file *file, char * buffer, size_t count, loff_t
*filp);
1 This is called when the user program tries to write into the file.
2 At most count bytes should be copied from the user-provided buffer,
probably using copy_from_user or one of its variants.
3 The code should increment the number *filp by the number of bytes
written.
4 The return value of this function should be the number of bytes written, or
a negative error code to indicate error.
8. Inode
/*<linux/fs.h>*/
Represents files.
Lots of fields but mostly 2 fields of interest for drivers if it is a
device file:
1 dev_t i_rdev; /*<linux/types.h>*/
2 struct cdev *i_cdev; cdev's an internal kernel stucture,
representing char devices
9. The File Systems
VFS (Virtual File System)
All file systems in Linux rely on the VFS to allow them not only to coexist, but
also to interoperate.
This enables you to use standard Unix system calls to read and write to different
file systems on different media.
The purpose of VFS is to maintain an interface between system calls concerning
files and the file management code proper
When a process performs a system call on files, it is directed at the VFS
The VFS is responsible for performing operations which are independent of
the format of the filesystem concerned
Then, the VFS redirects the request to the module managing the file
10. Timers and Time Management
Kernel notion of Time
1 Kernel can comprehend and manage time through tick rate of system timer in
hardware
2 When the system timer goes off, it issues an interrupt that the kernel handles via a
special interrupt handler
The Tick Rate: HZ (Programmable Interval Timer)
1 The tick rate is programmed on system boot based on a static preprocessor define,
HZ
2 The value of HZ differs for each supported architectures
3 The kernel defines the value in <asm/param.h>
#define HZ 1000 /* internal kernel time frequency */
4 When writing kernel code, never assume that HZ has any given value
Jiffies
1 The global variable jiffies holds the number of ticks that have occurred since the
system booted
extern unsigned long volatile jiffies; /* <linux/jiffies.h> */
on boot: jiffies = 0;
each timer interrupt: jiffies++;
2 convert forms of jiffies
second to jiffies: (second*HZ)
jiffies to second: (jiffies/HZ)
ex) unsigned long next_tick = jiffies + _1;/* one tick from now */
unsigned long later = jiffies + 5 * HZ; /* five second from now */
unsigned long timeout = jiffies + HZ/2; /* timeout in
/* … */
if (time_after(jiffies, timeout)) {
/* we did not time out, good … */
} else {
/* we time out, error … */
}
3 Internal Representation of Jiffies
The jiffies variable has 32 bit in size on 32-bit architectures and 64-bit on 64-bit
architectures
overflow: 49.7days (1000HZ / 32-bit)
4 macros for comparing tick counts:
#define time_after(unknown, known) ((long)(known) – (long)(unknown) < 0)
#define time_before(unknown, known) ((long)(unknown) – (long)(known) < 0)
#define time_after_eq(unknown, known) ((long)(unkown) – (long)(known) >=
0)
#define time_before_eq(unknown, known) ((long)(known) – (long)(unkown) >=
0)
5
Timers
1 Purpose: to delay execution of some function until a specified later time
2 Timer usage sequence:
specify an expiration time
specify a function to execute upon expiration
activate the timer
Timer is destroyed once it expires
No limit on the number of timers
3 represented by struct timer_list:
struct timer_list {
struct list_head entry; /* entry in linked list of
unsigned long expires; /* expiration value, in jif
spinlock_t lock; /* lock protecting this tim
void (*function)(unsigned long); /* the timer handler f
unsigned long data; /* lone argument to the han
struct tvec_t_base_s *base; /* internal timer fiel
};
4 Using:
12. ドライバとカーネルのインターフェース
スケジューリング関連サービス
1 schedule():プロセスの再スケジューリング
宣言:
#include <linux/sched.h>
asmlinkage void schedule(void);
機能: プロセスの再スケジューリングを行います。OSは、現在のプロ
セス・コントロール・リストより優先度が最も高いプロセスを選択し、
そのプロセスに制御を渡 します(実行可能状態にします)。この関数
を呼んだプロセス以外に制御が渡った場合、コールしたプロセスは「ス
リープ状態」に遷移します。
2 sleep_on():プロセスをスリープ状態にする
宣言:
#include <linux/sched.h>
void sleep_on(struct wait_queue **p);
void interruptible_sleep_on(struct wait_queue **p);
機能:
当該プロセスを「スリープ状態」に遷移させます。すなわち、他の
プロセスに制御を譲ります。この関数は、割込み禁止状態で発行し
なければなりません。Chuyen process vao trang thai sleed.
スリープ状態のプロセスは、ドライバ内の sleep_on()を発行した次の
ステップに進まなくなります。永久に進まない場合そのプロセスは
俗に言う 「お亡くなりになった」状態になりますが、これを避け
るのが後述の wake_up()です。ドライバで sleep_on()を発行するのは、
一般的にハー ドウェアに I/O 命令を出して、その I/O 完了を待って
いるときです。Neu lenh sleep_on() duoc phat sinh thi process cua driver
se khogn the chuyen den buoc tiep theo, thuc hien cau lenh tiep theo duoc.
Chung ta se dung lenh wake_up() de thoat khoi tinh trang sleep_on(). Thuc
chat cua lenh sleep_on() nay la phat ra cac cau lenh I/O vao hardware, va
cho*` cho den khi cac I/O nay thuc hien xong
DOS のようなシングルタスクの OS の場合は、ここで for()ループな
どで完了を待つのですが、Linux のようなマルチタスクの OS でこれ
をやると、 他のプロセスに制御が回らなくなり、システム全体が
重くなってしまうので、これを避けるために sleep_on()を使用します。
sleep_on()と interruptible_sleep_on()の使い分けが、良く分かっていな
かったりします(^_^);。 interruptible_sleep_on()は、「上位プロセス
で SIGINT などを発行してシステムコールを中断できるようにす
る」のではないかと推測していますが、どうでしょう。誰か知って
たら教えてください。
3 wake_up():プロセスを起こす
宣言:
#include <linux/sched.h>
void wake_up(struct wait_queue **q);
機能: 「スリープ状態」(I/Oウェイト中)のプロセスを、「実行可
能状態」に遷移させます。スリープ中のプロセスのコンテキストは、引
数で識別されます。指定したプロセスがスリープ状態でなければ、なに
もしません。
タイマー機能
1 add_timer():タイマー監視を開始する
宣言:
#include <linux/timer.h>
void add_timer(struct timer_list * timer);
struct timer_list {
struct timer_list *next; /* NULL のまま */
struct timer_list *prev; /* NULL のまま */
unsigned long expires; /* タイムアウト時間(10ms単位)*/
unsigned long data; /* 任意。複数のイベントを1つの
タイマーハンドラで管理する場合、この引数で認識する。*/
void (*function)(unsigned long); /* タイマーハンドラ関数。
引数として'data'が渡される。 */
};
機能: カーネルのタイマーリストに監視したいイベントを追加します。
'expires' ×10ミリ秒経過すると、関数 'function' に制御が移ります。
2 del_timer():タイマー監視を中止する
宣言:
#include <linux/timer.h>
int del_timer(struct timer_list * timer);
機能: カーネルのタイマーリストからイベントを削除します。タイムア
ウトして 'function' が呼ばれた後は、実行する必要はありません。
3 udelay():μ 秒単位の遅延
宣言:
#include <asm/delay.h>
__inline__ void udelay(unsigned long usecs);
機能: 1ミリ秒以下の非常に短時間の遅延をしたい場合に使用します。
当該マクロを発行しても、スケジューリングは行われません
メモリ操作関連
1 verify_area():ユーザ領域の妥当性検査
宣言:
#include <linux/mm.h>
int verify_area(int type, const void * addr, unsigned long size);
機能: 能 ユーザ領域(ユーザから渡された引数)の妥当性(整合性およ
び権限)を検査します。戻り値≦0の場合、ユーザ領域は使用不可(上
位の引数誤り)です。な お、ioctl()システムコールの第3引数(int また
は 任意のポインタ)がポインタの場合、そのポインタは連続したメモ
リ領域の先頭を指している必要があります。つまり、その引数が構造体
などのポインタであ り、そのメンバがさらにポインタである場合は、
メモリ空間が異なるため、ドライバ側ではその実体にはアクセスするこ
とができません。
2 memcpy_fromfs():ユーザ領域からのメモリ転送
宣言:
#include <linux/asm-i386/segment.h>
void memcpy_fromfs(void *to, void *from, int size);
機能: ユーザ領域からカーネル領域へのメモリコピーを行います。
※システムコールの引数にポインタが指定された場合、カーネル側(ド
ライバ)にポインタが渡されますが、ユーザAPとカーネルではメモリ
空間が異なるた め、ドライバ側ではポインタが指している領域に直接
にはアクセスできません。その場合当該関数を使用して、ポインタが指
している実体を、カーネル側で用意 した内部バッファにコピーしてか
らアクセスしてやる操作が必要となります。
De chuyen du lieu tu user space vao kernel space: The device driver
copies data between the kernel'ys address space and the user
program'ys address space whenever the user makes a read() or
write() system call
Several Linux routines such as, memcpy_*fs() and
put_fs*() enable device drivers to transfer data across the
usersystem boundary. Data may be transferred in bytes, words, or
in buffers of arbitrary sizes
For example, memcpy_fromfs() transfers an arbitrary
number of bytes of data from user space to the device, while
get_fs_byte() transfers a byte of data from user space.
Similarly, memcpy_tofs() and put_fs_byte() write
data to user space memory
3 memcpy_tofs():ユーザ領域へのメモリ転送
宣言:
#include <linux/asm-i386/segment.h>
void memcpy_tofs(void *to, void *from, int size);
機能: カーネル領域からユーザ領域へのメモリコピー。memcpy_fromfs()
を参照のこと。
4 memcmp():メモリ内容の比較
宣言:
#include <asm/string.h>
inline int memcmp(const void * cs,const void * ct,size_t count)
機能: memcmp(3) ライブラリ関数と同様です。カーネル空間内の変数を
比較します。
5 kmalloc():動的メモリ取得
宣言:
#include <linux/malloc.h>
void *kmalloc(int size, int priority);
機能: malloc(3) ライブラリ関数と同様です。カーネル空間内のヒープを
取得します。
リソース関連
1 request_irq():IRQの使用宣言
宣言:
#include <linux/sched.h>
#include <linux/signal.h>
int request_irq(
unsigned int irq, /* IRQ番号 */
void (*handler)(int, struct pt_regs *), /* 割り込みハンドラ */
unsigned long flags, /* フラグ(SA_INTERRUPT) */
const char *device); /* デバイス名 */
機能: IRQと割り込みハンドラをカーネルに登録します。IRQの使
用状況は /proc/interrupt で確認できます。
2 free_irq():IRQの解放
宣言:
#include <linux/sched.h>
void free_irq(unsigned int irq); /* arch/i386/kernel/irq.c */
機能: 使用していたIRQを解放します。
3 request_dma():DMAチャネルの予約
宣言:
#include <asm/dma.h> int request_dma(
unsigned int dmanr, /* DMA番号 */
char * device_id); /* デバイス名 */
機能: DMAチャネルを予約します。使用状況は /proc/dma で確認できま
す。
4 free_dma():DMAの解放
宣言:
#include <linux/sched.h>
free_dma(unsigned int dmanr);
機能:
使用中のDMAを解放します。
5 request_region():I/Oポートの予約
宣言:
#include <linux/ioport.h>
int request_region(
unsigned int from, /* 開始I/Oアドレス */
unsigned int extent, /* 使用バイト数 */
const char * device_id); /* デバイス名 */
機能: I/Oポートアドレスを予約します。使用状況は /proc/ioports で確
認できます。
6 release_region():I/Oポートの解放
宣言:
#include <linux/ioport.h>
int release_region(
unsigned int from, /* 開始I/Oアドレス */
unsigned int extent); /* 使用バイト数 */
機能: 使用中のI/Oポートを解放します。
7 check_region():I/Oポートの検査
宣言:
#include <linux/ioport.h>
int check_region(
unsigned int from, /* 開始I/Oアドレス */
unsigned int extent); /* 使用バイト数 */
機能: I/Oポートが使用されているかどうかを検査します。
8 DMAサポートマクロ群
宣言:
#include <asm/dma.h>
clear_dma_ff(DMAチャネル番号);
set_dma_mode(DMAチャネル番号, dma_mode); /* full address */
set_dma_addr(DMAチャネル番号, 先頭アドレス+転送済みバイト数);
set_dma_count(DMAチャネル番号, 転送カウント);
enable_dma(DMAチャネル番号);
機能:
能 static __inline__ void enable_dma(unsigned int dmanr)
指定のDMAチャネルを使用可能にします(単一マスク・ビットの
クリア)
static __inline__ void disable_dma(unsigned int dmanr)
指定のDMAチャネルを使用不可にします(単一マスク・ビットの
設定)
static __inline__ void clear_dma_ff(unsigned int dmanr)
'DMA Pointer Flip Flop'をクリアします。
コーディング・サンプル
clear_dma_ff(DMA);
outb(下位バイト、アドレス);
outb(上位バイト、アドレス);
clear_dma_ff(DMA);
下位バイト = inb(アドレス);
上位バイト = inb(アドレス);
この処理は、割り込み不可の状態で行なうこと!
static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
指定のDMAチャネルのモード設定を行ないます。
static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
指定のDMAチャネルに対して、転送アドレスとページビットの設
定を行ないます。DMAフリップフロップはクリアされているもの
と見なしています。
static __inline__ void set_dma_count(unsigned int dmanr, unsigned int
count)
指定のDMAチャネルに対して、転送サイズの設定(DMA1−3
は最大64K、DMA5−7は最大128K)を行ないます。注
意:1を引く、またはワード転送の場合2で割る、などの計算は内
部で行っています。
static __inline__ int get_dma_residue(unsigned int dmanr)
DMAの転送残りカウントを取得します。
その他
1 register_chrdev():ハンドラの登録
宣言:
#include <linux/fs.h>
int register_chrdev( /* linux/fs/devices.c */
unsigned int major, /* デバイスメジャー番号 */
const char * name, /* 内部デバイス名 */
struct file_operations *fops) /* ファイル操作構造体 */
struct file_operations { /* ファイル操作関数群管理構造体 */
int (*lseek) (struct inode *, struct file *, off_t, int);
int (*read) (struct inode *, struct file *, char *, int);
int (*write) (struct inode *, struct file *, char *, int);
int (*readdir) (struct inode *, struct file *, struct dirent *, int);
int (*select) (struct inode *, struct file *, int, select_table *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct inode *, struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
void (*release) (struct inode *, struct file *);
int (*fsync) (struct inode *, struct file *);
int (*fasync) (struct inode *, struct file *, int);
int (*check_media_change) (dev_t dev);
int (*revalidate) (dev_t dev);
};
機能: 仮想ファイルシステムにキャラクタ・デバイスとして登録します。
この後、割り込みハンドラ(ボトム・ハーフ・ルーチン)が有効になり
ます。
file_operations 構造体の各エントリは、アプリケーションが対応するシス
テムコールをコールした際の対応ハンドラとなります。
2 printk():カーネル用 printf()
宣言:
#include <linux/kernal.h>
asmlinkage int printk(const char *fmt, ...); /* printk.c */
機能: printf(3) のサブセットのようなものです。出力は起動時ならコン
ソールに表示され、起動後は syslogd デーモンを介して /var/log/syslog な
どに書き込まれます。
3 send_sig():自分自身(のプロセス)にシグナルを送る
宣言:
#include <linux/sched.h>
int send_sig(unsigned long sig,struct task_struct * p,int priv) /* exit.c */
機能:
4 notify_parent():親プロセスに知らせる
宣言:
#include <linux/sched.h>
void notify_parent(struct task_struct * tsk) /* exit.c */
機能: 自分自身が死んだことを親プロセスに知らせます。
5 outb():ポートへの1バイト出力
宣言:
#include <asm/io.h>
void outb(unsigned char value, unsigned address);
機能
6 inb():ポートからの1バイト入力
宣言:
#include <asm/io.h>
void inb(unsigned address)
機能:
13. ドライバと上位APとのインターフェース
file_operations 構造体: ドライバ内部の file_operations 構造体(register_chrdev() 参
照)は以下のように定義されています。この例を使って説明していきます。筆者
が使っていない引数などは、当然解説不能です(^_^);
全てのファイルシステムに全ての関数が定義されているわけではない.
する「ローダブル方式」があります。
16. アプリケーションがデバイスのデータを読み取る処理の流れ
Tu application su dung system call (la interface giua application va OS) de nham muc dich
truy xuat vao device. Chung ta co cac system call o application nhu sau:
1 open ファイルを開ける
2 close 閉じる
3 read ファイルからデータを読む.
4 write ファイルにデータを書き込む.
5 ioctl デバイスの属性を変更したり,制御したりするのに使用する.例えば,
通信ポートのスピードを変更するなど.
これらはアプリケーションが利用する関数群である
chung ta khong the nhin thay device, ma chung ta chi co the nhin thay device gia tuong
thong qua 1 loai file dac biet「/dev/xxx」
khi ma tu application access vao device thi kernel se su dung number duoc dinh nghia
cho device, tim kiem bang device driver table thogn qua major number. Major number
dung de phan biet cac device khac loai voi nhau. Ngoai ra con 1 tham so nua la minor
number. Khi muon phan biet cac thiet bi co cung major number hay noi cach khac la
cung loai thiet bi thi ta dung minor number. Minor number duoc ghi vao device special
file(inode) tuy nhien khi kernel goi device driver thi tham so minor number se duoc giao
cho thiet bi. Ve phai device thi minor number thuc chat la so thu tu cua port ma device
duoc gan vao.
アプリケーションがデバイスのデータを読み取る処理の流れ: デバイスドライバは以下の
3つの部分から構成されます。
vao device special file. Gom co 3 thong so: major number, device name, function table
In order that the device driver is correctly initialized when the
operating system is booted, the xxx_init() routine must be
executed.
To ensure this happens, add the following line to the end of the
chr_drv_init() function in the
/usr/src/linux/driver/char/mem.c file:
mem_start = xxx_init(mem_start); and resave the file back to
disk.
Chu y cac ham sau:
Read: デ バ イ ス か ら デ ー タ を 取 り 出 す た め に 使 用 し ま す 。 通 常 は 、
copy_to_user を使用してカーネル領域からユーザー領域にデータを転送
します。処理が成功した場合には読み出したバイト数を戻り値として返しま
す。
Write: デ ー タ を デ バ イ ス に 送 る た め に 使 用 し ま す 。 通 常 は 、
copy_from_user を使用してユーザー領域からカーネル領域にデータを転
送します。処理が成功した場合、書き込んだバイト数を戻り値として返しま
す。
2 Top Half:
Tuong ung voi cac system call o application chang han nhu system call open(); read();
thi kernel se goi cac function tuong ung xxx_open(); xxx_read();
3 Bottom Half:
Thong qua interrupt o hardware se khoi dong^ cac handler()
Thuc chat o day chinh la sudung clock phan cung「interrupible_sleep_on()」
4 Vi du:
例えば、read()メソッドにより、外部のハードウエアから情報を読み取る場合、アプリケーショ
ンは標準 API をコールします。これを受けて、システムコールライブラリの read()メソッドが
i/o デバイスは、要求されたデータをデータ読み出しのためのレジスタ、あるいはメモリ空間
にセットし、準備が完了すると割り込みにより、カーネルへ通知を行います。
のレジスタをアクセスして、データを取得します。同期転送の場合、 read()メソッドの中では、
処理の終了を待つ「interrupible_sleep_on()」がコールされています。この場合は、このボトム
ハーフルーチンの終了を受けて、カーネルが待ちの解除を行います。
17. カーネルへの割り込みハンドラ
前述のように、i/o デバイスが動作を完了して、その終了をカーネルに通知するためには、
割り込みが使用されます。 Khi ma device ket thuc qua trinh xuly tin hieu, nham muc
dich thong bao cho kernel biet thi no phai su dung ngat
この割り込みを受けて、デバイスドライバのトップハーフルーチンを起動するために、割り
込みハンドラの登録を行う必要があります。Vi trong phan bottom half thi chung ta co su
dung cau lenh 「interrupible_sleep_on()」tuc la se dung lai khogn hoat dong^, nham doi*
cho viec ghi/ doc du lieu ra phancung ket thuc. Khi viec ghi/doc nay ket thuc thi se
xuat hien ngat, ngat nay se phai lam nhiem vu wake_up_interruptible de cho
ham bottom half xu ly tiep. Do vay chung ta phai dang ky
ngat int request_irq o application va o kernel thi chung ta phai lam la
xxx_interrupt(int irq)
登録には標準の API が用意されています。割り込みハンドラへのポインタ引数には、デバイスドライバの
トップハーフルーチンを設定します。
18. カーネルへのデバイスドライバの組み込み
デバイスドライバを組み込んで使用する方法として、 Linux では2通りの方法が提供され
ています。Chung ta co 2 cach de co the dang ky device driver voi kernel
1つは、デバイスドライバを、カーネルにスタティックリンクしてしまう方法です。Cach thu
しないドライバモジュールは、メモリへ常駐させる必要が無いため、最小限のメモリでシステムを動作させ
ることが可能になります。
19.