zoukankan      html  css  js  c++  java
  • 字符设备驱动框架

    scull from 《Linux设备驱动程序》

    memdev.c

    /*
     * memdev.c
     * create at 2015/01/07
     * 字符设备驱动程序框架
     */
    #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/slab.h> #include <linux/cdev.h> #include <asm/io.h> #include <asm/uaccess.h> #include "memdev.h" static mem_major = MEMDEV_MAJOR; module_param(mem_major, int, S_IRUGO); /* 设备结构体指针 */ struct mem_dev *mem_devp; struct cdev cdev; /* 文件打开函数 */ int mem_open(struct inode *inode, struct file *filp) { struct mem_dev *dev; /* 获取次设备号 */ int num = MINOR(inode->i_rdev); if (num > MEMDEV_NR_DEVS) return -ENODEV; dev = &mem_devp[num]; filp->private_data = dev; return 0; } /* 文件释放函数 */ int mem_release(struct inode *inode, struct file *filp) { return 0; } /* 读函数 */ static ssize_t mem_read(struct file *filp, char __user *buf, size size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct mem_dev *dev = filp->private_data; /* 判断读位置是否有效 */ if (p >= MEMDEV_SIZE) return 0; if (count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; /*读数据到用户空间*/ if (copy_to_user(buf, (void*)(dev->data + p), count)) { ret = - EFAULT; } else { *ppos += count; ret = count; printk(KERN_INFO "read %u bytes(s) from %lu ", count, p); } return ret; } /*写函数*/ static ssize_t mem_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 mem_dev *dev = filp->private_data; /*获得设备结构体指针*/ /*分析和获取有效的写长度*/ if (p >= MEMDEV_SIZE) return 0; if (count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; /*从用户空间写入数据*/ if (copy_from_user(dev->data + p, buf, count)) ret = - EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO "written %u bytes(s) from %lu ", count, p); } return ret; } /* seek文件定位函数 */ static loff_t mem_llseek(struct file *filp, loff_t offset, int whence) { loff_t newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = offset; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + offset; break; case 2: /* SEEK_END */ newpos = MEMDEV_SIZE -1 + offset; break; default: /* can't happen */ return -EINVAL; } if ((newpos<0) || (newpos>MEMDEV_SIZE)) return -EINVAL; filp->f_pos = newpos; return newpos; } /*文件操作结构体*/ static const struct file_operations mem_fops = { .owner = THIS_MODULE, .llseek = mem_llseek, .read = mem_read, .write = mem_write, .open = mem_open, .release = mem_release, }; /*设备驱动模块加载函数*/ static int memdev_init(void) { int result; int i; dev_t devno = MKDEV(mem_major, 0); /* 静态申请设备号*/ if (mem_major) result = register_chrdev_region(devno, 2, "memdev"); else /* 动态分配设备号 */ { result = alloc_chrdev_region(&devno, 0, 2, "memdev"); mem_major = MAJOR(devno); } if (result < 0) return result; /*初始化cdev结构*/ cdev_init(&cdev, &mem_fops); cdev.owner = THIS_MODULE; cdev.ops = &mem_fops; /* 注册字符设备 */ cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS); /* 为设备描述结构分配内存*/ mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL); if (!mem_devp) /*申请失败*/ { result = - ENOMEM; goto fail_malloc; } memset(mem_devp, 0, sizeof(struct mem_dev)); /*为设备分配内存*/ for (i=0; i < MEMDEV_NR_DEVS; i++) { mem_devp[i].size = MEMDEV_SIZE; mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL); memset(mem_devp[i].data, 0, MEMDEV_SIZE); } return 0; fail_malloc: unregister_chrdev_region(devno, 1); return result; } /*模块卸载函数*/ static void memdev_exit(void) { cdev_del(&cdev); /*注销设备*/ kfree(mem_devp); /*释放设备结构体内存*/ unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/ } MODULE_AUTHOR("Elvalad"); MODULE_LICENSE("GPL"); module_init(memdev_init); module_exit(memdev_exit);

    memdev.h

    /*
     * memdev.h
     * create at 2015/01/07
     */
    
    #ifndef _MEMDEV_H_
    #define _MEMDEV_H_
    
    #ifndef MEMDEV_MAJOR
    #define MEMDEV_MAJOR 260 /*预设的mem的主设备号*/
    #endif
    
    #ifndef MEMDEV_NR_DEVS
    #define MEMDEV_NR_DEVS 2 /*设备数*/
    #endif
    
    #ifndef MEMDEV_SIZE
    #define MEMDEV_SIZE 4096
    #endif
    
    /*mem设备描述结构体*/
    struct mem_dev
    {
      char *data;
      unsigned long size;
    };
    
    #endif /* _MEMDEV_H_ */

    Makefile

    ifneq ($(KERNELRELEASE),)
    obj-m:=memdev.o
    else
    KERNELDIR:=/lib/modules/$(shell uname -r)/build
    PWD:=$(shell pwd)
    
    default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    
    clean:
        rm -rf *.o *.mod.c *.mod.o *.ko
    endif

    memdevtest.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <unistd.h>
    #include <linux/i2c.h>
    #include <linux/fcntl.h>
    
    int main()
    {
        int fd;
        //写入memdev设备的内容
        char buf[]="it's funny!!!";
        //memdev设备的内容读入到该buf中
        char buf_read[4096]; 
         
        if((fd=open("/dev/memdev",O_RDWR))==-1) //打开memdev设备
        printf("open memdev ERROR
    ");
        else
        printf("open memdev SUCCESS!
    ");
        
        printf("buf is %s
    ",buf);
        write(fd,buf,sizeof(buf)); //把buf中的内容写入memdev设备
        lseek(fd,0,SEEK_SET); //把文件指针重新定位到文件开始的位置
        read(fd,buf_read,sizeof(buf)); //把memdev设备中的内容读入到buf_read中
        printf("buf_read is %s
    ",buf_read);
        
        return 0;
    }

    编译字符驱动之后会产生一个memdev.ko文件,然后执行

    sudo insmod memdev.ko
    lsmod 或者 cat /proc/devices 查看ko是否插入

    创建设备节点

    sudo mknod memdev c 260 0

    编译memdevtest.c程序测试这个字符设备驱动

    gcc -o memdevtest memdevtest.c

    执行此测试程序,因为设备文件建立在/dev目录下,在执行此程序时因为要打开设备文件,所以需要root权限下执行。

  • 相关阅读:
    记忆点
    数组的操作
    console.log()中的运算与打印事件
    ie9上传后下载json
    mysql使用on duplicate key update批量更新数据
    vue 弹出菜单
    mysql备份脚本
    uniapp+nodejs微信支付小程序版
    mycat初体验
    vscode格式化html标签属性不换行(vetur插件)
  • 原文地址:https://www.cnblogs.com/elvalad/p/4279562.html
Copyright © 2011-2022 走看看