zoukankan      html  css  js  c++  java
  • 字符驱动

    设备三种类型

    1、字符设备

    2、块设备

    3、网络设备



    字符设备:在IO传输过程中以字符为单位,传输速率较慢

    内核代码:demo_chr_dev.c

     1 #include <linux/module.h>//define THIS_MODULE
     2 #include <linux/kernel.h>
     3 #include <linux/fs.h>  //define file_operations
     4 #include <linux/cdev.h>//define cdev 
     5 
     6 static struct cdev chr_dev;
     7 static dev_t ndev;//char device main id and sub id
     8 
     9 static int chr_open(struct inode * nd, struct file *filp)
    10 {
    11     int major = MAJOR(nd->i_rdev);
    12     int minor = MINOR(nd->i_rdev);
    13     printk("char_open, major=%d,minor=%d
    ", major, minor);
    14     return 0;
    15 };
    16 
    17 static ssize_t chr_read(struct file *f, char __user *u, size_t sz, loff_t *off)
    18 {
    19     printk("In the char_read() function!
    ");
    20     return 0;
    21 }
    22 
    23 struct file_operations chr_ops =
    24 {
    25     .owner = THIS_MODULE,
    26     .open = chr_open,
    27     .read = chr_read,
    28 };
    29 
    30 
    31 static int demo_init(void)
    32 {
    33     int ret;
    34     cdev_init(&chr_dev, &chr_ops);
    35     ret = alloc_chrdev_region(&ndev, 0, 1, "chr_dev");
    36     if(ret < 0)
    37         return ret;
    38     printk("demo_init(): major=%d,minor=%d
    ", MAJOR(ndev), MINOR(ndev));
    39     ret = cdev_add(&chr_dev, ndev, 1);
    40     if(ret < 0)
    41         return ret;
    42     return 0;
    43 }
    44 
    45 static void demo_exit(void)
    46 {
    47     printk("Removing char_dev module...
    ");
    48     cdev_del(&chr_dev);
    49     unregister_chrdev_region(ndev, 1);
    50 }
    51 
    52 module_init(demo_init);
    53 module_exit(demo_exit);
    54  
    55 
    56 MODULE_LICENSE("GPL");
    57 MODULE_AUTHOR("Sain");
    58 MODULE_DESCRIPTION("a char device driver as an example");

    //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 Module* modules*
    .PHONY: modules modules_install clean
    else
    obj-m := demo_chr_dev.o
    endif

    整个代码相较于hello world 主要增加了下面两个响应函数

    .open = chr_open,
    .read = chr_read,

    动态加载内核模块

    sudo insmod demo_chr_dev.ko

    dmesg能看到打出来相应日志了:

    [ 4833.212757] demo_init(): major=245,minor=0

    驱动测试程序

     1 //main.c
     2 
     3 
     4 #include <stdio.h>
     5 #include <fcntl.h>   //define O_RDONLY  
     6 #include <unistd.h>  //use posix function open read
     7 #define CHR_DEV "/dev/chr_dev"
     8 int main(void){
     9 
    10     int ret;
    11     char buff[32]={0};
    12     int fd = open(CHR_DEV, O_RDONLY | O_NDELAY);
    13     if(fd < 0){
    14         printf("open file %s failed
    ", CHR_DEV);
    15         return -1;
    16     }
    17 
    18     read(fd,buff,32);
    19     printf("read:[%s]", buff);
    20     close(fd);
    21     return 0;
    22 
    23 }

    gcc main.c -o main( 注意:不要gcc -c main.c -o main,加上-c完全时另外一个意思了)

    比较坑的是,直接执行./main 函数会提示打开失败

    还要根据设备号信息用mknod 命令在系统的/dev/目录创建新的设备节点

    ret = alloc_chrdev_region(&ndev, 0, 1, "chr_dev");

    根据前面的log创建设备节点sudo mknod chr_dev c 245 0

    ninjame@ubuntu1604:/dev$ ls -l chr_dev
    crw-r--r-- 1 root root 245, 2 9月   1 00:13 chr_dev

    重新执行./main

     可以看到应用程序成功调用到了设备驱动程序实现的函数

    [ 4833.212757] demo_init(): major=245,minor=0
    [ 5069.412260] char_open, major=245,minor=0
    [ 5069.412269] In the char_read() function!

    ps:

    1、实际中发现创建节点的名字可以随意 ,只要主设备号、次设备号对上就可以

    sudo mknod chr_devmode c 245 0  也是可以的

    2、测试代码open 函数在打开失败时是完全不会调到内核函数的

    chr_open 函数不存在出错分支,可见内核的调用和我们普通调用函数还是有很大区别的

    static int chr_open(struct inode * nd, struct file *filp)
    {
        int major = MAJOR(nd->i_rdev);
        int minor = MINOR(nd->i_rdev);
        printk("char_open, major=%d,minor=%d
    ", major, minor);
        return 0;
    };
  • 相关阅读:
    【转】myeclipse设置优化+快捷命令大全
    记昨日参加南天竺饶老师回访的一些感触点
    [zz]程序猿,你今天装B了没?
    什么是CGI
    Agile Tour——敏捷,在厦门落地 笔记小结
    用按键精灵来自动投票
    win7下安装matlab,启动后提示VC++Runtime Library错误 runtime error!
    单次扫描完成二值图连通区域标记
    6.3.2 最小支撑树树Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind
    用Java HashMap做对象Cache时要注意一点
  • 原文地址:https://www.cnblogs.com/hixin/p/7461270.html
Copyright © 2011-2022 走看看