一般在linux下设备分为字符设备和块设备。
字符设备是指设备发送和接收数据以字符的形式进行;而块设备则以整个数据缓冲区的形式进行。
在linux下对任何的操作可以看成是对设备的操作。简单而言之,可以是看成对设备文件的读写操作。
那么,怎样对linux 的设备文件进行读写呢?我们通过一段小程序来模拟linux下对字符设备文件的读写操作。
程序如下(本程序基于linux2.6内核):
1.定义自己的设备文件驱动
// my_driver.c
MODULE_LICENSE("GPL");
// 定义自己的操作类型
struct file_operations my_driver_fops =
{
read:
my_driver_read,
write:
my_driver_write,
};
static int my_ver = 0;
static struct semaphore sem;
static wait_queue_head_t outq;
static int flag = 0;
// 初始化文件设备
static int __init my_driver_init(void)
{
int ret;
ret = register_chrdev(MAJOR_NUM, "my_driver", &my_driver_fops);
if (ret) {
printk("my_driver register failure/n");
} else {
printk("my_driver register success/n");
init_MUTEX(&sem);
init_waitqueue_head(&outq);
}
return ret;
}
// 退出设备操作
static void __exit my_driver_exit(void)
{
int ret;
ret = unregister_chrdev(MAJOR_NUM, "my_driver");
if (ret)
printk("my_driver unregister failure/n");
else
printk("my_driver unregister success/n");
}
// 读取设备文件
static ssize_t my_driver_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
if (wait_event_interruptible(outq, flag != 0))
return - ERESTARTSYS;
if(down_interruptible(&sem))
return - ERESTARTSYS;
flag = 0;
if (copy_to_user(buf, &my_ver, sizeof(int))) {
up(&sem);
return - EFAULT;
}
up(&sem);
return sizeof(int);
}
// 写设备文件
static ssize_t my_driver_write(struct file *filp, const char *buf, size_t len,loff_t *off)
{
if (down_interruptible(&sem))
return - ERESTARTSYS;
if (copy_from_user(&my_ver, buf, sizeof(int))) {
up(&sem);
return - EFAULT;
}
up(&sem);
flag = 1;
wake_up_interruptible(&outq);
return sizeof(int);
}
// 自定义模块的加载与卸载
module_init(my_driver_init);
module_exit(my_driver_exit);
在这个驱动里my_driver_read、my_driver_write这两个函数分别实现内核空间与用户空间的数据交换,module_init(my_driver_init)、module_exit(my_driver_exit)用于模块的加载与卸载。
2.测试程序,为了验证我们的驱动是否正确我们编写了以下测试程序。
// my_read.c
int main(void)
{
int fd, num;
fd = open("/dev/my_driver",O_RDWR,S_IRUSR | S_IWUSR);
if(fd != -1) {
while(1) {
read(fd,&num,sizeof(int));
printf("the my_driver is %d/n",num);
if(0 == num) {
close(fd);
break;
}
}
} else{
printf("device open failure/n");
}
return 0;
}
读取设备文件数据。读取设备文件了my_var的内容。
// my_write.c
int main(void)
{
int fd, num;
fd = open("/dev/my_driver",O_RDWR,S_IRUSR | S_IWUSR);
if(fd != -1) {
while(1) {
printf("please input the my_driver!/n");
scanf("%d",&num);
write(fd,&num,sizeof(int));
if(0 == num){
close(fd);
break;
}
}
} else {
printf("open my_driver failure/n");
}
return 0;
}
写设备文件,将数据写到文件的my_ver里。
以上就完成了自定义设备文件的读写操作,在这里我们针对设备文件定义了相应的驱动程序,在里面我们实现了
数据在设备文件和用户之间的传递功能,是不是很简单?
编译程序生成my_driver.ko, insmod my_driver.ko, 执行my_write,my_read,看试试可以读写文件。
呵呵,自己动手试试吧!
完整程序下载