この章では、Linuxに実装されている、デバイスドライバが使用するカーネル内のサービスルーチンおよびマクロについて解説します。
宣言 |
#include <linux/sched.h> asmlinkage void schedule(void); |
---|---|
機能 | プロセスの再スケジューリングを行います。OSは、現在のプロセス・コントロール・リストより優先度が最も高いプロセスを選択し、そのプロセスに制御を渡します(実行可能状態にします)。この関数を呼んだプロセス以外に制御が渡った場合、コールしたプロセスは「スリープ状態」に遷移します。 |
宣言 |
#include <linux/sched.h> void sleep_on(struct wait_queue **p); void interruptible_sleep_on(struct wait_queue **p); |
---|---|
機能 |
当該プロセスを「スリープ状態」に遷移させます。すなわち、他のプロセスに制御を譲ります。この関数は、割込み禁止状態で発行しなければなりません。 スリープ状態のプロセスは、ドライバ内のsleep_on()を発行した次のステップに進まなくなります。永久に進まない場合そのプロセスは、俗に言う「お亡くなりになった」状態になりますが、これを避けるのが後述のwake_up()です。ドライバでsleep_on()を発行するのは、一般的にハードウェアにI/O命令を出して、そのI/O完了を待っているときです。 DOSのようなシングルタスクのOSの場合は、ここでfor()ループなどで完了を待つのですが、LinuxのようなマルチタスクのOSでこれをやると、他のプロセスに制御が回らなくなり、システム全体が重くなってしまうので、これを避けるためにsleep_on()を使用します。 sleep_on()とinterruptible_sleep_on()の使い分けが、良く分かっていなかったりします(^_^);。interruptible_sleep_on()は、「上位プロセスで SIGINT などを発行してシステムコールを中断できるようにする」のではないかと推測していますが、どうでしょう。誰か知ってたら教えてください。 |
宣言 |
#include <linux/sched.h> void wake_up(struct wait_queue **q); |
---|---|
機能 | 「スリープ状態」(I/Oウェイト中)のプロセスを、「実行可能状態」に遷移させます。スリープ中のプロセスのコンテキストは、引数で識別されます。指定したプロセスがスリープ状態でなければ、なにもしません。 |
宣言 |
#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' に制御が移ります。 |
宣言 |
#include <linux/timer.h> int del_timer(struct timer_list * timer); |
---|---|
機能 | カーネルのタイマーリストからイベントを削除します。タイムアウトして 'function' が呼ばれた後は、実行する必要はありません。 |
宣言 |
#include <asm/delay.h> __inline__ void udelay(unsigned long usecs); |
---|---|
機能 | 1ミリ秒以下の非常に短時間の遅延をしたい場合に使用します。当該マクロを発行しても、スケジューリングは行われません。 |
宣言 |
#include <linux/mm.h> int verify_area(int type, const void * addr, unsigned long size); |
---|---|
機能 | ユーザ領域(ユーザから渡された引数)の妥当性(整合性および権限)を検査します。戻り値≦0の場合、ユーザ領域は使用不可(上位の引数誤り)です。なお、ioctl()システムコールの第3引数(intまたは 任意のポインタ)がポインタの場合、そのポインタは連続したメモリ領域の先頭を指している必要があります。つまり、その引数が構造体などのポインタであり、そのメンバがさらにポインタである場合は、メモリ空間が異なるため、ドライバ側ではその実体にはアクセスすることができません。 |
宣言 |
#include <linux/asm-i386/segment.h> void memcpy_fromfs(void *to, void *from, int size); |
---|---|
機能 |
ユーザ領域からカーネル領域へのメモリコピーを行います。 ※システムコールの引数にポインタが指定された場合、カーネル側(ドライバ)にポインタが渡されますが、ユーザAPとカーネルではメモリ空間が異なるため、ドライバ側ではポインタが指している領域に直接にはアクセスできません。その場合当該関数を使用して、ポインタが指している実体を、カーネル側で用意した内部バッファにコピーしてからアクセスしてやる操作が必要となります。 |
宣言 |
#include <linux/asm-i386/segment.h> void memcpy_tofs(void *to, void *from, int size); |
---|---|
機能 | カーネル領域からユーザ領域へのメモリコピー。memcpy_fromfs()を参照のこと。 |
宣言 |
#include <asm/string.h> inline int memcmp(const void * cs,const void * ct,size_t count) |
---|---|
機能 | memcmp(3) ライブラリ関数と同様です。カーネル空間内の変数を比較します。 |
宣言 |
#include <linux/malloc.h> void *kmalloc(int size, int priority); |
---|---|
機能 | malloc(3) ライブラリ関数と同様です。カーネル空間内のヒープを取得します。 |
宣言 |
#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で確認できます。 |
宣言 |
#include <linux/sched.h> void free_irq(unsigned int irq); /* arch/i386/kernel/irq.c */ |
---|---|
機能 | 使用していたIRQを解放します。 |
宣言 |
#include <asm/dma.h>
int request_dma( unsigned int dmanr, /* DMA番号 */ char * device_id); /* デバイス名 */ |
---|---|
機能 | DMAチャネルを予約します。使用状況は /proc/dmaで確認できます。 |
宣言 |
#include <linux/sched.h> free_dma(unsigned int dmanr); |
---|---|
機能 | 使用中のDMAを解放します。 |
宣言 |
#include <linux/ioport.h> int request_region( unsigned int from, /* 開始I/Oアドレス */ unsigned int extent, /* 使用バイト数 */ const char * device_id); /* デバイス名 */ |
---|---|
機能 | I/Oポートアドレスを予約します。使用状況は /proc/ioportsで確認できます。 |
宣言 |
#include <linux/ioport.h> int release_region( unsigned int from, /* 開始I/Oアドレス */ unsigned int extent); /* 使用バイト数 */ |
---|---|
機能 | 使用中のI/Oポートを解放します。 |
宣言 |
#include <linux/ioport.h> int check_region( unsigned int from, /* 開始I/Oアドレス */ unsigned int extent); /* 使用バイト数 */ |
---|---|
機能 | I/Oポートが使用されているかどうかを検査します。 |
宣言 |
#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)
static __inline__ void clear_dma_ff(unsigned int dmanr) コーディング・サンプル
clear_dma_ff(DMA);★この処理は、割り込み不可の状態で行なうこと!
static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
static __inline__ int get_dma_residue(unsigned int dmanr)
|
宣言 |
#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 構造体の各エントリは、アプリケーションが対応するシステムコールをコールした際の対応ハンドラとなります。 |
宣言 |
#include <linux/kernal.h> asmlinkage int printk(const char *fmt, ...); /* printk.c */ |
---|---|
機能 | printf(3) のサブセットのようなものです。出力は起動時ならコンソールに表示され、起動後は syslogdデーモンを介して /var/log/syslogなどに書き込まれます。 |
宣言 |
#include <linux/sched.h> int send_sig(unsigned long sig,struct task_struct * p,int priv) /* exit.c */ |
---|---|
機能 |
宣言 |
#include <linux/sched.h> void notify_parent(struct task_struct * tsk) /* exit.c */ |
---|---|
機能 | 自分自身が死んだことを親プロセスに知らせます。 |
宣言 |
#include <asm/io.h> void outb(unsigned char value, unsigned address); |
---|---|
機能 |
宣言 |
#include <asm/io.h> void inb(unsigned address); |
---|---|
機能 |