1

The read() and write() callback functions in our ‘cmosram.c’ device-driver only transfer a single byte of data for each time called, so it takes 128 system-calls to read all of the RTC storage-locations!

Can you improve this driver’s efficiency, by modifying its read() and write() functions, so they’ll transfer as many valid bytes as the supplied buffer’s space could hold?

code is as follows

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

You should use the len parameter and loop inb/outb respectively to read/write the maximum number of bytes that fits into the given buffer. Then return len (the number of read bytes!) instead of return 1.

I won't give you example code as you should know better how to read that CMOS stuff.

于 2010-02-13T13:06:42.890 回答
0

您可以get_user在循环中执行此操作,但该函数的 128 次调用可能效率不高。您可以使用以下方法一次性完成所有操作。

首先,你需要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 回答