2010-02-13 137 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幫助。

祝你好運,玩得開心!