1

「cmosram.c」デバイス ドライバーの read() および write() コールバック関数は、呼び出されるたびに 1 バイトのデータしか転送しないため、RTC ストレージの場所をすべて読み取るには 128 のシステム コールが必要です。

read() 関数と write() 関数を変更して、提供されたバッファーのスペースが保持できる限り多くの有効なバイトを転送することで、このドライバーの効率を改善できますか?

コードは次のとおりです

char modname[] = "cmosram"; // name of this kernel module
char devname[] = "cmos";    // name for the device's file
int my_major = 70;      // major ID-number for driver
int cmos_size = 128;    // total bytes of cmos memory
int write_max = 9;      // largest 'writable' address

ssize_t my_read( struct file *file, char *buf, size_t len, loff_t *pos )
{
    unsigned char   datum;

    if ( *pos >= cmos_size ) return 0;

    outb( *pos, 0x70 );  datum = inb( 0x71 );

    if ( put_user( datum, buf ) ) return -EFAULT;

    *pos += 1;
    return  1;
}

ssize_t my_write( struct file *file, const char *buf, size_t len, loff_t *pos )
{
    unsigned char   datum;

    if ( *pos >= cmos_size ) return 0;

    if ( *pos > write_max ) return -EPERM;

    if ( get_user( datum, buf ) ) return -EFAULT;

    outb( *pos, 0x70 );  outb( datum, 0x71 );

    *pos += 1;
    return  1;
}

loff_t my_llseek( struct file *file, loff_t pos, int whence )
{
    loff_t  newpos = -1;

    switch ( whence )
        {
        case 0: newpos = pos; break;            // SEEK_SET
        case 1: newpos = file->f_pos + pos; break;  // SEEK_CUR
        case 2: newpos = cmos_size + pos; break;    // SEEK_END
        }

    if (( newpos < 0 )||( newpos > cmos_size )) return -EINVAL;

    file->f_pos = newpos;
    return  newpos;
}


struct file_operations my_fops = {
                owner:  THIS_MODULE,
                llseek: my_llseek,
                write:  my_write,
                read:   my_read,
                };

static int __init my_init( void )
{
    printk( "<1>\nInstalling \'%s\' module ", devname );
    printk( "(major=%d) \n", my_major );
    return  register_chrdev( my_major, devname, &my_fops );
}

static void __exit my_exit(void )
{
    unregister_chrdev( my_major, devname );
    printk( "<1>Removing \'%s\' module\n", devname );
}

module_init( my_init );
module_exit( my_exit );
MODULE_LICENSE("GPL"); 
4

2 に答える 2

2

lenパラメータと loop inb/をそれぞれ使用して、指定outbされたバッファに収まる最大バイト数を読み書きする必要があります。次にreturn len、(読み取りバイト数!) の代わりにreturn 1.

そのCMOSの読み方をよく知っているはずなので、サンプルコードは提供しません。

于 2010-02-13T13:06:42.890 に答える
0

ループ内で実行できますget_userが、関数の 128 回の呼び出しはおそらく非常に効率的ではありません。次のアプローチを使用すると、すべてを 1 つのショットで実行できます。

まずcopy_from_user、カーネル側のバッファに buf を入れる必要があります。事前にバッファーのサイズがわからないので、k/vmalloc する必要があります (編集: データが 128 バイト以下であるため、メモリ割り当てをスキップできます。スタックにローカル バッファーがある可能性があります)。

u8 * kernel_buf;

kernel_buf = kmalloc(len, GFP_KERNEL);
if(!kernel_buf)
   return -ENOMEM;
.
.
kfree(kernel_buf); // no memory leaks please

また、ユーザー空間バッファーからバイトを読み書きできることを確認してlenから、割り当てたばかりのカーネル側バッファーとの間でコピーできることを確認する必要があります。

if(!access_ok(VERIFY_WRITE, buf, len))
{
   kfree(kernel_buf);
   return -EFAULT;
}

if(copy_from_user(kernel_buf, buf, len))
   return -EFAULT;

// now do your business in a for loop
for(i = 0; i < len; i++)
{
   outb(*pos + i, 0x70);
   outb(kernel_buf[i], 0x71),
}

// cleanup kernel buf
kfree(kernel_buf);

return len;

私がコンパイルしたりテストしたりしていないので、明らかに私の提案を再確認する必要がありますが、rhis が役立つことを願っています。

頑張って楽しんでね!

于 2010-02-13T14:06:14.933 に答える