Вопрос

I have made the simple character driver with looking at an example. However, I don't see the driver simple in /dev/simple. Why is it not created over there? I don't see any error issue also. Have I missed something, is there any problem?

#include <linux/init.h>
#include <linux/module.h> /** needed by all modules **/
#include <linux/kernel.h>  /** This is for KERN_ALERT **/
#include <linux/fs.h>
#include <linux/cdev.h>

/** for putuser **/
 #include <asm/uaccess.h>

MODULE_LICENSE("SJ BSD/GPL");


static struct cdev SimpleDevs[2];

static int simple_major = 0;


static ssize_t sj_read(struct file *filp,
   char *buffer,    /* The buffer to fill with data */
   size_t length,   /* The length of the buffer     */
   loff_t *offset);

static int sj_open(struct inode *inode, struct file *file);   


static struct file_operations fops = {
  .read = sj_read,
  //.write = sj_write,
  .open = sj_open,
  //.release = sj_release
};

static ssize_t sj_read(struct file *filp,
   char *buffer,    /* The buffer to fill with data */
   size_t length,   /* The length of the buffer     */
   loff_t *offset)  /* Our offset in the file       */
{

     char msg[1024] = "Hello SJ_read";
     copy_to_user( buffer, msg, sizeof(msg) );

      return sizeof(msg);

}

static void simple_setup_cdev(struct cdev *dev, int minor,
                 struct file_operations *fops)
{
        int err, devno = MKDEV(simple_major, minor);

         dev = cdev_alloc();

         cdev_init(dev, fops);
         dev->owner = THIS_MODULE;
         dev->ops = fops;
         err = cdev_add (dev, devno, 1);
         /* Fail gracefully if need be */
         if (err)
                 printk (KERN_NOTICE "Error %d adding simple%d", err, minor);
 }

static int sjDevInit(void)
{

    int result;
    dev_t dev; 

    printk("Device Init now..");


    /** int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name);  **/
    /** dev -> The dev_t variable type,which will get the major number that the kernel allocates.  **/
    /**The same name will appear in /proc/devices.  **/
    result = alloc_chrdev_region(&dev, 0, 1, "simple");
    if( result < 0 )
    {
      printk("Error in allocating device");
      return -1;    
    }
    // printk("simple_major ..");
     simple_major = MAJOR(dev);
     printk("simple_major number is %d ..\r\n",simple_major );

    /* Now set up two cdevs. */

    simple_setup_cdev(SimpleDevs, 0, &fops);
    simple_setup_cdev(SimpleDevs + 1, 1, &fops);

    return 0;

}


static void sjDevRel(void)
{
    printk("Releasing Simple Devs\r\n");
    cdev_del(SimpleDevs);

}

static int sj_open(struct inode *inode, struct file *file)
{

   printk("Kernel..Sj_open ..I am opened\r\n");

   return 0;
}

module_init(sjDevInit);
module_exit(sjDevRel);
Это было полезно?

Решение

Node devices are either created manually (by directly invoking mknod) or by udevd daemon upon receiving an uevent message. The message consists of "action" field (ADD, REMOVE, etc.) and a set of key/value pairs which udevd can peek at to decide which rule to invoke.

To emit the event you will need to get a handle on kobject ((struct cdev *)->kobj). After your device is fully created you need to do something like this:

err = cdev_add (dev, devno, 1);
/* Fail gracefully if need be */
if (err)
    printk (KERN_NOTICE "Error %d adding simple%d", err, minor);
kobject_uevent(&dev->kobj, KOBJ_ADD);

Prior to the removal of device, you need to do the opposite:

kobject_uevent(&SimpleDevs[0]->kobj, KOBJ_REMOVE);
printk("Releasing Simple Devs\r\n");
cdev_del(SimpleDevs[0]);

(by the way, your code has a major pointer handling bug involving your definition and usage of SimpleDevs variable, which you should sort out and fix).

At this point you can use udevadm monitor command to experiment and see if you are getting the messages from your driver and use any udev tutorial to write an appropriate rule (such as this one: https://wiki.debian.org/udev).

If you feel like adding more information to your uevent messages, you can try the more verbose kobject_uevent_env() API. This usually looks somewhat like this:

char event[] = "DISK_RO=1";
char *envp[] = { event, NULL };

if (!ro)
    event[8] = '0';
kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);

http://code.metager.de/source/xref/linux/stable/block/genhd.c#1320

If you want fancier messages the usual approach is to reserve a fixed chunk of memory of appropriate size and fill it in with snprintf prior to passing it down to uevent.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top