2010-02-13 140 views
1

我们的'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"); 
+0

这是家庭作业(请看这里:http://www.cs.usfca.edu/~cruse/cs635/lesson04.ppt),所以我把它标记为这样。 – caf 2010-02-15 02:32:46

回答

2

应该使用len参数和循环inb/outb分别读/写装配到给定的缓冲区的最大字节数。然后return len(读取字节数!)而不是return 1

我不会给你示例代码,因为你应该更清楚如何阅读CMOS的东西。

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帮助。

祝你好运,玩得开心!