我正在学习linux设备驱动程序
所以我正在尝试为计算器编写代码,用户将使用用户空间程序进行输入,但计算将在内核中进行
我正在使用 ioctl 将值传递给内核
第一次运行良好(即在插入设备驱动程序之后),但是之后输出不正确。所以,如果我再次想要正确的答案,我会做rmmod驱动程序,再做一次insmod驱动程序
代码有什么问题吗?
有比使用驱动程序代码中使用的count变量更好的映射操作,value1和value2的方法
以下为输出 第一次我得到正确的输出,但是第二次是垃圾值:
calculator_ioctl$ ./a.out
*************************************
Opening Driver
Operation to perform
1. Add
2. Subtract
3. Multiply
4. Divide
2
Enter first value :45
Enter second value :11
writing value to driver
Reading value from driver
value is 34
closing driver
calculator_ioctl$ ./a.out
*************************************
Opening Driver
Operation to perform
1. Add
2. Subtract
3. Multiply
4. Divide
2
Enter first value :45
Enter second value :11
writing value to driver
Reading value from driver
value is -1410510832
closing driver
驱动程序代码:
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kdev_t.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/slab.h> //kmalloc.h
#include<linux/uaccess.h> //copy to/from user
#include<linux/ioctl.h>
#define WR_VALUE _IOW('a','a',int32_t*)
#define RD_VALUE _IOR('a','b',int32_t*)
int32_t value1 = 0 ;
int32_t value2 = 0 ;
int32_t value = 0 ;
int32_t oper = 0 ;
dev_t dev=0;
static struct class *dev_class;
static struct cdev etx_cdev ;
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
static long etx_ioctl(struct file *file,unsigned int cmd,unsigned long arg);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = etx_ioctl,
};
static long etx_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
static int count = 0;
switch(cmd) {
case WR_VALUE:
if(count == 0)
{
copy_from_user(&oper,(int32_t*)arg,sizeof(oper));
printk(KERN_INFO "oper = %d\n",oper);
break;
}
else if(count == 1){
copy_from_user(&value1,(int32_t*)arg,sizeof(value1));
printk(KERN_INFO "value1 = %d\n",value1);
break;
}
else if(count == 2){
copy_from_user(&value2,(int32_t*)arg,sizeof(value2));
printk(KERN_INFO "value2 = %d\n",value2);
break;
}
case RD_VALUE:
if(oper == 1)
value = value1 + value2 ;
else if(oper == 2)
value = value1 - value2;
else if(oper == 3)
value = value1 * value2;
else if(oper == 4)
value = value1 / value2;
else
break;
copy_to_user((int32_t*) arg, &value,sizeof(value));
break;
}
count+=1 ;
if(count == 3)
count = 0 ;
return 0;
}
static int __init etx_driver_init(void)
{
if((alloc_chrdev_region(&dev,0,1,"etx_dev")) <0){
printk(KERN_INFO"cannot allocate major number\n");
return -1;
}
printk(KERN_INFO " MAJOR = %d Minor = %d\n",MAJOR(dev),MINOR(dev));
cdev_init(&etx_cdev,&fops);
if((cdev_add(&etx_cdev,dev,1)) < 0){
printk(KERN_INFO "cannot add device to the system\n");
goto r_class;
}
/*Creating struct class*/
if((dev_class = class_create(THIS_MODULE,"etx_class")) == NULL){
printk(KERN_INFO "Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if((device_create(dev_class,NULL,dev,NULL,"etx_device")) == NULL){
printk(KERN_INFO "Cannot create the Device 1\n");
goto r_device;
}
printk(KERN_INFO "Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev,1);
return -1;
}
void __exit etx_driver_exit(void)
{
device_destroy(dev_class,dev);
class_destroy(dev_class);
cdev_del(&etx_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Device Driver Remove...Done!!!\n");
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
应用程序:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/ioctl.h>
#define WR_VALUE _IOW('a','a',int32_t*)
#define RD_VALUE _IOR('a','b',int32_t*)
int main()
{ int num;
int fd;
int32_t value,number1,number2,output,operation;
printf("\n*************************************\n");
printf("\nOpening Driver\n");
fd = open("/dev/etx_device",O_RDWR);
if(fd<0) {
printf("Cannot open device file ...\n");
return 0;
}
printf("Operation to perform\n\n");
printf("\
1. Add \n \
2. Subtract \n \
3. Multiply \n \
4. Divide \n\n\n ");
scanf("%d",&num);
if(num > 4 && num < 1)
{
printf("Enter between 1 and 4");
return 0;
}
ioctl(fd,WR_VALUE,(int32_t*) &num);
printf("Enter first value :");
scanf("%d",&number1);
printf("Enter second value :");
scanf("%d",&number2);
printf("writing value to driver\n");
ioctl(fd,WR_VALUE,(int32_t*) &number1);
ioctl(fd,WR_VALUE,(int32_t*) &number2);
printf("Reading value from driver \n");
ioctl(fd,RD_VALUE,(int32_t*)&value);
printf("value is %d\n",value);
printf("closing driver\n");
close(fd);
}