栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux驱动学习,实现简单的字符设备驱动?基于ubuntu16.04,VirtualBox6。从入门到放弃

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux驱动学习,实现简单的字符设备驱动?基于ubuntu16.04,VirtualBox6。从入门到放弃

Linux驱动学习
  • Linux驱动学习(一、在Ubuntu主机实现)
  • 一、需要的文件
    • 1、驱动源代码hello.c
    • 2、Makefile
    • 3、应用程序app.c
  • 二、加载驱动
  • 三、执行app

Linux驱动学习(一、在Ubuntu主机实现)
Linux驱动学习(二、在Ubuntu主机的QEMU模拟平台实现)

Linux驱动学习(一、在Ubuntu主机实现)

这次学习会遇到很多问题:1、gcc版本不同导致的问题
2、编译平台不同
3、我不知道什么原因的原因
4、这篇教程没写完 希望能给大家提供一点思路,作者是个菜鸟,不知道是在ubuntu上实现还是qemu,如果在qemu上运行,就用交叉编译生成文件,再复制到文件系统中再去insmod。

这篇先简单介绍在ubuntu主机上测试驱动

一、需要的文件 1、驱动源代码hello.c

printk打印的东西不要全复制成一样的了
使用自动创建设备节点的方法,不用每次mknod了
调用了 __register_chrdev(major, 0, 256, name, fops) 函数: 这个函数不只帮我们注册了设备号,还帮我们做了cdev 的初始化以及cdev 的注册;

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int major;
static int minor = 0;
static int hello_open(struct inode *inode, struct file *file);
static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg);  

static dev_t devno;
static struct class *cls;
static struct device *test_device;

static char test_buff[128]; 

struct file_operations hello_fileop = {     
    .owner = THIS_MODULE,    
    .open = hello_open,
    .read = hello_read,
    .write = hello_write,
    .unlocked_ioctl = hello_ioctl
};


static int hello_open(struct inode *inode, struct file *file)
{
    printk(KERN_alert"|----------------|n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|   hello_open   |n");
    printk(KERN_alert"|      *OvO*     |n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|----------------|n");
    return 0;
}

static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    strcat(test_buff, " from kernel!");
    if (0 != copy_to_user(buf, test_buff, strlen(test_buff))) {
        printk(KERN_alert"ERROR:  read error!");
    }
    printk(KERN_alert"|----------------|n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|   hello_read   |n");
    printk(KERN_alert"|      *O3O*     |n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|----------------|n");
    return 0;
}

static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    memset(test_buff, 0, sizeof(test_buff));
    if (0 != copy_from_user(test_buff, buf, count)) {
        printk(KERN_alert"ERROR:  write error!");
    }
    printk(KERN_alert"|----------------|n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|   hello_write  |n");
    printk(KERN_alert"|      *OxO*     |n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|----------------|n");
    return 0;
}

  
long  hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    if (cmd == 1) {
    	printk(KERN_alert"|----------------|n");
    	printk(KERN_alert"|                |n");
    	printk(KERN_alert"|   hello_ioctl  |n");
    	printk(KERN_alert"|      CMD 1     |n");
    	printk(KERN_alert"|     success    |n");
    	printk(KERN_alert"|----------------|n");
        return 0;
    }
    if (cmd == 4) {
        printk(KERN_alert"|----------------|n");
    	printk(KERN_alert"|                |n");
    	printk(KERN_alert"|   hello_ioctl  |n");
    	printk(KERN_alert"|      CMD 2     |n");
    	printk(KERN_alert"|     success    |n");
    	printk(KERN_alert"|----------------|n");
        return 0;
    }
    if (cmd == 3) {
        printk(KERN_alert"|----------------|n");
    	printk(KERN_alert"|                |n");
    	printk(KERN_alert"|   hello_ioctl  |n");
    	printk(KERN_alert"|      CMD 3     |n");
    	printk(KERN_alert"|     success    |n");
    	printk(KERN_alert"|----------------|n");
        return 0;
    }

    printk("hello_ioctl errorn");
    return -EFAULT;
}  
        
static int hello_init(void)
{
    printk(KERN_alert"|----------------|n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|   hello_init   |n");
    printk(KERN_alert"|      *OvO*     |n");


    major = register_chrdev(0, "hello", &hello_fileop);
    devno = MKDEV(major, minor);
    cls = class_create(THIS_MODULE, "hello_class");

    if (IS_ERR(cls)) {
        unregister_chrdev(major, "hello");
        printk(KERN_alert"|   IS_ERR(cls)  |n");
        printk(KERN_alert"|----------------|n");
        return -EBUSY;
    }

    test_device = device_create(cls, NULL, devno, NULL, "hello");

    if (IS_ERR(test_device)) {
        class_destroy(cls);
        unregister_chrdev(major, "hello");
        printk(KERN_alert"| IS_ERR(device)-|n");
        printk(KERN_alert"|----------------|n");
        return -EBUSY;
    }
    printk(KERN_alert"|      steve     |n");
    printk(KERN_alert"|----------------|n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_alert"|----------------|n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|   hello_exit   |n");
    printk(KERN_alert"|      mO.Om     |n");
    printk(KERN_alert"|                |n");
    printk(KERN_alert"|----------------|n");

    device_destroy(cls, devno);
    class_destroy(cls);
    unregister_chrdev(major, "hello");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("STEVE"); 
2、Makefile
KERN_DIR = /lib/modules/$(shell uname -r)/build

all:
	make -C $(KERN_DIR) M=`pwd` modules

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order

obj-m    += hello.o
3、应用程序app.c
#include 
#include 
#include 
#include  
#include 

#include 
#include 
 
int main(int argc, char **argv)
{
    int fd;
    int file;
    int val = 1;
    char data[256] = {0};
    fd = open("/dev/hello", O_RDWR);
    //file = open("hellofile", O_RDWR);
    
    if (fd == -1) {
        printf("0-can't open...n");
        exit(-1);
    } else {
        printf("1-open ok...use 'dmesg | tail -12' to see 12 lines printkn");
	int retval;
        retval = write(fd, "steve", 6);
        if (retval == -1) {
            perror("write errorn");
            close(fd);
            exit(-1);
        } else {
            printf("2-write ok...use 'vi 文件名' to see see what you writen");
            retval = read(fd, data, 10);
            if (retval == -1) {
                perror("read errorn");
                close(fd);
                exit(-1);
            }
            printf("3-read ok: %sn", data);

	    unsigned int CMD;
    	    printf("请输入CMD:");
    	    scanf("%d", &CMD);  

	    if(CMD==2){
		retval = ioctl(fd, 4, 0);
	    }else{
		retval = ioctl(fd, CMD, 0);
	    }
            
            if (retval == -1) {
                perror("ioctl errorn");
                close(fd);
                exit(-1);
            }
            printf("4-ioctl CMD%d okn",CMD);
            close(fd);
        }

    }

    exit(EXIT_SUCCESS);
    return 0;
}
二、加载驱动


app.c hello.c Makefile是必需的,hellofile只是我加上去的测试文件

先make出hello.ko文件

make

make执行成功,如下图所示
如果是要在上一篇linux教程中的qemu中测试驱动,那就要给make 加上一些参数 比如在makefile中这样写:make -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-

insmod命令功能: 用于将指定模块加载到内核中

 sudo insmod hello.ko

insmod成功,输出init函数打印的东东

dmesg | tail -6


查看当前有哪些设备

cat /proc/devices

可以看到字符设备已经有hello了,我这自动分配为243号

ls -l /dev/hello

hello.c代码已经帮我们生成好了/dev/hello

三、执行app

在应用层调用ioctl的时候,当传入的cmd=2时会出现错误。
ioctl返回值为-1。错误号errno:14, bad address。

上网查阅才知道需要使用_IOWR等宏来生成cmd命令,而不能自己写。
虽然自己写也可以,但很有可能和系统的其他cmd命令冲突。刚好当ioctl的cmd=2使就出现了错误。但我先用偏方实现了。以后再改

https://mjmwired.net/kernel/documentation/ioctl-number.txt

生成可执行文件

gcc -o app app.c

执行

sudo ./app


查看最近30条记录

dmesg | tail -30

跑路,明天再写
试一下把上面的驱动移植到qemu中,
因为第二次作业做的只是雏形,不适合在工程下使用,可能因为少了很多东西?所以下面遇到一些问题不好解决

把刚才的文件生成arm端的hello.ko 和 app,复制到qemu的文件系统中,发现报错 out-of-tree 原因是 其中,内核配置项:

CONFIG_MODULE_SIG=y
表示开启了签名机制。

CONFIG_MODULE_SIG_FORCE=y
则模块必须有正确的签名才能正常使用。

CONFIG_MODULE_SIG_ALL=y
内核在编译的时候,会主动去给模块签名。
这次init 并没有自动创建/dev/hello 可能是因为busybox配置?
当我给这个系统加读写权限后(mount -o remount rw /),loading out-of-tree 报错又没了。。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/599325.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号