zoukankan      html  css  js  c++  java
  • 《Linux设备驱动程序》第三版 scull编译笔记

    0 准备工作。

    0.0 系统环境:Ubuntu18.04.1 amd64。

    0.1 安装必要软件包

    sudo apt install build-essential bison flex libssl-dev libelf-dev
    

      

    1 下载内核源码,构建源码树

    sudo apt install linux-source-4.15.0 -y
    
    cd /usr/src/linux-source-4.15.0/
    sudo tar xf linux-source-4.15.0.tar.bz2
    
    cd linux-source-4.15.0/
    
    sudo make oldconfig
    
    sudo make prepare
    
    sudo make scripts
    

      

    2 编译驱动源码

    源码需要改动几处:

    copy_to_user()改为raw_copy_to_user();

    copy_from_user()改为raw_copy_from_user();

    init_MUTEX((&scull_device->sem);改为sema_init(&scull_device->sem, 1);

    make
    
    sudo insmod scull.ko
    
    sudo rmmod scull.ko
    

     

    附1:scull.c

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/slab.h>
    #include <linux/errno.h>
    #include <linux/types.h>
    #include <linux/cdev.h>
    #include <asm/uaccess.h>
    
    #include "scull.h"
    
    int scull_major = SCULL_MAJOR;
    int scull_minor = 0;
    
    module_param(scull_major, int, S_IRUGO);
    module_param(scull_minor, int, S_IRUGO);
    
    struct scull_dev *scull_device;
    
    int scull_trim(struct scull_dev *dev)
    {
        if (dev)
        {
            if (dev->data)
            {
                kfree(dev->data);
            }
            dev->data = NULL;
            dev->size = 0;
        }
        return 0;
    }
    
    int scull_open(struct inode *inode, struct file *filp)
    {
        struct scull_dev *dev;
    
        dev = container_of(inode->i_cdev, struct scull_dev, cdev);
        filp->private_data = dev;
    
        if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
        {
            if (down_interruptible(&dev->sem))
            {
                return -ERESTARTSYS;
            }
            scull_trim(dev);
            up(&dev->sem);
        }
    
        return 0;
    }
    
    int scull_release(struct inode *inode, struct file *filp)
    {
        return 0;
    }
    
    ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
    {
        struct scull_dev *dev = filp->private_data;
        ssize_t retval = 0;
    
        if (down_interruptible(&dev->sem))
        {
            return -ERESTARTSYS;
        }
        if (*f_pos >= dev->size)
        {
            goto out;
        }
        if (*f_pos + count > dev->size)
        {
            count = dev->size - *f_pos;
        }
    
        if (!dev->data)
        {
            goto out;
        }
    
        if (raw_copy_to_user(buf, dev->data + *f_pos, count))
        {
            retval = -EFAULT;
            goto out;
        }
    
        *f_pos += count;
        retval = count;
    
        out:
            up(&dev->sem);
            return retval;
    }
    
    ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
    {
        struct scull_dev *dev = filp->private_data;
        ssize_t retval = -ENOMEM;
    
        if (down_interruptible(&dev->sem))    
        {
            return -ERESTARTSYS; 
        }
    
        if (!dev->data)    
        {
            dev->data = kmalloc(SCULL_BUFFER_SIZE, GFP_KERNEL);
            if (!dev->data)
            {
                goto out;
            }
            memset(dev->data, 0, SCULL_BUFFER_SIZE);
         }
    
        if (count > SCULL_BUFFER_SIZE - dev->size)
        {
            count = SCULL_BUFFER_SIZE - dev->size;
        }
    
        if (raw_copy_from_user(dev->data + dev->size, buf, count))
        {
            retval = -EFAULT;
            goto out;
        }
        
        dev->size += count;
        retval = count;
    
        out:
            up(&dev->sem);
            return retval;
    }
    
    loff_t scull_llseek(struct file *filp, loff_t off, int whence)
    {
        struct scull_dev *dev = filp->private_data;
        loff_t newpos;
    
        switch(whence)
        {
            case 0:
                newpos = off;
                break;
            case 1:
                newpos = filp->f_pos + off;
                break;
            case 2:
                newpos = dev->size + off;
                break;
            default:
                return -EINVAL;
        }
        if (newpos < 0)
        {
            return -EINVAL;
        }
        filp->f_pos = newpos;
        return newpos;
    }
    
    struct file_operations scull_fops = {
        .owner = THIS_MODULE,
        .llseek = scull_llseek,
        .read = scull_read,
        .write = scull_write,
        .open = scull_open,
        .release = scull_release,    
    };
    
    void  scull_cleanup_module(void)
    {
        dev_t devno = MKDEV(scull_major, scull_minor);
    
        if (scull_device)
        {
            scull_trim(scull_device);
            cdev_del(&scull_device->cdev);
            kfree(scull_device);    
        }
        unregister_chrdev_region(devno, 1);
    }
    
    static void scull_setup_cdev(struct scull_dev *dev)
    {
        int err, devno = MKDEV(scull_major, scull_minor);
    
        cdev_init(&dev->cdev, &scull_fops);
        dev->cdev.owner = THIS_MODULE;
        dev->cdev.ops = &scull_fops;
        err = cdev_add(&dev->cdev, devno, 1);
    
        if (err)
        {
            printk(KERN_NOTICE "Error %d adding scull", err);
        }
    }
    
    static int __init scull_init_module(void)
    {
        int result;
        dev_t dev = 0;
    
        if (scull_major)    
        {
            dev = MKDEV(scull_major, scull_minor);
            result = register_chrdev_region(dev, 1, "scull");
        }
        else
        {
            result = alloc_chrdev_region(&dev, scull_minor, 1, "scull");
            scull_major = MAJOR(dev);
        }
        if (result < 0)
        {
            printk(KERN_WARNING "scull: can't get major %d
    ", scull_major);
            return result;
        }
    
        scull_device = kmalloc(sizeof(struct scull_dev), GFP_KERNEL);        
        if (!scull_device)
        {
            result = -ENOMEM;
            goto fail;
        }
        memset(scull_device, 0, sizeof(struct scull_dev));
    
        sema_init(&scull_device->sem, 1);
    
        scull_setup_cdev(scull_device);
    
        return 0;
    
        fail:
            scull_cleanup_module();
            return result;
    }
    
    module_init(scull_init_module);
    module_exit(scull_cleanup_module);
    
    MODULE_LICENSE("GPL");
    

      

    附2:scull.h

    #ifndef _SCULL_H
    #define _SCULL_H
    
    #define SCULL_MAJOR 0
    #define SCULL_BUFFER_SIZE PAGE_SIZE
    
    struct scull_dev {
        char *data;
        unsigned long size;
        struct semaphore sem;
        struct cdev cdev;
    };
    
    #endif
    

      

    附3:Makefile

     #sample driver module
    obj-m := scull.o
    KDIR = /root/linux-2.6.36.4/
    PWD:=$(shell pwd)
    INSTALLDIR=$(PWD)
    modules:
    	$(MAKE) -C /lib/modules/`uname -r`/build M=`pwd` modules
    clean:
    	rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions
    .PHONY:modules clean
    

      

  • 相关阅读:
    python 前置程序窗口,还原最小化的窗口
    GreenDao官方文档翻译(上)
    Android 使用Instrumentation进行界面的单元测试
    Android:View中的performClick()触发条件
    Java 单元测试(Junit)
    再看薄荷
    单例模式-Singleton
    Java 如何防止线程意外中止
    Java Error和Exception区别
    linux的进程1:rootfs与linuxrc
  • 原文地址:https://www.cnblogs.com/areful/p/10513769.html
Copyright © 2011-2022 走看看