現在のプログラムを変更する前に、これを保存しておく。
今までに作成したデバイスドライバのデバイスノードではマイナー番号を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