zoukankan      html  css  js  c++  java
  • linux 3.0.35下globalmem 字符设备驱动实现

    1、Makefile

    KDIR=/home/xxx/s-linux-3.0.35
    PWD:=$(shell pwd)
    
    # kernel modules
    obj-m := globalmem.o
    
    modules:
        make -C $(KDIR) M=$(PWD) modules
    
    clean:
        rm -rf *.o *.ko *.mod.c *.markesr *.order *.symvers
    
    .PHONY:modules clean

    2、globalmem.c

    #include <linux/module.h>
    #include <linux/types.h>
    #include <linux/fs.h>
    #include <linux/errno.h>
    #include <linux/mm.h>
    #include <linux/sched.h>
    #include <linux/init.h>
    #include <linux/cdev.h>
    #include <linux/slab.h>
    
    #include <asm/io.h>
    #include <asm/system.h>
    #include <asm/uaccess.h>
    
    #define GLOBALMEM_SIZE 0x1000 // 4KB
    
    // create device node in the board side.
    // mknod /dev/globalmem c 120 0
    #define GLOBALMEM_MAJOR 120 // preset major number
    
    // define ioctl cmd
    #define GLOBALMEM_MAGIC 0x01
    #define MEM_CLEAR _IO(GLOBALMEM_MAGIC, 0)
    
    static int globalmem_major = GLOBALMEM_MAJOR;
    
    // globalmem struct
    struct globalmem_dev {
        struct cdev cdev; // cdev struct
        unsigned char mem[GLOBALMEM_SIZE]; // global memory
    };
    
    struct globalmem_dev *globalmem_devp; // device struct instance
    
    int globalmem_open(struct inode *inode, struct file *filp)
    {
            // set device struct pointer to file privatedata pointer
        filp->private_data = globalmem_devp;
    
        return 0;
    }
    
    int globalmem_release(struct inode *inode, struct file *filp)
    {
        return 0;
    }
    
    static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
                                  loff_t *ppos)
    {
        unsigned long p = *ppos;
        unsigned int count = size;
        int ret = 0;
        struct globalmem_dev *dev = filp->private_data; // get device struct pointer
            
            // analysis and get valid read length
        if (p >= GLOBALMEM_SIZE) // overflow
            return 0;
    
        if (count > GLOBALMEM_SIZE - p) // count is too large
            count = GLOBALMEM_SIZE - p;
    
            // kernel buf -> user buf
        if (copy_to_user(buf, (void *)(dev->mem + p), count))
            ret = -EFAULT;
        else {
            *ppos += count;
            ret = count;
            printk(KERN_INFO "read %d bytes from %ld
    ", count, p);
        }
    
        return ret;
    }
    
    static ssize_t globalmem_write(struct file *filp, const char __user *buf,
                                   size_t size, loff_t *ppos)
    {
        unsigned long p = *ppos;
        unsigned int count = size;
        int ret = 0;
        struct globalmem_dev *dev = filp->private_data; // get device stuct pointer
    
            // analysis and get valid write length
        if (p >= GLOBALMEM_SIZE) // write overflow
            return 0;
    
        if (count > GLOBALMEM_SIZE - p) // write count is too large
            count = GLOBALMEM_SIZE - p;
    
            // user buf -> kernel buf
        if (copy_from_user(dev->mem + p, buf, count))
            ret = -EFAULT;
        else {
            *ppos += count;
            ret = count;
            printk(KERN_INFO "written %d bytes from %ld
    ", count, p);
        }
    
        return ret;
    }
    
    static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
    {
        loff_t ret = 0;
    
        switch (orig) {
            case 0: // from the file head
                if (offset < 0 || ((unsigned int) offset > GLOBALMEM_SIZE)) {
                    ret = -EINVAL;
                    break;
                }
                filp->f_pos = (unsigned int) offset;
                ret = filp->f_pos;
                break;
    
            case 1: // from current position
                if ((filp->f_pos + offset) > GLOBALMEM_SIZE || (filp->f_pos + offset) < 0) {
                    ret = - EINVAL;
                    break;
                }
                filp->f_pos += offset;
                ret = filp->f_pos;
                break;
        }
    
        return ret;
    }
    
    
    static long globalmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
    {
    
        struct globalmem_dev *dev = filp->private_data; // get device stuct pointer
        
        switch (cmd) {
            case MEM_CLEAR:
                memset(dev->mem, 0, GLOBALMEM_SIZE);
                printk(KERN_INFO "globalmem is set to zero
    ");
                break;
    
            default:
                return -EINVAL; // not supported
        }
    
        return 0;
    }
    
    // file operations struct
    static const struct file_operations globalmem_fops = {
        .owner = THIS_MODULE,
        .llseek = globalmem_llseek,
        .read = globalmem_read,
        .write = globalmem_write,
        .unlocked_ioctl = globalmem_ioctl,
        .open = globalmem_open,
        .release = globalmem_release,
    };
    
    // init and add cdev struct
    static void globalmem_setup_cdev(struct globalmem_dev * dev, int index)
    {
        int err;
        int devno = MKDEV(globalmem_major, 0);
    
        cdev_init(&dev->cdev, &globalmem_fops);
        err = cdev_add(&dev->cdev, devno, 1);
        if (err)
            printk(KERN_NOTICE "Error %d adding globalmem", err);
    }
    
    // globalmem device init function
    int globalmem_init(void)
    {
        int result;
        dev_t devno = MKDEV(globalmem_major, 0);
    
            // apply globalmem device kernel region
        if (globalmem_major)
            result = register_chrdev_region(devno, 1, "globalmem");
        else {
                // get major no dynamically
            result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
            globalmem_major = MAJOR(devno);
        }
    
        if (result < 0)
            return result;
    
            // apply device struct memory
        globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
        if (!globalmem_devp) {
            result = - ENOMEM;
            goto fail_malloc;
        }
    
        memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
        globalmem_setup_cdev(globalmem_devp, 0);
    
        return 0;
    
      fail_malloc:
        unregister_chrdev_region(devno, 1);
        return result;
    }
    
    // globalmem device exit function
    void globalmem_exit(void)
    {
        // del cdev struct
        cdev_del(&globalmem_devp->cdev); 
        // free device struct memory
        kfree(globalmem_devp); 
        // unregister device region
        unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); 
    }
    
    module_param(globalmem_major, int, S_IRUGO);
    module_init(globalmem_init);
    module_exit(globalmem_exit);
    
    MODULE_AUTHOR("TT <TT@idle.com>");
    MODULE_LICENSE("Dual BSD/GPL");
  • 相关阅读:
    程序是怎样跑起来的 第三章
    C#4.5-4.7学习总结
    第二周学习总结
    程序是如何跑起来的 第二章
    第一章读后感
    师生关系读后感
    C#学习总结
    我与计算机
    读《程序怎样跑起来》第一章有感
    读师生关系有感
  • 原文地址:https://www.cnblogs.com/aqing1987/p/4463372.html
Copyright © 2011-2022 走看看