next up previous
次へ: ドライバの格納 上へ: デバイスドライバの拡張 戻る: デバイスドライバの拡張

デバイスノードによる処理の分岐

現在のプログラムを変更する前に、これを保存しておく。


\begin{boxedminipage}{5cm}
\begin{verbatim}...

今までに作成したデバイスドライバのデバイスノードではマイナー番号を0にし ていた。
デバイスドライバとデバイスノードの関連付けはメジャー番号によっておこなわ れるので、マイナー番号には任意の値を指定することができる。
この任意に指定できるマイナー番号の値をシステムコールされるメソッドの中で 確認できれば、そのマイナー番号でプログラムを分岐させることによって処理を 分けることができる。 今回はオープンするデバイスノードのマイナー番号に応じて、バイト単位かビッ ト単位かを区別して処理できるようにする。

その区別のために、新しいデバイスノードを追加することにする。
スペシャルファイル名とマイナー番号を変更して、つぎのようにデバイスノード を二つ作ることにする。
なお、バイト単位の操作が行なうデバイスノードのスペシャルファイル名を pci2726byteとし、ビット単位の操作を行なうデバイスノードのスペシャルファ イル名をpci2726bitとする。


\begin{boxedminipage}{\textwidth}
\begin{verbatim}...

生成したデバイスノードの情報を次のように確認してみる。 (日付と時刻は変る。)

  # 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のデバイスノードが作成できた。

ドライバー内でマイナー番号を取り出す処理は次のようになる。


\begin{boxedminipage}{\textwidth}
\begin{verbatim}minor = MINOR(inode->i_rdev);\end{verbatim}
\end{boxedminipage}

このマクロ(MINOR)を使用することで、inode構造体に含まれるマイナー番号のデー タを取得する。

dio_readやdio_writeのメソッドにはinode構造体を直接渡すことはできないが、 、file構造体中にinode構造体へのポインタが含まれているため、下記のように することでdio_readやdio_write中でもマイナー番号を取得することが可能に なる。


\begin{boxedminipage}{\textwidth}
\begin{verbatim}minor = MINOR(filp->f_dentry->inode->i_rdev);\end{verbatim}
\end{boxedminipage}

このマイナー(minor)番号を条件とするswitch文により、 /dev/pci2726byteを使用する場合と/dev/pci2726bitを使用する場合に分岐させる ことができる。/dev/pci2726byteを使用する場合はバイト単位の入出力を行い、 /dev/pci2726bitを使用する場合にはビット単位の入出力を行えるようにド ライバのreadシステムコールとwriteシステムコールのメソッドを変更する。

現在のプログラムを変更する前に、実験の失敗に備えて、これを保存しておく。


\begin{boxedminipage}{5cm}
\begin{verbatim}...

ドライバの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



MANOME Yoichi 平成18年12月26日