• 字符设备驱动程序实例


    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     }
    ~           

  • 相关阅读:
    阿里云ecs环境配置
    linux下Nginx安装Zend Optimizer组件步骤
    phpcms 按价格、按销量、按时间等排序实现思路
    云服务器 ECS Linux Web 环境配置站点的方法
    CentOS7安装和配置FTP
    Centos7安装SVN
    ExtJs桌面组件(DeskTop)
    jsapi支付,提示redirect_uri 参数错误
    php判断来源网址地址并且限制非法来源
    php正则表达式获取表格内容
  • 原文地址:https://www.cnblogs.com/oracleloyal/p/5368225.html
Copyright © 2020-2023  润新知