• Linux符设备驱动编程


     加入内核源码树外

    ① 建立两个文件scull.cscull.h,以及Makefile文件

    Makefile文件

     

    ② 用make进行编译,生成scull.ko驱动程序模块

     

     ③ 把scull.ko模块加载到内核,并且查看scull.ko驱动

     

    ④ 查看当前设备使用的主设备号,主设备号为260

     

    ⑤ 首先应该在/dev/目录下创建与该驱动程序相对应的文件节点,查看创建好的驱动程序节点文件并修改scull的权限。

     

    ⑥ 编写test.c程序,来对驱动程序进行测试。编译并执行该程序

     

    移除驱动模块

     

    加入内核源码树里面

     ① 把驱动程序(模块程序)拷贝到内核源码树根目录下/drivers/char下

     

    ② 编译配置文件Kconfig,加入驱动选项,使之在make menuconfig的时候出现改模块选项

     

    ③ 在内核根目录下执行make menuconfig

     

    ④ 没有安装curses库,安装。

     

    ⑤ 在内核根目录下执行make menuconfig,找到驱动模块,设置启动为M

     

    ⑥ 在模块文件所在目录的Makefile中加入要编译的驱动模块文件

     

    ⑦  在源代码根目录linux下,执行make bzImage后执行make modules

     

    ⑧  在char目录下查看得知device1.ko已经存在

     

    ⑨  lsmod指令安装模块文件,再对驱动程序进行测试。编译并执行该程序

     

    代码:

     1 #ifndef _MEMDEV_H_
     2 #define _MEMDEV_H_
     3 
     4 #ifndef MEMDEV_MAJOR
     5 #define MEMDEV_MAJOR 260 /*预设的mem的主设备号*/
     6 #endif
     7 
     8 #ifndef MEMDEV_NR_DEVS
     9 #define MEMDEV_NR_DEVS 2 /*设备数*/
    10 #endif
    11 
    12 #ifndef MEMDEV_SIZE
    13 #define MEMDEV_SIZE 4096
    14 #endif
    15 
    16 /*mem设备描述结构体*/
    17 struct mem_dev 
    18 { 
    19   char *data; 
    20   unsigned long size; 
    21 };
    22 
    23 #endif /* _MEMDEV_H_ */
    scull.h
      1 #include <linux/module.h>
      2 #include <linux/types.h>
      3 #include <linux/fs.h>
      4 #include <linux/errno.h>
      5 #include <linux/mm.h>
      6 #include <linux/sched.h>
      7 #include <linux/init.h>
      8 #include <linux/cdev.h>
      9 #include <asm/io.h>
     10 #include <asm/switch_to.h>
     11 #include <asm/uaccess.h>
     12 #include <linux/slab.h>
     13 
     14 #include "scull.h"
     15 
     16 static int mem_major = MEMDEV_MAJOR;
     17 
     18 module_param(mem_major, int, S_IRUGO);
     19 
     20 struct mem_dev *mem_devp; /*设备结构体指针*/
     21 
     22 struct cdev cdev; 
     23 
     24 /*文件打开函数*/
     25 int mem_open(struct inode *inode, struct file *filp)
     26 {
     27     struct mem_dev *dev;
     28     
     29     /*获取次设备号*/
     30     int num = MINOR(inode->i_rdev);
     31 
     32     if (num >= MEMDEV_NR_DEVS) 
     33             return -ENODEV;
     34     dev = &mem_devp[num];
     35     
     36     /*将设备描述结构指针赋值给文件私有数据指针*/
     37     filp->private_data = dev;
     38     
     39     return 0; 
     40 }
     41 
     42 /*文件释放函数*/
     43 int mem_release(struct inode *inode, struct file *filp)
     44 {
     45   return 0;
     46 }
     47 
     48 /*读函数*/
     49 static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
     50 {
     51   unsigned long p = *ppos;
     52   unsigned int count = size;
     53   int ret = 0;
     54   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
     55 
     56   /*判断读位置是否有效*/
     57   if (p >= MEMDEV_SIZE)
     58     return 0;
     59   if (count > MEMDEV_SIZE - p)
     60     count = MEMDEV_SIZE - p;
     61 
     62   /*读数据到用户空间*/
     63   if (copy_to_user(buf, (void*)(dev->data + p), count))
     64   {
     65     ret = - EFAULT;
     66   }
     67   else
     68   {
     69     *ppos += count;
     70     ret = count;
     71     
     72     printk(KERN_INFO "read %d bytes(s) from %d
    ", count, p);
     73   }
     74 
     75   return ret;
     76 }
     77 
     78 /*写函数*/
     79 static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
     80 {
     81   unsigned long p = *ppos;
     82   unsigned int count = size;
     83   int ret = 0;
     84   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
     85   
     86   /*分析和获取有效的写长度*/
     87   if (p >= MEMDEV_SIZE)
     88     return 0;
     89   if (count > MEMDEV_SIZE - p)
     90     count = MEMDEV_SIZE - p;
     91     
     92   /*从用户空间写入数据*/
     93   if (copy_from_user(dev->data + p, buf, count))
     94     ret = - EFAULT;
     95   else
     96   {
     97     *ppos += count;
     98     ret = count;
     99     
    100     printk(KERN_INFO "written %d bytes(s) from %d
    ", count, p);
    101   }
    102 
    103   return ret;
    104 }
    105 
    106 /* seek文件定位函数 */
    107 static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
    108 { 
    109     loff_t newpos;
    110 
    111     switch(whence) {
    112       case 0: /* SEEK_SET */
    113         newpos = offset;
    114         break;
    115 
    116       case 1: /* SEEK_CUR */
    117         newpos = filp->f_pos + offset;
    118         break;
    119 
    120       case 2: /* SEEK_END */
    121         newpos = MEMDEV_SIZE -1 + offset;
    122         break;
    123 
    124       default: /* can't happen */
    125         return -EINVAL;
    126     }
    127     if ((newpos<0) || (newpos>MEMDEV_SIZE))
    128      return -EINVAL;
    129      
    130     filp->f_pos = newpos;
    131     return newpos;
    132 
    133 }
    134 
    135 /*文件操作结构体*/
    136 static const struct file_operations mem_fops =
    137 {
    138   .owner = THIS_MODULE,
    139   .llseek = mem_llseek,
    140   .read = mem_read,
    141   .write = mem_write,
    142   .open = mem_open,
    143   .release = mem_release,
    144 };
    145 
    146 /*设备驱动模块加载函数*/
    147 static int memdev_init(void)
    148 {
    149   int result;
    150   int i;
    151 
    152   dev_t devno = MKDEV(mem_major, 0);
    153 
    154   /* 静态申请设备号*/
    155   if (mem_major)
    156     result = register_chrdev_region(devno, 2, "memdev");
    157   else /* 动态分配设备号 */
    158   {
    159     result = alloc_chrdev_region(&devno, 0, 2, "memdev");
    160     mem_major = MAJOR(devno);
    161   } 
    162   
    163   if (result < 0)
    164     return result;
    165 
    166   /*初始化cdev结构*/
    167   cdev_init(&cdev, &mem_fops);
    168   cdev.owner = THIS_MODULE;
    169   cdev.ops = &mem_fops;
    170   
    171   /* 注册字符设备 */
    172   cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
    173    
    174   /* 为设备描述结构分配内存*/
    175   mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
    176   if (!mem_devp) /*申请失败*/
    177   {
    178     result = - ENOMEM;
    179     goto fail_malloc;
    180   }
    181   memset(mem_devp, 0, sizeof(struct mem_dev));
    182   
    183   /*为设备分配内存*/
    184   for (i=0; i < MEMDEV_NR_DEVS; i++) 
    185   {
    186         mem_devp[i].size = MEMDEV_SIZE;
    187         mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
    188         memset(mem_devp[i].data, 0, MEMDEV_SIZE);
    189   }
    190     
    191   return 0;
    192 
    193   fail_malloc: 
    194   unregister_chrdev_region(devno, 1);
    195   
    196   return result;
    197 }
    198 
    199 /*模块卸载函数*/
    200 static void memdev_exit(void)
    201 {
    202   cdev_del(&cdev); /*注销设备*/
    203   kfree(mem_devp); /*释放设备结构体内存*/
    204   unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
    205 }
    206 
    207 MODULE_AUTHOR("David Xie");
    208 MODULE_LICENSE("GPL");
    209 
    210 module_init(memdev_init);
    211 module_exit(memdev_exit);
    scull.c
    1 obj-m +=scull.o
    2 all:
    3     make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
    4 clean:
    5     make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
    Makefile
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <time.h>
     4 #include <unistd.h>
     5 #include <linux/i2c.h>
     6 #include <linux/fcntl.h>
     7 
     8 int main()
     9 {
    10  int fd;
    11  char buf[]="this is a test!";
    12 
    13  char buf_read[4096];
    14 
    15  
    16  if((fd=open("/dev/scull",O_RDWR))==-1) 
    17 
    18   printf("open scull WRONG!
    ");
    19  else
    20   printf("open scull SUCCESS!
    ");
    21   
    22  printf("buf is %s
    ",buf); 
    23 
    24  write(fd,buf,sizeof(buf)); 
    25 
    26  
    27  lseek(fd,0,SEEK_SET); 
    28 
    29  
    30  read(fd,buf_read,sizeof(buf)); 
    31 
    32  
    33  printf("buf_read is %s
    ",buf_read);
    34  
    35  return 0;
    36 }
    test.c

     

  • 相关阅读:
    能飞英语学习软件学习实践
    英语学习方式总结与实践
    Hello World
    centos 7.6中搭建samba共享服务
    PHP漏洞全解(一)PHP网站的安全性问题
    MySQL查询语句练习题
    在PHP中使用CURL实现GET和POST请求的方法
    js数组的操作大全
    php四种基础算法:冒泡,选择,插入和快速排序法
    Linux查看端口使用状态及启动
  • 原文地址:https://www.cnblogs.com/erbing/p/5626920.html
Copyright © 2020-2023  润新知