現在のプログラムを変更する前に、これを保存しておく。
今までに作成したデバイスドライバのデバイスノードではマイナー番号を0にし
ていた。
デバイスドライバとデバイスノードの関連付けはメジャー番号によっておこなわ
れるので、マイナー番号には任意の値を指定することができる。
この任意に指定できるマイナー番号の値をシステムコールされるメソッドの中で
確認できれば、そのマイナー番号でプログラムを分岐させることによって処理を
分けることができる。
今回はオープンするデバイスノードのマイナー番号に応じて、バイト単位かビッ
ト単位かを区別して処理できるようにする。
その区別のために、新しいデバイスノードを追加することにする。
スペシャルファイル名とマイナー番号を変更して、つぎのようにデバイスノード
を二つ作ることにする。
なお、バイト単位の操作が行なうデバイスノードのスペシャルファイル名を
pci2726byteとし、ビット単位の操作を行なうデバイスノードのスペシャルファ
イル名をpci2726bitとする。
生成したデバイスノードの情報を次のように確認してみる。
(日付と時刻は変る。)
# ls -l /dev/pci2726byte crw-r--r-- 1 root root 254, 0 Nov 1 15:30 /dev/pci2726byte |
# ls -l /dev/pci2726bit crw-r--r-- 1 root root 254, 1 Nov 1 15:35 /dev/pci2726bit |
これで、メジャー番号254マイナー番号0のデバイスノードとメジャー番号254マ
イナー番号1のデバイスノードが作成できた。
ドライバー内でマイナー番号を取り出す処理は次のようになる。
このマクロ(MINOR)を使用することで、inode構造体に含まれるマイナー番号のデー タを取得する。
dio_readやdio_writeのメソッドにはinode構造体を直接渡すことはできないが、 、file構造体中にinode構造体へのポインタが含まれているため、下記のように することでdio_readやdio_write中でもマイナー番号を取得することが可能に なる。
このマイナー(minor)番号を条件とするswitch文により、
/dev/pci2726byteを使用する場合と/dev/pci2726bitを使用する場合に分岐させる
ことができる。/dev/pci2726byteを使用する場合はバイト単位の入出力を行い、
/dev/pci2726bitを使用する場合にはビット単位の入出力を行えるようにド
ライバのreadシステムコールとwriteシステムコールのメソッドを変更する。
現在のプログラムを変更する前に、実験の失敗に備えて、これを保存しておく。
ドライバのdio_read
関数を次のように変更する。
ssize_t dio_read(struct file *filp, char *buff, size_t count, loff_t *offp) { int i, minor; unsigned char bdata[32]; unsigned long uldata; PDIO_RESOURCE pdio_res; printk("[dio_read] ga Yobareta.\n"); if (filp->private_data == NULL) return -ENODEV; pdio_res = (PDIO_RESOURCE)filp->private_data; minor = MINOR(filp->f_dentry->d_inode->i_rdev); if (count < 0) return -EINVAL; switch (minor) { case 0: if (count > 4) count = 4; for (i = 0; i < count; i++) bdata[i] = inb(pdio_res->io_address[0] + i); break; case 1: if (count > 32) count = 32; uldata = inl(pdio_res->io_address[0]); for (i = 0; i < count; i++) bdata[i] = (uldata >> i) & 0x01; break; default: return -ENODEV; } if (copy_to_user(buff, bdata, count)) return -EFAULT; return count; }
ドラバのdio_write
関数も次のように変更する。
ssize_t dio_write(struct file *filp, const char *buff, size_t count, loff_t *offp) { int i, minor; unsigned char bdata[32]; unsigned long uldata; PDIO_RESOURCE pdio_res; printk("dio_write was called.\n"); if (filp->private_data == NULL) return -ENODEV; pdio_res = (PDIO_RESOURCE)filp->private_data; minor = MINOR(filp->f_dentry->d_inode->i_rdev); if (count < 0) return -EINVAL; switch (minor) { case 0: if (count > 4) count = 4; if (copy_from_user(bdata, buff, count)) return -EFAULT; for (i = 0; i < count; i++) outb(bdata[i], pdio_res->io_address[0] + i); break; case 1: if (count > 32) count = 32; if (copy_from_user(bdata, buff, count)) return -EFAULT; uldata = 0; for (i = 0; i < count; i++) uldata |= (bdata[i] & 0x01) << i; outl(uldata, pdio_res->io_address[0]); break; default: return -ENODEV; } return count; }
書き直したドライバ・ソースを次のようにコンパイルする。
# make clean # make