カーネル関連

Linux-2.6カーネルやデバイスドライバ関連のメモ
まだメモのレベルなので間違ってるかもしれません。

linux-2.6のコンパイル

make xconfig には Qtライブラリが必要

# apt-get install libqt3-dev

linux-2.6でモジュールを操作するにはmodule-init-toolsが必要。 従来の modutils の置き換え

# apt-get install module-init-tools

configのメモ

Loadable module support  --->
  [*]   Module unloading
を有効にしないと rmmod 出来なくなる
  [ ] Preemptible Kernel
プリエンプション

linux-2.6デバイスドライバのコンパイル、ロード、アンロード

linux-2.6のデバイスドライバをコンパイルするには、カーネルをビルドしたソースツリー一式が必要となる。(2.4の時と同じ)

hello.c ソースコード

/*
 * hello.c    demo driver program for linux-2.6
 *   Ver0.1 2005-04-13 Y.Ebihara
 */

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

static int hello_init(void){
  printk(KERN_ALERT "hello, world\n");
  return 0;
}

static void hello_exit(void){
  printk(KERN_ALERT "good bye\n");
}

module_init(hello_init);
module_exit(hello_exit);

Makefile(1行のみ!!)

obj-m   := hello.o

コンパイルの実行

$ make -C ~/kernel/linux-2.6.11.7 M=`pwd` modules
make: Entering directory `/home/ebihara/kernel/linux-2.6.11.7'
  CC [M]  /home/ebihara/project/preemption/hello/hello.o
  Building modules, stage 2.
  MODPOST
  CC      /home/ebihara/project/preemption/hello/hello.mod.o
  LD [M]  /home/ebihara/project/preemption/hello/hello.ko
make: Leaving directory `/home/ebihara/kernel/linux-2.6.11.7'
-C でカーネルをビルドしたディレクトリを指定する

ロード

# insmod hello.ko

アンロード

# rmmod hello

キャラクタデバイスの登録

静的割り当て

linux-2.4の頃と同じく register_chrdev(), unregister_chrdev() でもok。

デバイス番号(メジャー、マイナー)の自動割り当て

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
                        const char *name)
  dev_t *dev              保存先 割り当て結果dev_t変数ポインタ
  unsigned int baseminor  マイナー番号の開始番号
  unsigned int count      割り当てるマイナー番号の数
  const char *name        デバイス名
void cdev_init(struct cdev *cdev, struct file_operations *fops)
  struct cdev *cdev       保存先 キャラクタデバイス構造体ポインタ
  struct file_operations *fops  ファイルオペレーションズ構造体
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
  struct cdev *p          登録するキャラクタデバイス構造体
  dev_t dev               デバイス
  unsigned count          数

を使う。以下sample

dev_t devno;
minor = 0;
devno = 0;
// キャラクターデバイス番号の動的割り当て
result = alloc_chrdev_region(&devno, minor, WAKEUPDRV_MINOR_NUMS, DEVNAME);
if(result<0){
  printk(KERN_WARNING DEVNAME ":can't get major %d\n",major);
  return result;
}

major  = MAJOR(devno);
printk(KERN_NOTICE DEVNAME ":major=%d\n",major);

// キャラクターデバイスの登録(マイナー番号の数だけ)
for(i=0; i<COUNTDRV_MINOR_NUMS; i++){
  result = countdrv_cdevs_init(&countdrv_dev[i],i);
  if(result){
    return result;
  }
}

int countdrv_cdevs_init(struct countdrv_dev *dev, int mi)
{
  int err;
  int devno;

  /*
   * MKDEV(major, minor)
   */

  devno = MKDEV(major, mi);
  cdev_init(&dev->cdev, &countdrv_fops);
  dev->cdev.owner = THIS_MODULE;
  // キャラクタデバイスの登録(*cdev, 最初のデバイス番号, 登録するデバイス数)
  err = cdev_add(&dev->cdev, devno, 1);
  if(err){
    printk(KERN_NOTICE "error %d adding chrdev %d",err,mi);
    return err;
  }

  dev->counter = 0; // カウンター変数の初期化
  return 0;
}

I/Oアドレス予約

 struct resource * request_region(start,n,name)
 失敗したらNULLが返る

プロセスの休眠、起床

interruptible_sleep_on(&q)やwake_up_interruptible(&q)はlinux-2.4と同じで変更無し。

wait_queue_head_t q;        待ち列q
init_waitqueue_head(&q);    qの初期化
interruptible_sleep_on(&q); qにつないで寝る
wake_up_interruptible(&q);  qにつながっている全プロセスを起こす

linux-2.4と変更無いがinterruptible_sleep_on()を使うのはもはや推奨されない。

wait_event_interruptible(q, 式);
// qには&を付けないこと
// 式が「成立するまで」待つ

を用いる。以下に例

 err=wait_event_interruptible(parasw_read_wait, (parasw_inp != parasw_file->readout) );
 if(err<0){
   return err;
 }
 /* シグナル(ctrl+c等)によって中断したならfs層に処理を依頼 */
 if(signal_pending(current)){
   return -ERESTARTSYS;
 }

割り込み

TopHalf

上半分はlinux-2.4とあまり変わらない。

void parasw_interrupt(int irq_no, void *dev_id, struct pt_regs *regs){
}

だったものが

irqreturn_t parasw_interrupt(int irq_no, void *dev_id, struct pt_regs *regs){
  :処理
  return IRQ_HANDLED;
}

に変更になった。

BottomHalf

下半分はlinux-2.4と同じくTaskletsを使う方法とWorkqueueを使う方法がある。Taskletsは割り込み期間で動く。Workletsはカーネル内部を走行している専用のスレッドで実行されるためsleepに入ることが許される。

#include <linux/workqueue.h>
// ワークキュー関数
static void parasw_bh(void *unused){
  wake_up_interruptible(&parasw_read_wait);
}
// ワークキューの定義
DECLARE_WORK(parasw_bh_wq, parasw_bh, NULL);
// ワークキューのスケジュール
schedule_work(&parasw_bh_wq);

モジュールパラメータ

モジュールパラメータは module_param()マクロで定義する。

module_param(io,int,0644);
module_param(irq,int,0644);
module_param(parasw_buf,ulong,444);

リンク

関連

Last-modified: 2005-08-25 (木) 20:08:56 (4168d)