角色设备驱动程序

时间:2010-02-13 12:50:05

标签: linux-kernel device-driver hardware-port

我们的'cmosram.c'设备驱动程序中的read()和write()回调函数每次调用时只传输一个字节的数据,因此需要128个系统调用来读取所有RTC存储 - 位置!

你可以通过修改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"); 

2 个答案:

答案 0 :(得分:2)

您应该分别使用len参数并循环inb / outb来读取/写入适合给定缓冲区的最大字节数。然后return len(读取的字节数!)而不是return 1

我不会给你示例代码,因为你应该更好地了解如何读取CMOS内容。

答案 1 :(得分:0)

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

首先,您需要将copy_from_user buf放入内核端缓冲区。你不知道提前缓冲区的大小,所以你应该k / vmalloc它(编辑:你可以跳过内存分配,因为你的数据是&lt; = 128字节,可能在堆栈上有一个本地缓冲区)< / p>

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;

显然你应该仔细检查我的建议,因为我没有编译或测试它们,但希望这有帮助。

祝你好运,玩得开心!