2

初心者としてデバイスドライバーを試しているので、2 つの質問があります。

  1. 私は 1 つのモジュールを作成し、それをロードしました。動的にメジャー番号 251 を取得しました。マイナー デバイスの数は 1 のみ、つまりマイナー番号 0 のままです。テスト用に、デバイス ファイル (mknod を使用して作成) で echo と cat を試したところ、期待どおりに動作しました。モジュールをアンロードしても /dev エントリを削除せず、同じメジャー番号でモジュールを再度ロードし、以前に使用されたのと同じデバイス ファイルに書き込み/読み取りを試みると、カーネルがクラッシュします。これを行うべきではないことはわかっていますが、このクラッシュを引き起こすこのシナリオで何が起こるかを理解したいだけです。VFSが行うことだと思います。

  2. デバイスファイルで cat を実行すると、読み取りが無期限に発生し続けます。なぜ?それを止めるには、オフセット操作を使用する必要がありました。これは、バッファの長さがデフォルトで 32768 になっているためと思われますか?

編集: さらに、以下のように ioctl 関数を 1 つ追加すると、ioctl が定義されていない場合にうまく機能する init および cleanup 関数のストレージ クラスに関するエラーが発生します。ioctl と init/cleanup 関数のストレージ クラスの間のリンクを取得できません。更新されたコードが掲載されています。エラーは以下のとおりです。

    /home/diwakar/Documents/my_modules/first_test_module/flowTest.c:95:12: error: invalid storage class for function ‘flow_init’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_init’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:98:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_ioctl’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:112:13: error: invalid storage class for function ‘flow_terminate’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: error: invalid storage class for function ‘__inittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: invalid storage class for function ‘__exittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: expected declaration or statement at end of input
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: At top level:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:73:13: warning: ‘flow_ioctl’ defined but not used [-Wunused-function]

以下はコードです:

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/ioctl.h>

#define SUCCESS 0
#define BUF_LEN 80

#define FLOWTEST_MAGIC 'f'
#define FLOW_QUERY _IOR(FLOWTEST_MAGIC,1,int)

MODULE_LICENSE("GPL");
int minor_num=0,i;
int num_devices=1;
int fopen=0,counter=0,ioctl_test;

static struct cdev ms_flow_cd;
static char c;

///// Open , close and rest of the things

static int flow_open(struct inode *f_inode, struct file *f_file)
{
printk(KERN_ALERT "flowtest device: OPEN\n");
return SUCCESS;
}

static ssize_t flow_read(struct file *f_file, char __user *buf, size_t
  len, loff_t *off)
{
  printk(KERN_INFO "flowtest Driver: READ()\nlength len=%d, Offset = %d\n",len,*off);

/* Check to avoid the infinitely printing on screen. Return 1 on first read, and 0 on subsequent read */
if(*off==1)
return 0;

printk(KERN_INFO "Copying...\n");
copy_to_user(buf,&c,1);
printk(KERN_INFO "Copied : %s\n",buf);

*off = *off+1;
return 1;       // Return 1 on first read 


}

 static ssize_t flow_write(struct file *f_file, const char __user *buf,
  size_t len, loff_t *off)
{
  printk(KERN_INFO "flowtest Driver: WRITE()\n");
 if (copy_from_user(&c,buf+len-2,1) != 0)
  return -EFAULT;
 else
 {
 printk(KERN_INFO "Length len = %d\n\nLast character written  is  - %c\n",len,*(buf+len-2));
 return len;
}
}

static int flow_close(struct inode *i, struct file *f)
{
  printk(KERN_INFO "ms_tty Device: CLOSE()\n");
  return 0;
}

///* ioctl commands *///

static long flow_ioctl (struct file *filp,unsigned int cmd, unsigned long arg)
{
    switch(cmd) {
        case FLOW_QUERY:
            ioctl_test=51;
            return ioctl_test;
        default: 
            return -ENOTTY; 
} 
///////////////////File operations structure below/////////////////////////

struct file_operations flow_fops = {
         .owner =    THIS_MODULE,
         .llseek =   NULL,
         .read =     flow_read,
         .write =    flow_write,
         .unlocked_ioctl =   flow_ioctl,
         .open =     flow_open,
         .release =  flow_close
 };


static int flow_init(void)
    {
    printk(KERN_ALERT "Here with flowTest module ... loading...\n");
 int result=0;
 dev_t dev=0;
result = alloc_chrdev_region(&dev, minor_num, 
num_devices,"mod_flowtest");                              // allocate major number dynamically.

i=MAJOR(dev);
printk(KERN_ALERT "Major allocated = %d",i);

cdev_init(&ms_flow_cd,&flow_fops);
cdev_add(&ms_flow_cd,dev,1);

return 0;
    }

static void flow_terminate(void)
    {
    dev_t devno=MKDEV(i,0);         // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
    printk(KERN_ALERT "Going out... exiting...\n");
    unregister_chrdev_region(devno,num_devices);        //remove entry from the /proc/devices
    }

module_init(flow_init);
module_exit(flow_terminate);
4

2 に答える 2

3

cdev_del()1-クリーンアップ機能がありません。つまり、デバイスは登録されたままですが、それを処理する関数がアンロードされるため、クラッシュします。また、cdev_add はおそらく次のロードで失敗しますが、戻り値をチェックしていないためわかりません。

2- 問題ないように見えます...オフセットを変更し、正しいバイト数を返し、オフセットが 1 の場合は 0 を返します。これは EOF を示します。ただし、*off >= 1 であることを確認する必要があります。

編集-読み取りハンドラー関数に渡される長さは、ユーザーランドからずっと来ますread()。ユーザーがデバイス ファイルを開いて を呼び出した場合、それはユーザーが最大32768 バイトのデータread(fd, buf, 32768);を読み込もうとしていることを意味します。その長さは、読み取りハンドラーにずっと渡されます。提供する 32768 バイトのデータがない場合は、あるものを提供し、長さを返します。ここで、ユーザー コードはそれがファイルの終わりかどうかわからないため、別の 32768 読み取りを試みます。今は本当にデータがないので、0 を返します。これはユーザー コードに EOF に達したことを伝え、停止します。

要約すると、読み取りハンドラーで何らかのデフォルト値として表示されているのは、ユーティリティcatが何かを読み取るために使用するブロック サイズです。read 関数で別の数値を表示したい場合はdd、ブロック サイズを指定できるため、代わりに を使用してみてください。

dd if=/dev/flowtest of=/dev/null bs=512 count=1

さらに、count=1 を指定しているため、これは 1 つのブロックを読み取って停止する必要があります。count=1 を省略すると、 のようcatになり、EOF まで読み取ろうとします。

于 2013-06-05T12:48:44.023 に答える
0

2 については、mknod を使用するときにモジュールを char デバイスとして開始するようにしてください。

    mknod /dev/you_device c major_number minor_number
于 2013-06-05T17:52:32.627 に答える