字符块设备驱动程序框架---已测试程序hello为例

简介: 字符块设备驱动程序框架---已测试程序hello为例

怎么编写驱动程序

1.确定主设备号。

2.定义自己的file_operations结构体。

3.实现对应的open/read/write等函数,填入file_operations结构体。

4.把file_operations结构体告诉内核:注册驱动程序。

5.谁来注册驱动函数=呢?得有一个人口函数:安装驱动程序时,就会去调用这个出口函数。

6有人口函数就应该有出口函数:卸载驱动程序是,就会去调用这个出口函数。

7.其他完善:提供设备信息,自动创建设备节点。


app调用的系统调用函数open,read,write等系统调用函数时,会先调用sys_open,sys_read,sys_write,再根据设备判断是普通文件,还是设备文件,进而调用drv_open,drv_read,drv_write等驱动程序。那么驱动程序怎么提前写出来呢?也就是前面的七点

struct file {
  union {
    struct llist_node fu_llist;
    struct rcu_head   fu_rcuhead;
  } f_u;
  struct path   f_path;
  struct inode    *f_inode; /* cached value */
  const struct file_operations  *f_op;
  /*
   * Protects f_ep_links, f_flags.
   * Must not be taken from IRQ context.
   */
  spinlock_t    f_lock;
  atomic_long_t   f_count;
  unsigned int    f_flags;
  fmode_t     f_mode;
  struct mutex    f_pos_lock;
  loff_t      f_pos;
  struct fown_struct  f_owner;
  const struct cred *f_cred;
  struct file_ra_state  f_ra;
  u64     f_version;
#ifdef CONFIG_SECURITY
  void      *f_security;
#endif
  /* needed for tty driver, and maybe others */
  void      *private_data;
#ifdef CONFIG_EPOLL
  /* Used by fs/eventpoll.c to link all the hooks to this file */
  struct list_head  f_ep_links;
  struct list_head  f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
  struct address_space  *f_mapping;
} __attribute__((aligned(4)));  /* lest something weird decides that 2 is OK */

struct file 这个结构体也就是我们使用open函数的返回值,是一个整数,可以暂时当做设备描述符。const struct file_operations *f_op;结构体指针,指向file_operations结构体,这个结构体里面就有驱动程序

struct file_operations {
  struct module *owner;
  loff_t (*llseek) (struct file *, loff_t, int);
  ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
  ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
  ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
  ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
  int (*iterate) (struct file *, struct dir_context *);
  int (*iterate_shared) (struct file *, struct dir_context *);
  unsigned int (*poll) (struct file *, struct poll_table_struct *);
  long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
  long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
  int (*mmap) (struct file *, struct vm_area_struct *);
  int (*open) (struct inode *, struct file *);
  int (*flush) (struct file *, fl_owner_t id);
  int (*release) (struct inode *, struct file *);
  int (*fsync) (struct file *, loff_t, loff_t, int datasync);
  int (*fasync) (int, struct file *, int);
  int (*lock) (struct file *, int, struct file_lock *);
  ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
  unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
  int (*check_flags)(int);
  int (*flock) (struct file *, int, struct file_lock *);
  ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
  ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
  int (*setlease)(struct file *, long, struct file_lock **, void **);
  long (*fallocate)(struct file *file, int mode, loff_t offset,
        loff_t len);
  void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
  unsigned (*mmap_capabilities)(struct file *);
#endif
  ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
      loff_t, size_t, unsigned int);
  int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
      u64);
  ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
      u64);
};

将open,write,read等函数填入到file_operations结构体中。而file_operations由register_chrdev(主设备号,file_operations)将设备注册到chrdev【】数组中。注册之后就可以通过之前系统分配的设备号或者自己指定的设备号就可以调用这个设备的驱动函数了。


开始编写驱动程序

参照liunx/char/misc.c进行编写

首先添加头文件

/*
总体流程
1.确定主设备号。
2.定义自己的file_operations结构体。
3.实现对应的open/read/write等函数,填入file_operations结构体。
4.把file_operations结构体告诉内核:注册驱动程序。
5.谁来注册驱动函数=呢?得有一个人口函数:安装驱动程序时,就会去调用这个出口函数。
6有人口函数就应该有出口函数:卸载驱动程序是,就会去调用这个出口函数。
7.其他完善:提供设备信息,自动创建设备节点。
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
/* 1.确定主设备号。*/
static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;
#define MIN(a,b)(a<b?a:b)
/*3.实现对应的open/read/write等函数,填入file_operations结构体。*/
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
  int err;
  printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
  err = copy_to_user(buf, kernel_buf, MIN(1024,size));
  return MIN(1024, size);
}
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
  int err;
  printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
  err = copy_from_user(kernel_buf, buf, MIN(1024,size));
  return MIN(1024,size);
}
static int hello_drv_open (struct inode *node, struct file *file)
{
  printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
  return 0;
}
static int hello_drv_release (struct inode *node, struct file *file)
{
  printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
  return 0;
}
/* 2.定义自己的file_operations结构体。*/
static const struct file_operations hello_drv = {
  .owner   = THIS_MODULE,
  .open    = hello_drv_open,
  .read    = hello_drv_read,
  .write   = hello_drv_write,
  .release = hello_drv_release,
};
/*4.把file_operations结构体告诉内核:注册驱动程序。*/
/*5.谁来注册驱动函数=呢?得有一个人口函数:安装驱动程序时,就会去调用这个出口函数。*/
static int __init hello_init(void)
{
  int err;
  printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
  register_chrdev(0, "hello", &hello_drv);//应用程序访问某一个驱动程序需要根据某一个设备节点才能访问,那么如何才能设置设备节点那??
  hello_class = class_create(THIS_MODULE, "hello");
  err = PTR_ERR(hello_class);
  if (IS_ERR(hello_class))
  {
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
    unregister_chrdev(major, "hello");
    return -1;
  }
  device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); 
  return 0;
}
/*6有人口函数就应该有出口函数:卸载驱动程序是,就会去调用这个出口函数。*/
static void __exit hello_exit(void)
{
  printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
  device_destroy(hello_class,MKDEV(major, 0));
  class_destroy(hello_class);
  unregister_chrdev(major, "hello");
}
/*7.其他完善:提供设备信息,自动创建设备节点。*/
module_init(hello_init);//将hello_init修饰为入口函数
module_exit(hello_exit);//将hello_exit修饰为出口函数
MODULE_LICENSE("GPL");//表示同意加入GPL协议,开源协议

注意在liunx上编译后放在6ull开发板上运行时会出现

ls: cannot access ‘/dev/hello’: No such file or directory

但是hello这个驱动程序又已经加载进了内核中。这里只是没有dev设备节点,所以这里手动添加设备节点。

mknod /dev/hello c 240 0

添加之后就可以进行测试程序的操作了。


目录
打赏
0
0
0
0
5
分享
相关文章
探索软件测试中的自动化测试框架选择与优化策略
本文深入探讨了在现代软件开发流程中,如何根据项目特性、团队技能和长期维护需求,精准选择合适的自动化测试框架。
214 11
|
7天前
|
Metasploit Pro 4.22.7-2025042101 发布 - 专业渗透测试框架
Metasploit Pro 4.22.7-2025042101 (Linux, Windows) - 专业渗透测试框架
30 5
Metasploit Pro 4.22.7-2025042101 发布 - 专业渗透测试框架
测试工程师要失业?Magnitude:开源AI Agent驱动的端到端测试框架,让Web测试更智能,自动完善测试用例!
Magnitude是一个基于视觉AI代理的开源端到端测试框架,通过自然语言构建测试用例,结合推理代理和视觉代理实现智能化的Web应用测试,支持本地运行和CI/CD集成。
141 15
测试工程师要失业?Magnitude:开源AI Agent驱动的端到端测试框架,让Web测试更智能,自动完善测试用例!
Acunetix v25.4 发布 - Web 应用程序安全测试
Acunetix v25.4 (Linux, Windows) - Web 应用程序安全测试
29 3
Acunetix v25.4 发布 - Web 应用程序安全测试
AI做奥赛题能及格吗?OlympicArena:上海交大推出多学科认知推理基准测试框架,挑战AI极限
OlympicArena是由上海交大等机构联合推出的多学科认知推理基准测试框架,包含7大学科11,163道奥林匹克竞赛级题目,通过细粒度评估推动AI向超级智能发展。
90 12
AI做奥赛题能及格吗?OlympicArena:上海交大推出多学科认知推理基准测试框架,挑战AI极限
|
22天前
|
Metasploit Pro 4.22.7-2025040601 (Linux, Windows) - 专业渗透测试框架
Metasploit Pro 4.22.7-2025040601 (Linux, Windows) - 专业渗透测试框架
60 1
Metasploit Pro 4.22.7-2025040601 (Linux, Windows) - 专业渗透测试框架
Metasploit Framework 6.4.55 (macOS, Linux, Windows) - 开源渗透测试框架
Metasploit Framework 6.4.55 (macOS, Linux, Windows) - 开源渗透测试框架
43 0
Metasploit Framework 6.4.55 (macOS, Linux, Windows) - 开源渗透测试框架
|
3月前
|
AppSpider Pro 7.5.015 for Windows - Web 应用程序安全测试
AppSpider Pro 7.5.015 for Windows - Web 应用程序安全测试
48 12
AppSpider Pro 7.5.015 for Windows - Web 应用程序安全测试
AxBench:斯坦福大学推出评估语言模型控制方法的基准测试框架
AxBench 是由斯坦福大学推出,用于评估语言模型可解释性方法的基准测试框架,支持概念检测和模型转向任务,帮助研究者系统地比较不同控制技术的有效性。
81 5
AxBench:斯坦福大学推出评估语言模型控制方法的基准测试框架
Python 高级编程与实战:构建自动化测试框架
本文深入探讨了Python中的自动化测试框架,包括unittest、pytest和nose2,并通过实战项目帮助读者掌握这些技术。文中详细介绍了各框架的基本用法和示例代码,助力开发者快速验证代码正确性,减少手动测试工作量。学习资源推荐包括Python官方文档及Real Python等网站。

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等