字符设备驱动程序
我们的“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");
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");
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您应该分别使用
len
参数和循环inb
/outb
来读取/写入适合给定缓冲区的最大字节数。然后return len
(读取的字节数!)而不是return 1
。我不会给您示例代码,因为您应该更好地了解如何读取 CMOS 内容。
You should use the
len
parameter and loopinb
/outb
respectively to read/write the maximum number of bytes that fits into the given buffer. Thenreturn len
(the number of read bytes!) instead ofreturn 1
.I won't give you example code as you should know better how to read that CMOS stuff.
您可以在循环中执行
get_user
,但该函数的 128 次调用可能不是非常高效。您可以使用以下方法一次性完成这一切。首先,您需要将 buf 复制到内核端缓冲区中。您事先不知道缓冲区的大小,因此您应该 k/vmalloc 它(编辑:您可以跳过内存分配,因为您的数据 <= 128 字节,也许堆栈上有一个本地缓冲区)
您还需要验证您可以从用户空间缓冲区读取/写入
len
字节,然后复制到/从您刚刚分配的内核端缓冲区。显然,您应该仔细检查我的建议,因为我还没有编译或测试它们,但希望有帮助。
祝你好运,玩得开心!
You could do the
get_user
in a loop, but 128 invocations of the function is probably not super efficient. You can do it all in one shot with the following approach.First of all, you need to
copy_from_user
the buf into a kernel-side buffer. You don't know the size of the buffer ahead of time, so you should k/vmalloc it (EDIT: you can skip the memory allocation since your data is <= 128 bytes, maybe have a local buffer on the stack)You also need to verify you can read/write
len
bytes from the userspace buffer, then copy to/from the kernel side buffer you just allocated.Obviously you should double-check my suggestions as I haven't compiled or tested them, but hopefully rhis helps.
Good luck and have fun!