Модуль ядра Linux: возможно ли использовать функцию open внутри другой функции open для моего модуля? - PullRequest
0 голосов
/ 25 октября 2019

Возможно, этот вопрос не имеет смысла, но мне было интересно, существует ли "рекомендуемая практика", как открыть файловый дескриптор для устройства внутри функции открытия созданного модуля.

На самом деле,Я разработал простой модуль ядра Linux с его основными функциями:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>  
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>

MODULE_LICENSE("GPL");      
MODULE_AUTHOR("Gaston");  
MODULE_DESCRIPTION("A simple Linux char driver"); 
MODULE_VERSION("0.1"); 


ssize_t exer_open(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device has been opened\n");

    return 0;
}



ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {

    return 0;
}



ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {

    return 0;

}   




ssize_t exer_close(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device successfully closed\n");
    return 0;
}


struct file_operations exer_file_operations = { 
    .owner = THIS_MODULE,
    .open = exer_open,
    .read = exer_read,
    .write = exer_write,
    .release = exer_close,
};


int exer_simple_module_init(void) {

    printk(KERN_INFO "Initializing the LKM\n");
    register_chrdev(240, "Simple Char Drv", &exer_file_operations);
    return 0;
}


void exer_simple_module_exit(void) {

    unregister_chrdev(240, "Simple Char Drv");
}


module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);

Я скомпилировал его, и ошибок не было.

Теперь я хочу открыть файловый дескриптор моего устройства (КНОПКУ) вЧтобы потом манипулировать им из программы пользовательского пространства, я внес некоторые изменения, добавив путь к устройству BUTTON и другую открытую функцию, например:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>  
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>

MODULE_LICENSE("GPL");      
MODULE_AUTHOR("Gaston");  
MODULE_DESCRIPTION("A simple Linux char driver"); 
MODULE_VERSION("0.1"); 

#define BTN_FILE_PATH "/dev/input/event0"

int file;
char *str = BTN_FILE_PATH;


ssize_t exer_open(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device has been opened\n");

    if((file = open(str, O_RDONLY)) < 0) {
        printk("simplekey: File can not open");
        return(-1);
    }
    return 0;
}



ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {

    return 0;
}


ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {

    return 0;

}   


ssize_t exer_close(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device successfully closed\n");
    return 0;
}


struct file_operations exer_file_operations = { 
    .owner = THIS_MODULE,
    .open = exer_open,
    .read = exer_read,
    .write = exer_write,
    .release = exer_close,
};


int exer_simple_module_init(void) {

    printk(KERN_INFO "Initializing the LKM\n");
    register_chrdev(240, "Simple Char Drv", &exer_file_operations);
    return 0;
}


void exer_simple_module_exit(void) {

    unregister_chrdev(240, "Simple Char Drv");
}


module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);

Но проблема, когда я пытаюсь скомпилировать модуль, теперь приводит к ошибкам. печатаются:

/ home / gaston / ledshared / exer_simple_char_drv.c: в функции 'exer_open': /home/gaston/ledshared/exer_simple_char_drv.c:32:13: ошибка: неявное объявление функции'open' [-Werror = неявное объявление-функции]

if ((file = open (str, O_RDONLY)) <0) {</p>

Как я могу решить проблемупожалуйста ?

1 Ответ

1 голос
/ 25 октября 2019

open() - функция пространства пользователя. Эквивалентная функция пространства ядра - filp_open(), но она возвращает struct file * вместо int файлового дескриптора. Возвращенный struct file * может быть кодом ошибки вместо действительного указателя. Используйте макрос IS_ERR(ptr), чтобы проверить это, и макрос PTR_ERR(ptr), чтобы извлечь код ошибки (который будет отрицательным значением errno).

Использование функции filp_open не рекомендуется, но здесьВот некоторые модификации вашего кода для использования этой функции:

int exer_open(struct inode *pinode, struct file *pfile) {
    struct file *f;

    f = filp_open(str, O_RDONLY);
    if (IS_ERR(f)) {
        printk("simplekey: File can not open");
        return(PTR_ERR(f));
    }
    pfile->private_data = f;

    printk(KERN_INFO "Device has been opened\n");
    return 0;
}

Функция закрытия должна выглядеть примерно так:

int exer_close(struct inode *pinode, struct file *pfile) {
    struct file *f = pfile->private_data;
    int rc;

    rc = filp_close(f, NULL);
    if (rc == 0) {
        printk(KERN_INFO "Device successfully closed\n");
    }
    return rc;
}

У модуля нет законного способа чтения изstruct file * непосредственно в буфер пространства пользователя или запись из буфера пространства пользователя в struct file *, поэтому необходим промежуточный буфер в памяти ядра, так что kernel_read() или kernel_write() можно использовать для чтения или записифайл:

ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
    struct file *f = pfile->private_data;
    enum { MAX_BUF_SIZE = 4096 };
    size_t buf_size = 0;
    char *buf = NULL;
    ssize_t total = 0;
    ssize_t rc = 0;

    /* Allocate temporary buffer. */
    if (length) {
        buf_size = min_t(size_t, MAX_BUF_SIZE, length);
        buf = kmalloc(buf_size, GFP_KERNEL);
        if (buf == NULL) {
            return -ENOMEM;
        }
    }

    /* Read file to buffer in chunks. */
    do {
        size_t amount = min_t(size_t, length, buf_size);

        rc = kernel_read(f, buf, amount, offset);
        if (rc > 0) {
            /* Have read some data from file. */
            if (copy_to_user(buffer, buf, rc) != 0) {
                /* Bad user memory! */
                rc = -EFAULT;
            } else {
                /* Update totals. */
                total += rc;
                buffer += rc;
                *offset += rc;
                length -= rc;
                if (rc < amount) {
                    /* Didn't read the full amount, so terminate early. */
                    rc = 0;
                }
            }
        }
    } while (rc > 0 && length > 0);

    /* Free temporary buffer. */
    kfree(buf);

    if (total > 0) {
        return total;
    }
    return rc;
}


ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
    struct file *f = pfile->private_data;
    enum { MAX_BUF_SIZE = 4096 };
    size_t buf_size = 0;
    char *buf = NULL;
    ssize_t total = 0;
    ssize_t rc = 0;

    /* Allocate temporary buffer. */
    if (length) {
        buf_size = min_t(size_t, MAX_BUF_SIZE, length);
        buf = kmalloc(buf_size, GFP_KERNEL);
        if (buf == NULL) {
            return -ENOMEM;
        }
    }

    /* Write file from buffer in chunks. */
    do {
        size_t amount = min_t(size_t, length, buf_size);

        if (copy_from_user(buf, buffer, amount) != 0) {
            /* Bad user memory! */
            rc = -EFAULT;
        } else {
            rc = kernel_write(f, buf, amount, offset);
            if (rc > 0) {
                /* Have written some data to file. */
                /* Update totals. */
                total += rc;
                buffer += rc;
                *offset += rc;
                length -= rc;
                if (rc < amount) {
                    /* Didn't write the full amount, so terminate early. */
                    rc = 0;
                }
            }
        }
    } while (rc > 0 && length > 0);

    /* Free temporary buffer. */
    kfree(buf);

    if (total > 0) {
        return total;
    }
    return rc;
}   
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...