zoukankan      html  css  js  c++  java
  • 字符设备驱动程序实例

    1:memdev.h

      1 #ifndef MEMDEV_H_
      2 #define MEMDEV_H_
      3 #ifndef MEMDEV_MAJOR
      4 #define MEMDEV_MAJOR 179 /*预设的mem的主设备号*/
      5 #endif
      6
      7 #ifndef MEMDEV_NR_DEVS
      8 #define MEMDEV_NR_DEVS 2 /*设备数*/
      9 #endif
     10
     11 #ifndef MEMDEV_SIZE
     12 #define MEMDEV_SIZE 4096
     13 #endif
     14
     15 /*mem设备描述结构体*/
     16 struct mem_dev
     17 {
     18   char *data;
     19   unsigned long size;
     20 };
     21 #endif
    ~          

    2:memdev.c

      #include <linux/module.h>
      2   #include <linux/module.h>
      3   #include <linux/kernel.h>
      4   #include <linux/init.h>
      5   #include <linux/fs.h>
      6   #include <linux/cdev.h>
      7   #include <linux/device.h>
      8   #include <asm/uaccess.h>
      9   #include <linux/slab.h>
     10   #include"memdev.h"
     11     static  int mem_major = MEMDEV_MAJOR;
     12
     13     module_param(mem_major, int, S_IRUGO);
     14
     15     struct mem_dev *mem_devp; /*设备结构体指针*/
     16
     17     struct cdev cdev;
     18
     19     /*文件打开函数*/
     20     int mem_open(struct inode *inode, struct file *filp)
     21     {
     22         struct mem_dev *dev;
     23
     24         /*获取次设备号*/
     25         int num = MINOR(inode->i_rdev);
     26
     27         if (num >= MEMDEV_NR_DEVS)
     28                 return -ENODEV;
     29         dev = &mem_devp[num];
     30
     31         /*将设备描述结构指针赋值给文件私有数据指针*/
     32         filp->private_data = dev;
     33
     34         return 0;
     35     }
     36
     37     /*文件释放函数*/
     38     int mem_release(struct inode *inode, struct file *filp)
     39     {
     40       return 0;
     41     }
     42
     43     /*读函数*/
     44     static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, lof    f_t *ppos)
     45     {
     46       unsigned long p = *ppos; /*记录文件指针偏移位置*/
     47       unsigned int count = size; /*记录需要读取的字节数*/
     48       int ret = 0; /*返回值*/
     49       struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
     50
     51       /*判断读位置是否有效*/
     52       if (p >= MEMDEV_SIZE) /*要读取的偏移大于设备的内存空间*/
     53         return 0;
     54       if (count > MEMDEV_SIZE - p) /*要读取的字节大于设备的内存空间*/
     55         count = MEMDEV_SIZE - p;
     57       /*读数据到用户空间:内核空间->用户空间交换数据*/
     58       if (copy_to_user(buf, (void*)(dev->data + p), count))
     59       {
     60         ret = - EFAULT;
     61       }
     62       else
     63       {
     64         *ppos += count;
     65         ret = count;
     66
     67         printk(KERN_INFO "read %d bytes(s) from %d ", count, p);
     68       }
     69
     70       return ret;
     71     }
     72
     73     /*写函数*/
     74     static ssize_t mem_write(struct file *filp, const char __user *buf, size_t si    ze, loff_t *ppos)
     75     {
     76       unsigned long p = *ppos;
     77       unsigned int count = size;
     78       int ret = 0;
     79       struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
     80
     81       /*分析和获取有效的写长度*/
     82       if (p >= MEMDEV_SIZE)
     83         return 0;
     84       if (count > MEMDEV_SIZE - p) /*要写入的字节大于设备的内存空间*/
     85         count = MEMDEV_SIZE - p;
     86
     87       /*从用户空间写入数据*/
     88       if (copy_from_user(dev->data + p, buf, count))
     89         ret = - EFAULT;
     90       else
     91       {
     92         *ppos += count; /*增加偏移位置*/
     93         ret = count; /*返回实际的写入字节数*/
     94
     95         printk(KERN_INFO "written %d bytes(s) from %d ", count, p);
     96       }
     97
     98       return ret;
     99     }
    100
    101     /* seek文件定位函数 */
    102     static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
    103     {
            loff_t newpos;
    105
    106         switch(whence) {
    107           case 0: /* SEEK_SET */ /*相对文件开始位置偏移*/
    108             newpos = offset; /*更新文件指针位置*/
    109             break;
    110
    111           case 1: /* SEEK_CUR */
    112             newpos = filp->f_pos + offset;
    113             break;
    114
    115           case 2: /* SEEK_END */
    116             newpos = MEMDEV_SIZE -1 + offset;
    117             break;
    118
    119           default: /* can't happen */
    120             return -EINVAL;
    121         }
    122         if ((newpos<0) || (newpos>MEMDEV_SIZE))
    123             return -EINVAL;
    124
    125         filp->f_pos = newpos;
    126         return newpos;
    127
    128     }
    129
    130     /*文件操作结构体*/
    131     static const struct file_operations mem_fops =
    132     {
    133       .owner = THIS_MODULE,
    134       .llseek = mem_llseek,
    135       .read = mem_read,
    136       .write = mem_write,
    137       .open = mem_open,
    138       .release = mem_release,
    139     };
    140
    141     /*设备驱动模块加载函数*/
    142     static int memdev_init(void)
    143     {
    144       int result;
    145       int i;
    146   dev_t devno = MKDEV(mem_major, 0);
    148
    149        /* 申请设备号,当xxx_major不为0时,表示静态指定;当为0时,表示动态申请*/
    150       /* 静态申请设备号*/
    151       if (mem_major)
    152         result = register_chrdev_region(devno, 2, "memdev");
    153       else /* 动态分配设备号 */
    154       {
    155         result = alloc_chrdev_region(&devno, 0, 2, "memdev");
    156         mem_major = MAJOR(devno); /*获得申请的主设备号*/
    157       }
    158
    159       if (result < 0)
    160         return result;
    161
    162      /*初始化cdev结构,并传递file_operations结构指针*/
    163       cdev_init(&cdev, &mem_fops);
    164       cdev.owner = THIS_MODULE; /*指定所属模块*/
    165       cdev.ops = &mem_fops;
    166
    167       /* 注册字符设备 */
    168       cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
    169
    170       /* 为设备描述结构分配内存*/
    171       mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
    172       if (!mem_devp) /*申请失败*/
    173       {
    174         result = - ENOMEM;
    175         goto fail_malloc;
    176       }
    177       memset(mem_devp, 0, sizeof(struct mem_dev));
    178
    179       /*为设备分配内存*/
    180       for (i=0; i < MEMDEV_NR_DEVS; i++)
    181       {
    182             mem_devp[i].size = MEMDEV_SIZE;
    183             mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
    184             memset(mem_devp[i].data, 0, MEMDEV_SIZE);
    185       }
    186
    187       return 0;

      fail_malloc:
    190       unregister_chrdev_region(devno, 1);
    191
    192       return result;
    193     }
    194
    195     /*模块卸载函数*/
    196     static void memdev_exit(void)
    197     {
    198       cdev_del(&cdev); /*注销设备*/
    199       kfree(mem_devp); /*释放设备结构体内存*/
    200       unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
    201     }
    202
    203     MODULE_AUTHOR("David Xie");
    204     MODULE_LICENSE("GPL");
    205
    206     module_init(memdev_init);
    207     module_exit(memdev_exit);
    makefile 编写:
    1 ifeq ($(KERNELRELEASE),)
      2 #KERNEL_DIR:=/home/archermind/zhaoxi/bsw_ww02_2016/kernel/cht
      3 KERNEL_DIR:=/usr/src/linux-headers-3.13.0-32-generic
      4 PWD:=$(shell pwd)
      5 modules:
      6     $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
      7 modules_install:
      8     $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install
      9 clean:
     10     rm -rf  .*.cmd *.ko  *.o modules.order  Module.symvers *mod.c
     11     .PHONY: modules modules_install clean
     12 else
     13     modules-objs := memdev.o
     14     obj-m := memdev.o
     15 endif
    ~           
    3:加载驱动:make

    sudo insmod memdev.ko(如果出现insmod: error inserting 'memdev.ko': -1 Device or resource busy)查看 cat /proc/devices设备号和自己注册的是不是存在冲突导致加载失败)

    修改头文件宏#define MEMDEV_MAJOR 主节点号

    在/sys/modules会出先设备文件->需要在/dev下创建节点号,mknod /dev/memdev0 c 主设备号 次设备号 (例如上述代码不休改,则是sudo mknod /dev/memdev0 c 179 0)

    用户空间的操作test.c

      1     #include <stdio.h>
      2
      3     int main()
      4     {
      5         FILE *fp0 = NULL;
      6         char Buf[4096];
      7
      8         /*初始化Buf*/
      9         strcpy(Buf,"Mem is char dev!");
     10         printf("BUF: %s ",Buf);
     11
     12         /*打开设备文件*/
     13         fp0 = fopen("/dev/memdev0","r+");
     14         if (fp0 == NULL)
     15         {
     16             printf("Open Memdev0 Error! ");
     17             return -1;
     18         }
     19
     20         /*写入设备*/
     21         fwrite(Buf, sizeof(Buf), 1, fp0);
     22
     23         /*重新定位文件位置(思考没有该指令,会有何后果)*/
     24         fseek(fp0,0,SEEK_SET);
     25
     26         /*清除Buf*/
     27         strcpy(Buf,"Buf is NULL!");
     28         printf("BUF: %s ",Buf);
     29
     30
     31         /*读出设备*/
     32         fread(Buf, sizeof(Buf), 1, fp0);
     33
     34         /*检测结果*/
     35         printf("BUF: %s ",Buf);
     36
     37         return 0;
     38
     39     }
    ~           

  • 相关阅读:
    Constants and Variables
    随想
    C#基础篇之语言和框架介绍
    Python基础19 实例方法 类方法 静态方法 私有变量 私有方法 属性
    Python基础18 实例变量 类变量 构造方法
    Python基础17 嵌套函数 函数类型和Lambda表达式 三大基础函数 filter() map() reduce()
    Python基础16 函数返回值 作用区域 生成器
    Python基础11 List插入,删除,替换和其他常用方法 insert() remove() pop() reverse() copy() clear() index() count()
    Python基础15 函数的定义 使用关键字参数调用 参数默认值 可变参数
    Python基础14 字典的创建修改访问和遍历 popitem() keys() values() items()
  • 原文地址:https://www.cnblogs.com/oracleloyal/p/5368225.html
Copyright © 2011-2022 走看看