LINUX.ORG.RU

Модуль ядра, терзающий файл символьного устройства


0

2

Привет. Эта тема уже тут несколько раз поднималась, но, к сожалению, не нашел в обсуждении того, что мне нужно. Задача: создать модуль ядра, работающий с файлом символьного устройства и выводящий кол-во попыток чтения из этого устройства (с использованием ioctl). Устройство любое можно взять, главное, чтоб символьное было :) Не могу найти инструкций, как провернуть это дело: Лава прочитал, теперь я гуру написания ничего не делающих модулей; какая вот функция позволяет «подключиться» к файлу устройства, используя старший номер устройства?

а по имени устройства «подлючиться» к нему нельзя?

metawishmaster ★★★★ ()

Ты хочешь считать обращения к чужому устройству или к своему? Если к чужому, то наверно какие-то хуки на ioctl() надо смотреть.

frey ★★ ()

А как ты собираешься использовать свои ioctl-запросы для «чужого» устройства? Тебе драйвер этого устройства вернет просто Invalid request... Разве не так?

Dennis7 ()

Вот пример модуля для версии ядра > 2.6.25. При загрузке модуль должен создавать символьное устройство /dev/my_device. Если выключить автосоздание ноды устройства, то ее можно создать вручную: сначала узнаем major number из /proc/devices, затем mknod

maj=`sed -n 's/\\(^[0-9][0-9]*\\) my_device.*/\\1/p' /proc/devices`; mknod /dev/my_device c $maj 0

/* h.c */

#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
#endif

MODULE_LICENSE("GPL");

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)
#define AUTO_CREATE_DEV_NODE
#endif

struct _my_data;

/* process ioctl() on file */
static int my_drv_ioctl(struct inode *inode, struct file *filp, unsigned cmd, unsigned long arg)
{
    struct _my_data *data = (struct _my_data*)filp->private_data;
    /* TODO: use data */
    printk("my_drv_ioctl()\n");
    return 0; /* ok */
}

/* process open() on file */
static int my_drv_open(struct inode *inode, struct file *filp)
{
    struct _my_data *data = NULL;
    /* TODO: allocate data to associate with opened file handle */
    filp->private_data = data;
    printk("my_drv_open()\n");
    return 0; /* ok */
}

/* process close() on file */
static int my_drv_release(struct inode *inode, struct file *filp)
{
    struct _my_data *data = (struct _my_data*)filp->private_data;
    /* TODO: free data */
    printk("my_drv_release()\n");
    return 0; /* ok */
}

static long my_drv_unlocked_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
{
    return my_drv_ioctl(NULL, filp, cmd, arg);
}

#ifdef CONFIG_COMPAT
static long my_drv_compat_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
{
    return my_drv_ioctl(NULL, filp, cmd, (unsigned long)compat_ptr(arg));
}
#endif

static struct file_operations fops = {
    .owner   = THIS_MODULE,
    .open    = my_drv_open,
    .release = my_drv_release,
    .unlocked_ioctl = my_drv_unlocked_ioctl  /* ioctl without BKL (big kernel lock) */
#ifdef CONFIG_COMPAT
    ,.compat_ioctl = my_drv_compat_ioctl     /* 32-bit user -> 64-bit kernel ioctl */
#endif
};

struct _my_dev_info {
    int major;
    const char *class_name;
    const char *device_name;
    struct class *class;
    struct device *device;
};

#ifdef AUTO_CREATE_DEV_NODE
static int _create_device_node(struct _my_dev_info *info)
{
    int err;
    info->class = class_create(THIS_MODULE, info->class_name);
    printk("class_create: %s (err=%ld)\n", info->class_name, IS_ERR(info->class));
    if (!IS_ERR(info->class)) {
        dev_t dev = MKDEV(info->major, /*minor_start*/0);
        info->device = device_create(info->class, /*parent:*/NULL, dev, /*drvdata:*/NULL, /*fmt:*/info->device_name, 0);
        printk("device_create: %s (err=%ld)\n", info->device_name, IS_ERR(info->device));
        if (!IS_ERR(info->device))
            return 0; /* ok */
        else {
            err = IS_ERR(info->device);
            printk(KERN_ERR "device_create failed for %s (%d)\n", info->device_name, err);
        }
        class_destroy(info->class);
    }
    else {
        err = IS_ERR(info->class);
        printk(KERN_ERR "class_create failed for %s (%d)\n", info->class_name, err);
    }
    return err;
}

static void _remove_device_node(struct _my_dev_info *info)
{
    printk("device_destroy: (%p) %s (major=%d)\n", info->class, info->device_name, info->major);
    device_destroy(info->class, MKDEV(info->major, /*minor_start*/0));
    printk("class_destroy: (%p) %s (major=%d)\n", info->class, info->class_name, info->major);
    class_destroy(info->class);
}
#endif

продолжение следует...

anonymous ()
Ответ на: комментарий от anonymous

продолжение

static inline int _register_device(struct _my_dev_info *info)
{
    int err = 0;
    info->major = register_chrdev(info->major, info->device_name, &fops);
    if (-EBUSY != info->major) {
#ifdef AUTO_CREATE_DEV_NODE
        err = _create_device_node(info);
#endif
        if (!err)
            return 0; /* ok */
        unregister_chrdev(info->major, info->device_name);
    }
    else {
        err = info->major;
        printk(KERN_ERR "register_chrdev failed for %s (%d)\n", info->device_name, err);
    }
    return err;
}

static inline void _unregister_device(struct _my_dev_info *info)
{
#ifdef AUTO_CREATE_DEV_NODE
    _remove_device_node(info);
#endif
    printk("unregister_chrdev: %s (major=%d)\n", info->device_name, info->major);
    unregister_chrdev(info->major, info->device_name);
}

static struct _my_dev_info my_info = {
    .major = 0/*use dynamic major number*/,
    .class_name = "my_class",
    .device_name = "my_device"
};

static int __init h_init(void)
{
    printk(KERN_INFO "Hello world 1.\n");
    return _register_device(&my_info);
}

static void __exit h_fini(void)
{
    _unregister_device(&my_info);
    printk(KERN_INFO "Goodbye world 1.\n");
}

module_init(h_init);
module_exit(h_fini);

anonymous ()
Ответ на: комментарий от anonymous

Не понял в чем у тебя проблема добавить поле счетчик в эту структуру _my_data и инкрементировать его при каждом вызове ioctl.

frey ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.