|
カーネル関連 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(¶sw_read_wait); } // ワークキューの定義 DECLARE_WORK(parasw_bh_wq, parasw_bh, NULL); // ワークキューのスケジュール schedule_work(¶sw_bh_wq); モジュールパラメータモジュールパラメータは module_param()マクロで定義する。 module_param(io,int,0644); module_param(irq,int,0644); module_param(parasw_buf,ulong,444); リンク
関連 |