калькулятор с использованием ioctl драйвера устройства Linux - PullRequest
0 голосов
/ 20 ноября 2018

Я изучаю драйверы устройств Linux

Итак, я пытаюсь написать код для калькулятора, где пользователь будет вводить данные с помощью программы userpace, но вычисления будут выполняться в ядре

Я использую ioctl для передачи значений в ядро ​​

Он отлично работает в первый раз (т.е. после установки драйвера устройства), но после этого выдает неправильный вывод. Поэтому, если я снова хочу получить правильный ответ, я делаю драйвер rmmod и снова драйвер insmod

Что не так с кодом?

Есть ли лучший способ отобразить операцию, значение1 и значение2, чем использование переменной count, которую я использую в коде драйвера

следующий вывод где в первый раз я получаю правильный вывод, а во второй раз значение мусора:

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);

}  
...