zoukankan      html  css  js  c++  java
  • 2017-2018-1 20155305 实验四 外设驱动程序设计

    2017-2018-1 20155305 实验四 外设驱动程序设计

    实验目的

    • 学习资源中全课中的“hqyj.嵌入式Linux应用程序开发标准教程.pdf”中的第十一章
    • 在Ubuntu完成资源中全课中的“hqyj.嵌入式Linux应用程序开发标准教程.pdf”中的第十一章的test试验
    • 提交编译,加载模块,卸载模块,测试运行的截图

    实验步骤

    1.阅读hqyj.嵌入式Linux应用程序开发标准教程.pdf中的十一章,记录学习笔记,如下:

    2.在虚拟机中创建文件夹
    3.根据书第十一章最后关于字符设备的test实验中代码,将test_drv.c,test.c,Makefile,test_drv_load,test_drv_unload文件敲入,保存在文件夹内。
    test_drv.c代码如下所示:

    /* test_drv.c */

    #include <linux/module.h>
    
    #include <linux/init.h>
    
    #include <linux/fs.h>
    
    #include <linux/kernel.h>
    
    #include <linux/slab.h>
    
    #include <linux/types.h>
    
    #include <linux/errno.h>
    
    #include <linux/cdev.h>
    
    #include <asm/uaccess.h>
    
    #define     TEST_DEVICE_NAME    "test_dev"
    
    #define     BUFF_SZ         1024
    
    
    
    static struct cdev test_dev;
    
    unsigned int major =0;
    
    static char *data = NULL;
    
    
    
    
    
    static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos);
    
    static ssize_t test_write(struct file *file,const char *buffer, size_t count,loff_t *f_pos);
    
    static int test_open(struct inode *inode, struct file *file);
    
    static int test_release(struct inode *inode,struct file *file);
    
    
    
    static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos)
    
    {
    
        int len;
    
        if (count < 0 )
    
        {
    
            return -EINVAL;
    
        }
    
        len = strlen(data);
    
        count = (len > count)?count:len;
    
        if (copy_to_user(buf, data, count))
    
        {
    
            return -EFAULT;
    
        }
    
        return count;
    
    }
    
    
    
    static ssize_t test_write(struct file *file, const char *buffer, size_t count, loff_t *f_pos)
    
    {
    
        if(count < 0)
    
        {
    
            return -EINVAL;
    
        }
    
        memset(data, 0, BUFF_SZ);
    
        count = (BUFF_SZ > count)?count:BUFF_SZ;
    
        if (copy_from_user(data, buffer, count))
    
        {
    
            return -EFAULT;
    
        }
    
        return count;
    
    }
    
    
    
    static int test_open(struct inode *inode, struct file *file)
    
    {
    
        printk("This is open operation
    ");
    
        data = (char*)kmalloc(sizeof(char) * BUFF_SZ, GFP_KERNEL);
    
        if (!data)
    
        {
    
            return -ENOMEM;
    
        }
    
        memset(data, 0, BUFF_SZ);
    
        return 0;
    
    }
    
    
    
    static int test_release(struct inode *inode,struct file *file)
    
    {
    
        printk("This is release operation
    ");
    
        if (data)
    
        {
    
            kfree(data);
    
            data = NULL;
    
        }
    
        return 0;
    
    }
    
    
    
    static void test_setup_cdev(struct cdev *dev, int minor,
    
            struct file_operations *fops)
    
    {
    
        int err, devno = MKDEV(major, minor);
    
        
    
        cdev_init(dev, fops);
    
        dev->owner = THIS_MODULE;
    
        dev->ops = fops;
    
        err = cdev_add (dev, devno, 1);
    
        if (err)
    
        {
    
            printk (KERN_NOTICE "Error %d adding test %d", err, minor);
    
        }
    
    }
    
    
    static struct file_operations test_fops = 
    
    {
    
        .owner   = THIS_MODULE,
    
        .read    = test_read,
    
        .write   = test_write,
    
        .open    = test_open,
    
        .release = test_release,
    
    };
    
    
    
    int init_module(void)
    
    {
    
        int result;
    
        dev_t dev = MKDEV(major, 0);
    
    
    
        if (major)
    
        {
    
            result = register_chrdev_region(dev, 1, TEST_DEVICE_NAME);
    
        }
    
        else 
    
        {
    
            result = alloc_chrdev_region(&dev, 0, 1, TEST_DEVICE_NAME);
    
            major = MAJOR(dev);
    
        }
    
    
    
        if (result < 0) 
    
        {
    
            printk(KERN_WARNING "Test device: unable to get major %d
    ", major);
    
            return result;
    
        }
    
    
    
        test_setup_cdev(&test_dev, 0, &test_fops);
    
        printk("The major of the test device is %d
    ", major);
    
        return 0;
    
    }
    
    void cleanup_module(void) 
    
    {
    
        cdev_del(&test_dev);
    
        unregister_chrdev_region(MKDEV(major, 0), 1);
    
        printk("Test device uninstalled
    ");
    
    }
    

    test.c代码如下:

    /* test.c */
    
    
    
    #include <stdio.h>
    
    #include <stdlib.h>
    
    #include <string.h>
    
    #include <sys/stat.h>
    
    #include <sys/types.h>
    
    #include <unistd.h>
    
    #include <fcntl.h>
    
    #define     TEST_DEVICE_FILENAME        "/dev/test_dev"
    
    #define     BUFF_SZ             1024
    
    
    
    int main()
    
    {
    
        int fd, nwrite, nread;
    
        char buff[BUFF_SZ];
    
    
    
        fd = open(TEST_DEVICE_FILENAME, O_RDWR);
    
        if (fd < 0)
    
        {
    
            perror("open");
    
            exit(1);
    
        }
    
            
    
        do
    
        {
    
            printf("Input some words to kernel(enter 'quit' to exit):");
    
            memset(buff, 0, BUFF_SZ);
    
            if (fgets(buff, BUFF_SZ, stdin) == NULL)
    
            {
    
                perror("fgets");
    
                break;
    
            }
    
            buff[strlen(buff) - 1] = '';
    
            
    
            if (write(fd, buff, strlen(buff)) < 0)
    
            {
    
                perror("write");
    
                break;
    
            }
    
            
    
            if (read(fd, buff, BUFF_SZ) < 0)
    
            {
    
                perror("read");
    
                break;
    
            }
    
            else
    
            {
    
                printf("The read string is from kernel:%s
    ", buff);
    
            }
    
            
    
        } while(strncmp(buff, "quit", 4));
    
        
    
        close(fd);
    
        exit(0);
    
    }
    

    Makefile内容如下:

    ifeq ($(KERNELRELEASE),)
    
    
    
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    
    
    
    PWD := $(shell pwd)
    
    
    
    modules:
    
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    
    
    
    modules_install:
    
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
    
    
    
    clean:
    
        rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
    
    
    
    .PHONY: modules modules_install clean
    
    
    
    else
    
        obj-m := test_drv.o
    
    endif
    

    test_drv_load脚本内容如下:

    #!/bin/sh
    module="test_drv"
    device="test_dev"
    mode="664"
    group="david"
    
    
    # remove stale nodes
    rm -f /dev/${device} 
    
    # invoke insmod with all arguments we got
    # and use a pathname, as newer modutils don't look in . by default
    /sbin/insmod -f ./$module.ko $* || exit 1
    
    major=`cat /proc/devices | awk "\$2=="$device" {print \$1}"`
    
    mknod /dev/${device} c $major 0
    
    # give appropriate group/permissions
    chgrp $group /dev/${device}
    chmod $mode  /dev/${device}
    

    test_drv_unload脚本内容如下:

    #!/bin/sh
    module="test_drv"
    device="test_dev"
    
    # invoke rmmod with all arguments we got
    /sbin/rmmod $module $* || exit 1
    
    # remove nodes
    rm -f /dev/${device}
    
    exit 0
    

    4.加载模块
    先给脚本文件增加可执行权限:chmod +x ./test_drv_load
    再以管理员身份运行加载脚本:sudo ./test_drv_load
    加载成功

    1. 编译运行test.c
      编译:gcc -o test test.c
      运行:./test
      根据提示输入学号信息

    2. 卸载模块
      先给脚本文件增加可执行权限:chmod +x ./test_drv_unload
      再以管理员身份运行加载脚本:sudo ./test_drv_unload

    实验中的问题及解决过程

    问题1:运行脚本时“open: Permission denied”
    解决:chmod +x ...(脚本名字)
    sudo ./被增添了可执行权限的脚本名字

    新学到的知识点

    重点学习字符设备驱动编程,了解分配设备号、设备注册、内核操作的相关函数的使用方法
    驱动硬件、驱动程序、内核模块的概念
    lsmod、rmmod、insmod、modprobe等指令的用法
    如何通过文件属性查看设备及其分类
    大致了解各驱动程序编程

  • 相关阅读:
    Zabbix5 Frame 嵌套
    Zabbix5 对接 SAML 协议 SSO
    CentOS7 安装 Nexus
    CentOS7 安装 SonarQube
    GitLab 后台修改用户密码
    GitLab 查看版本号
    GitLab Admin Area 500 Error
    Linux 安装 PostgreSQL
    Liger ui grid 参数
    vue.js 是一个怪东西
  • 原文地址:https://www.cnblogs.com/20155305ql/p/7954035.html
Copyright © 2011-2022 走看看