Skip to content

Latest commit

 

History

History
349 lines (263 loc) · 7.28 KB

嵌入式系统设计实验报告二.md

File metadata and controls

349 lines (263 loc) · 7.28 KB
嵌入式系统设计实验报告
(二)




























作者:康赣鹏

学号:14130140377

Email:[email protected]

教师:朱光明


##模块参数及Proc文件系统 ###一、实验目的

掌握简单字符设备驱动程序中模块参数及Proc文件系统的编写方法。

学习利用模块参数进行驱动程序参数传递,学习利用Proc文件系统进行数据读写。

###二、实验要求

按实验内容编写驱动程序

编译驱动程序

在嵌入式设备上加载驱动程序并利用Proc文件系统的读写进行驱动程序测试

###三、实验内容

写一个简单的字符设备驱动程序,要求:

  • 定义一个全局结构指针,初始值为NULL,该数据结构中包含一个大小为N的buffer;
  • 在open中对该全局结构进行NULL判断,为NULL则为其分配内存,并将buffer初始化为0;
  • 在release中释放buffer;
  • 通过读proc文件系统对该buffer进行读取;
  • 通过写proc文件系统对该buffer进行赋值;
  • Buffer的大小N是模块参数,在加载过程中指定。

###四、实验步骤

参考《嵌入式系统设计》课程第05讲内容,根据实验内容要求设计编写驱动程序

编译和加载驱动程序

进行驱动程序测试

卸载驱动程序

在docker上make成功

将文件通过网线和路由器将文件发送到树莓派中

insmod 动态加载模块

查看当前的模块

测试模块

open:对该全局结构进行NULL判断,当buffer为NULL时,则为其分配内存,并将buffer初始化为0,将count自加

static int qled_open(struct inode* inode, struct file *file) {
  printk("open %u\n",count);
  if(count ==0 || buffer == NULL) {
    if(buffer_size == 0) {
      buffer_size = BUF_SIZE;
    }
    buffer = kmalloc(buffer_size,GFP_KERNEL);
    if(buffer == NULL) {
      printk("cannot alloc");
      return -1;
    }
    printk("alloc\n");
  }
  try_module_get(THIS_MODULE);
  ++ count;
  return 0;
}

close:在release中如果count为0,则释放,否则进行count自减

// proc close
static int qled_close(struct inode *inode, struct file *filep)
{
  --count;
  printk("close %u",count);
  if(count == 0) {
    if(buffer) {
      kfree(buffer);
      printk("free\n");
      buffer = NULL;
    }
  }
  module_put(THIS_MODULE);
  return 0;
}

write:在write里面对该buffer进行赋值,若count和文件指针来判断写入文件的大小

static ssize_t qled_write(struct file *filep, char *buf, size_t count, loff_t *f_pos)
{
  int len = -ENOMEM;
  if(buffer) {
    if (*f_pos < buffer_size) {
        len = count + *f_pos > buffer_size ? buffer_size - *f_pos : count;
        copy_from_user(buffer + *f_pos,buf,len);
    }
    else {
        len = count > buffer_size ? buffer_size  : count;
        copy_from_user(buffer + *f_pos,buf,len);
    }
    *f_pos += len;
  }
  return len;
}

read:在read里面对该buffer进行读取,若count和文件指针来判断读取内容的大小。

static ssize_t qled_read(struct file *filep, char *buf, size_t count, loff_t *f_pos)
{
  int len = 0;
  if(buffer) {
    if (*f_pos < buffer_size) {
        len = count + *f_pos > buffer_size ? buffer_size - *f_pos : count;
        copy_to_user(buf,buffer + *f_pos,len);
    }
    *f_pos += len;
  }
  return len;
}

加载模块

static int init_ledc(void) {
  printk("start!\n");
  qled = proc_create_data("proc",0644,NULL,&qled_fops,"123");
  return 0;
}

卸载模块

static void exit_ledc(void) {
  printk("exit!\n");
  remove_proc_entry("proc",NULL);
  if(buffer) {
    kfree(buffer);
    printk("free");
  }
}

Makefile:

obj-m:=proc.o
ledmodp-y:=proc.o


KERNELBUILD:=../../linux-rpi-4.4.y/
ccflags-y := -std=gnu99

module: proc.c
	$(MAKE) ARCH=arm -C $(KERNELBUILD)    M=$(shell pwd) modules ARCH=arm CROSS_COMPILE=armv7-rpi2-linux-gnueabihf-

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

测试程序:

#include <unistd.h>
#include <stdio.h>

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fs.h>

int main() {
	int fd = open("/proc/proc",O_RDWR);
	char buf[1024] = "123456";
	int k;
	write(fd,buf,1024);
	bzero(buf,1024);
	scanf("%d",&k);
	read(fd,buf,1024);
	perror("error");
	printf("%s\n",buf);
	close(fd);
}

代码清单:

#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include<linux/seq_file.h>
#include<linux/proc_fs.h>
#include<linux/sched.h>
#include<linux/uaccess.h>
#include<linux/string.h>
#include<linux/moduleparam.h>


#define BUF_SIZE (1024)

static unsigned long buffer_size = 0;

///// Datas
static char *buffer;
struct proc_dir_entty *qled;
static unsigned int count=0;


// proc open
static int qled_open(struct inode* inode, struct file *file) {
  printk("open %u\n",count);
  if(count ==0 || buffer == NULL) {
    if(buffer_size == 0) {
      buffer_size = BUF_SIZE;
    }
    buffer = kmalloc(buffer_size,GFP_KERNEL);
    if(buffer == NULL) {
      printk("cannot alloc");
      return -1;
    }
    printk("alloc\n");
  }
  try_module_get(THIS_MODULE);
  ++ count;
  return 0;
}


// proc close
static int qled_close(struct inode *inode, struct file *filep)
{
  --count;
  printk("close %u",count);
  if(count == 0) {
    if(buffer) {
      kfree(buffer);
      printk("free\n");
      buffer = NULL;
    }
  }
  module_put(THIS_MODULE);
  return 0;
}

static ssize_t qled_write(struct file *filep, char *buf, size_t count, loff_t *f_pos)
{
  int len = -ENOMEM;
  if(buffer) {
    if (*f_pos < buffer_size) {
        len = count + *f_pos > buffer_size ? buffer_size - *f_pos : count;
        copy_from_user(buffer + *f_pos,buf,len);
    }
    else {
        len = count > buffer_size ? buffer_size  : count;
        copy_from_user(buffer + *f_pos,buf,len);
    }
    *f_pos += len;
  }
  return len;
}

static ssize_t qled_read(struct file *filep, char *buf, size_t count, loff_t *f_pos)
{
  int len = 0;
  if(buffer) {
    if (*f_pos < buffer_size) {
        len = count + *f_pos > buffer_size ? buffer_size - *f_pos : count;
        copy_to_user(buf,buffer + *f_pos,len);
    }
    *f_pos += len;
  }
  return len;
}


// file operations
static struct file_operations qled_fops = {
  open:    qled_open,
  release: qled_close,
  read:    qled_read,
  write:   qled_write,
};


static int init_ledc(void) {
  printk("start!\n");
  qled = proc_create_data("proc",0644,NULL,&qled_fops,"123");
  return 0;
}


static void exit_ledc(void) {
  printk("exit!\n");
  remove_proc_entry("proc",NULL);
  if(buffer) {
    kfree(buffer);
    printk("free");
  }
}

module_init(init_ledc);
module_exit(exit_ledc);

module_param(buffer_size,ulong,S_IRUGO);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("kangkang");