sábado, 22 de outubro de 2011

Character device Hello World

This is a little character device hello World, more
information on code.

/*
 * file: gkos_char_device.c
 *
 * Desc: A simple device that
 *      echos a message when read,
 *      write method not implemented
 *
 *      This was made on top of 
 *      LDD and LKMPG examples 
 *      
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>

#define DEVICE_NAME "gkos_char_device"


/*
 * Prototypes 
 */
int init_module(void);
void cleanup_module(void);
static int dev_open(struct inode *inode, struct file *);
static int dev_release(struct inode *inode, struct file *);
static ssize_t dev_read(struct file *fp, char *buf, size_t len, loff_t *off);
static ssize_t dev_write(struct file *, const char *buf, size_t len, 
                loff_t *off);
static int dev_init(void);

/*
 * Our variables, @use_counter
 * will block concurrenty opens.
 * @buffer is the message and
 * @buffer_len the lenght of @buffer (duh)
 */
static char use_counter = 0;
static char buffer[] = "Hello character device world\n";
static int buffer_len = sizeof(buffer);

static dev_t dev;
static struct cdev *cdevp;


static struct file_operations fops = {
        .owner = THIS_MODULE,
        .read = dev_read,
        .write = dev_write,
        .open = dev_open,
        .release = dev_release
};

/*
 * Any device specific initialization
 * goes here. Its called at bottom of init_module()
 */
static int dev_init(void)
{
        return 0;
}

/*
 * Called when device is opened
 */
static int dev_open(struct inode *inode, struct file *fp)
{
        if (use_counter)
                return -EBUSY;
        use_counter++;
        try_module_get(THIS_MODULE);
        return 0;
}

/* 
 * Called when device is released. The device is
 * released when there is no process using it.
 */
static int dev_release(struct inode *inode, struct file *fp)
{
        use_counter--;
        module_put(THIS_MODULE);
        return 0;
}


/*
 * @off controls
 * the "walk" through our buffer, is whith @off
 * that we say to user where is stoped.
 * @len is how much bytes to read. I almost ignore it.
 * I just check if is greater than 0.
 *
 * Called when device is read. 
 * This method will read one, and only one byte per call,
 * If @off is longer than my buffer size or len is not
 * greater than 0 it returns 0, otherwise I copy one byte
 * to user buffer and returns the bytes readed, so 1.
 */
static ssize_t dev_read(struct file *fp, char *buf, size_t len, loff_t *off)
{
        if (*off >= buffer_len || len <= 0)
                return 0;

        if (copy_to_user(buf, &buffer[*off], 1u))
                        return -EFAULT;

        (*off)++;
        return 1;
}


/*
 * Not implemented at all
 */
static ssize_t dev_write(struct file *fp, const char *buf, size_t len, 
                loff_t *off)
{
        return -ENOSYS;
}

/*
 * Called when module is load
 */
int init_module(void)
{
        int error;

        /* Alloc a device region */
        error = alloc_chrdev_region(&dev, 1, 1, DEVICE_NAME);
        if (error) 
                goto error_out;

        /* Registring */
        cdevp = cdev_alloc();
        if (!cdevp) 
                return -ENOMEM; 

        /* Init it! */
        cdev_init(cdevp, &fops); 

        /* Tell the kernel "hey, I'm exist" */
        error = cdev_add(cdevp, dev, 1);
        if (error < 0) 
                goto error_out;

        printk(KERN_INFO DEVICE_NAME " registred with major %d\n", MAJOR(dev));
        printk(KERN_INFO DEVICE_NAME " do: `mknod /dev/%s c %d %d' to create "
                        "the device file\n", 
                        DEVICE_NAME, MAJOR(dev), MINOR(dev)); 

        /* Device initialization isn't needed yet */
        if (dev_init())
                goto error_out;

        return 0;

error_out:
        return -EFAULT;
}

void cleanup_module(void)
{
        cdev_del(cdevp);
}

MODULE_LICENSE("GPL");

Makefile:
obj-m += gkos_char_device.o

all:
 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 
 
clean:
 rm *.ko *.o *.mod.c *.mod.o

Building and Running:

Nenhum comentário:

Postar um comentário