20

Linux モジュールでsysfsを使用する方法を学んでいますが、これらのトピックに関する最新のドキュメントを見つけるのに最も苦労しています。私が使用しているLinux Device Drivers 3rd Editionの本は、残念ながらこの分野ではかなり古いようです (たとえば、class_device現在の Linux バージョンでは構造が完全になくなっているようです)。

モジュールのそれぞれのsysfsクラスの下に、カーネル空間からモジュール変数の値を読み取れるようにする属性を表示しようとしているだけです。

私のコードでは、udev がモジュールの/dev/fooにデバイス ノードを作成できるようにするクラスを作成しています。

dev_t foo_dev;
alloc_chrdev_region(&foo_dev, 0, 1, "bar");

struct class *bar = class_create(THIS_MODULE, "bar");

device_create(bar, NULL, foo_dev, NULL, "foo");

struct cdev foo_dev_file;
cdev_init(&foo_dev_file, &fops); /* fops defined earlier */
cdev_add(&foo_dev_file, foo_dev, 1);

モジュールを挿入すると、sysfsクラス ディレクトリが作成され、/sys/class/bar/foo/にいくつかのデフォルト属性が設定されます。この新しいディレクトリの下に表示される属性を作成するにはどうすればよいですか?

私は概念をかなりよく理解しています-属性構造の作成、sysfs_ops関数の定義など-私の問題は、どの特定のカーネル構造を使用するのか(class_attribute?)、またはこれらの属性を右側に表示する方法がわからないことですsysfsディレクトリ。

現在の Linux カーネルのプロセスを詳述したチュートリアルまたは記事を教えてくれる人はいますか?

4

3 に答える 3

2

以下のリンクに良いチュートリアルがあります

http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html

parrot_driver.c:

/*
 * Linux 2.6 and 3.0 'parrot' sample device driver
 *
 * Copyright (c) 2011, Pete Batard <pete@akeo.ie>
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/kfifo.h>
#include "parrot_driver.h"

/* Module information */
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESCRIPTION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");

/* Device variables */
static struct class* parrot_class = NULL;
static struct device* parrot_device = NULL;
static int parrot_major;
/* Flag used with the one_shot mode */
static bool message_read;
/* A mutex will ensure that only one process accesses our device */
static DEFINE_MUTEX(parrot_device_mutex);
/* Use a Kernel FIFO for read operations */
static DECLARE_KFIFO(parrot_msg_fifo, char, PARROT_MSG_FIFO_SIZE);
/* This table keeps track of each message length in the FIFO */
static unsigned int parrot_msg_len[PARROT_MSG_FIFO_MAX];
/* Read and write index for the table above */
static int parrot_msg_idx_rd, parrot_msg_idx_wr;

/* Module parameters that can be provided on insmod */
static bool debug = false;  /* print extra debug info */
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "enable debug info (default: false)");
static bool one_shot = true;    /* only read a single message after open() */
module_param(one_shot, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "disable the readout of multiple messages at once (default: true)");


static int parrot_device_open(struct inode* inode, struct file* filp)
{
    dbg("");

    /* Our sample device does not allow write access */
    if ( ((filp->f_flags & O_ACCMODE) == O_WRONLY)
      || ((filp->f_flags & O_ACCMODE) == O_RDWR) ) {
        warn("write access is prohibited\n");
        return -EACCES;
    }

    /* Ensure that only one process has access to our device at any one time
    * For more info on concurrent accesses, see http://lwn.net/images/pdf/LDD3/ch05.pdf */
    if (!mutex_trylock(&parrot_device_mutex)) {
        warn("another process is accessing the device\n");
        return -EBUSY;
    }

    message_read = false;
    return 0;
}

static int parrot_device_close(struct inode* inode, struct file* filp)
{
    dbg("");
    mutex_unlock(&parrot_device_mutex);
    return 0;
}

static ssize_t parrot_device_read(struct file* filp, char __user *buffer, size_t length, loff_t* offset)
{
    int retval;
    unsigned int copied;

    /* The default from 'cat' is to issue multiple reads until the FIFO is depleted
     * one_shot avoids that */
    if (one_shot && message_read) return 0;
    dbg("");

    if (kfifo_is_empty(&parrot_msg_fifo)) {
        dbg("no message in fifo\n");
        return 0;
    }

    retval = kfifo_to_user(&parrot_msg_fifo, buffer, parrot_msg_len[parrot_msg_idx_rd], &copied);
    /* Ignore short reads (but warn about them) */
    if (parrot_msg_len[parrot_msg_idx_rd] != copied) {
        warn("short read detected\n");
    }
    /* loop into the message length table */
    parrot_msg_idx_rd = (parrot_msg_idx_rd+1)%PARROT_MSG_FIFO_MAX;
    message_read = true;

    return retval ? retval : copied;
}

/* The file_operation scructure tells the kernel which device operations are handled.
 * For a list of available file operations, see http://lwn.net/images/pdf/LDD3/ch03.pdf */
static struct file_operations fops = {
    .read = parrot_device_read,
    .open = parrot_device_open,
    .release = parrot_device_close
};

/* Placing data into the read FIFO is done through sysfs */
static ssize_t sys_add_to_fifo(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
    unsigned int copied;

    dbg("");
    if (kfifo_avail(&parrot_msg_fifo) < count) {
        warn("not enough space left on fifo\n");
        return -ENOSPC;
    }
    if ((parrot_msg_idx_wr+1)%PARROT_MSG_FIFO_MAX == parrot_msg_idx_rd) {
        /* We've looped into our message length table */
        warn("message length table is full\n");
        return -ENOSPC;
    }

    /* The buffer is already in kernel space, so no need for ..._from_user() */
    copied = kfifo_in(&parrot_msg_fifo, buf, count);
    parrot_msg_len[parrot_msg_idx_wr] = copied;
    if (copied != count) {
        warn("short write detected\n");
    }
    parrot_msg_idx_wr = (parrot_msg_idx_wr+1)%PARROT_MSG_FIFO_MAX;

    return copied;
}

/* This sysfs entry resets the FIFO */
static ssize_t sys_reset(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
    dbg("");

    /* Ideally, we would have a mutex around the FIFO, to ensure that we don't reset while in use.
     * To keep this sample simple, and because this is a sysfs operation, we don't do that */
    kfifo_reset(&parrot_msg_fifo);
    parrot_msg_idx_rd = parrot_msg_idx_wr = 0;

    return count;
}

/* Declare the sysfs entries. The macros create instances of dev_attr_fifo and dev_attr_reset */
static DEVICE_ATTR(fifo, S_IWUSR, NULL, sys_add_to_fifo);
static DEVICE_ATTR(reset, S_IWUSR, NULL, sys_reset);

/* Module initialization and release */
static int __init parrot_module_init(void)
{
    int retval;
    dbg("");

    /* First, see if we can dynamically allocate a major for our device */
    parrot_major = register_chrdev(0, DEVICE_NAME, &fops);
    if (parrot_major < 0) {
        err("failed to register device: error %d\n", parrot_major);
        retval = parrot_major;
        goto failed_chrdevreg;
    }

    /* We can either tie our device to a bus (existing, or one that we create)
     * or use a "virtual" device class. For this example, we choose the latter */
    parrot_class = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(parrot_class)) {
        err("failed to register device class '%s'\n", CLASS_NAME);
        retval = PTR_ERR(parrot_class);
        goto failed_classreg;
    }

    /* With a class, the easiest way to instantiate a device is to call device_create() */
    parrot_device = device_create(parrot_class, NULL, MKDEV(parrot_major, 0), NULL, CLASS_NAME "_" DEVICE_NAME);
    if (IS_ERR(parrot_device)) {
        err("failed to create device '%s_%s'\n", CLASS_NAME, DEVICE_NAME);
        retval = PTR_ERR(parrot_device);
        goto failed_devreg;
    }

    /* Now we can create the sysfs endpoints (don't care about errors).
     * dev_attr_fifo and dev_attr_reset come from the DEVICE_ATTR(...) earlier */
    retval = device_create_file(parrot_device, &dev_attr_fifo);
    if (retval < 0) {
        warn("failed to create write /sys endpoint - continuing without\n");
    }
    retval = device_create_file(parrot_device, &dev_attr_reset);
    if (retval < 0) {
        warn("failed to create reset /sys endpoint - continuing without\n");
    }

    mutex_init(&parrot_device_mutex);
    /* This device uses a Kernel FIFO for its read operation */
    INIT_KFIFO(parrot_msg_fifo);
    parrot_msg_idx_rd = parrot_msg_idx_wr = 0;

    return 0;

failed_devreg:
    class_unregister(parrot_class);
    class_destroy(parrot_class);
failed_classreg:
    unregister_chrdev(parrot_major, DEVICE_NAME);
failed_chrdevreg:
    return -1;
}

static void __exit parrot_module_exit(void)
{
    dbg("");
    device_remove_file(parrot_device, &dev_attr_fifo);
    device_remove_file(parrot_device, &dev_attr_reset);
    device_destroy(parrot_class, MKDEV(parrot_major, 0));
    class_unregister(parrot_class);
    class_destroy(parrot_class);
    unregister_chrdev(parrot_major, DEVICE_NAME);
}

/* Let the kernel know the calls for module init and exit */
module_init(parrot_module_init);
module_exit(parrot_module_exit);

parrot_driver.h:

/*
 * Linux 2.6 and 3.0 'parrot' sample device driver
 *
 * Copyright (c) 2011, Pete Batard <pete@akeo.ie>
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#define DEVICE_NAME "device"
#define CLASS_NAME "parrot"
#define PARROT_MSG_FIFO_SIZE 1024
#define PARROT_MSG_FIFO_MAX  128

#define AUTHOR "Pete Batard <pete@akeo.ie>"
#define DESCRIPTION "'parrot' sample device driver"
#define VERSION "0.3"

/* We'll use our own macros for printk */
#define dbg(format, arg...) do { if (debug) pr_info(CLASS_NAME ": %s: " format , __FUNCTION__ , ## arg); } while (0)
#define err(format, arg...) pr_err(CLASS_NAME ": " format, ## arg)
#define info(format, arg...) pr_info(CLASS_NAME ": " format, ## arg)
#define warn(format, arg...) pr_warn(CLASS_NAME ": " format, ## arg)
于 2015-08-17T11:20:04.993 に答える