一个简单的字符设备驱动

.h文件

#ifndef _DEMO_H_
#define _DEMO_H_
#include <linux/ioctl.h>
/*Macros to help debuging*/
#undef PDEBUG
#ifdef DEMO_DEBUG
    #ifdef __KERNEL__
        #define PDEBUG(fmt, args...) printk(KERN_DEBUG "DEMO:" fmt,## args)
    #else
        #define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
    #endif
#else
#define PDEBUG(fmt, args...)
#endif

#define DEMO_MAJOR 224
#define DEMO_MINOR 0
#define COMMAND1 1
#define COMMAND2 2

struct demo_dev {
            struct cdev cdev;
};

ssize_t demo_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
loff_t demo_llseek(struct file *filp, loff_t off, int whence);
static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);

#endif

 

.c文件

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/device.h>
#include "demo.h"

MODULE_AUTHOR("Gaowei");
MODULE_LICENSE("Dual BSD/GPL");

struct demo_dev *demo_devices;

static unsigned char demo_inc = 0;//全局变量,每次只能打开一个设备

static u8 demo_buffer[256];
static struct class *demo_class;
int demo_open(struct inode *inode, struct file *filp)
{
        struct demo_dev *dev;

        if (demo_inc > 0) return -ERESTARTSYS;
        demo_inc++;
        dev = container_of(inode->i_cdev, struct demo_dev, cdev);
        filp->private_data = dev;

        return 0;
}

int demo_release(struct inode *inode, struct file *filp)
{
        demo_inc--;
        return 0;
}

ssize_t demo_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
        int result;
        loff_t pos = *f_pos; //pos: offset

        if (pos >= 256) {
                result = 0;
                goto out;
        }
        if (count > (256 - pos))
                count = 256 - pos;
        pos += count;

        if (copy_to_user(buf, demo_buffer+*f_pos, count)) {
                count = -EFAULT;
                goto out;
        }

        *f_pos = pos;
out:
        return count;
}

ssize_t  demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
        ssize_t retval = -ENOMEM;
        loff_t pos = *f_pos;

        if (pos > 256)
                goto out;
        if (count > (256 - pos))
                count = 256 - pos;
        pos += count;
        if (copy_from_user(demo_buffer+*f_pos, buf, count)) {
                retval = -EFAULT;
                goto out;
        }

        *f_pos = pos;
        retval = count;
out:
        return retval;
}

static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
        if (cmd == COMMAND1) {
                printk("ioctl command 1 successfully\n");
                return 0;
        }
        if (cmd == COMMAND2) {
                printk("ioctl command 2 successfully\n");
                return 0;
        }
        printk("ioctl error\n");
        return -EFAULT;
}

loff_t demo_llseek(struct file *filp, loff_t off, int whence)
{
        loff_t pos;

        pos = filp->f_pos;
        switch (whence) {
                case 0:
                        pos = off;
                        break;
                case 1:
                        pos += off;
                        break;
                case 2:
                default:
                        return -EINVAL;
        }

        if ((pos > 256) || (pos < 0))
                return -EINVAL;

        return filp->f_pos = pos;
}

struct file_operations demo_fops = {
        .owner = THIS_MODULE,
        .llseek = demo_llseek,
        .read = demo_read,
        .write = demo_write,
        .unlocked_ioctl = demo_ioctl,
        .open = demo_open,
        .release = demo_release,
};

void demo_cleanup_module(void)
{
        dev_t devno = MKDEV(DEMO_MAJOR, DEMO_MINOR);

        if (demo_devices) {
                cdev_del(&demo_devices->cdev);
                kfree(demo_devices);
        }
        unregister_chrdev_region(devno, 1);
}

/*Init module流程:
1)注册设备号MKDEV;
2)注册设备驱动程序,即初始化cdev结构(嵌入到demo_devices结构中)*/
int demo_init_module(void)
{
        int result;
        dev_t dev = 0;

        dev = MKDEV(DEMO_MAJOR, DEMO_MINOR);
        result = register_chrdev_region(dev, 1, "DEMO");
        if (result < 0) {
                printk(KERN_WARNING "DEMO: can't get major %d\n", DEMO_MAJOR);
                return result;
        }
        demo_devices = kmalloc(sizeof(struct demo_dev), GFP_KERNEL);
        if (!demo_devices) {
                result = -ENOMEM;
                goto fail;
        }
        memset(demo_devices, 0, sizeof(struct demo_dev));
        cdev_init(&demo_devices->cdev, &demo_fops);
        demo_devices->cdev.owner = THIS_MODULE;
        result = cdev_add(&demo_devices->cdev, dev, 1);
        if (result) {
                printk(KERN_NOTICE "error %d adding demo\n", result);
                goto fail;
        }
        demo_class = class_create(THIS_MODULE, "DEMO");
        device_create(demo_class, NULL, MKDEV(DEMO_MAJOR, DEMO_MINOR), NULL, "DEMO"); // create a device
        return 0;
fail:
        demo_cleanup_module();
        return result;
}

module_init(demo_init_module);
module_exit(demo_cleanup_module);

Makefile文件

obj-m:=demo.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
        $(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
        $(MAKE) -C $(KDIR) M=$(PWD) clean

 

posted @ 2017-01-03 15:31  penghan  阅读(834)  评论(0编辑  收藏  举报