SPI驱动框架

SPI驱动框架

  1. 概述
  2. 详细讲解

论述

为什要写这个博客呢,主要有两个原因:第一,记录自己对SPI驱动的理解;第二,网上很多讲解SPI驱动都是自上而下地讲解,比较难理解,现在我将从下而上地进行详细讲解。在阅读驱动程序是不能够从上而下读的,而是应该找到入口函数,一一连接起来。
大部分的驱动都是这三个步骤:注册设备,注册驱动,生成设备节点。

详细讲解

模块加载和模块卸载

module_init(spi_init);//spi_init只是函数名,无特殊意义
module_exit(spi_exit);//spi_exit只是函数名,无特殊意义

加载模块和卸载模块将会进入驱动注册函数和驱动卸载函数

spi_init和spi_exit函数(驱动注册和驱动卸载)

static void spi_init(void)
{
  spi_register_driver(spi_driver);//注册驱动,spi_driver是spi类型驱动专有结构体
  return 0;
}
static void spi_exit(void)
{
  spi_spi_unregister_driver(spi_driver);//驱动卸载,spi_driver是spi类型驱动专有结构体
  return 0;
}

spi_driver结构体

spi_driver是很重要的结构体,spi驱动的.name将spi_device联系起来,spi驱动里的probe函数和remove函数将驱动和设备节点联系起来,至此,设备\、驱动、节点三者联系了起来。

struct spi_driver
{ 
  const struct spi_device_id *id_table,  
  int  (*probe)(struct spi_device *spi),    
  int  (*remove)(struct spi_device *spi),  
  void (*shutdown)(struct spi_device *spi), 
  int  (*suspend)(struct spi_device *spi,pm_message_t mesg), 
  int  (*resume)(struct spi_device *spi),  
  struct device_driver  driver;  
}

例子

struct spi_driver spi 
{
    driver = {
               .name  = "设备名",//这步将驱动和设备建立起了关系
               .owner = THIS_MODULE,//THIS_MODULE
             },
    .probe  = probe,  //和设备节点联系起来
    .remove = remove,            
}

probe函数和remove函数(设备节点生成和摧毁)

int probe(struct spi_device *spi)
{
	my_spi = spi; 
	misc_register(miscdevice);  //字符设备节点注册
	return 0;
}
static int rc522_remove(struct spi_device *spi)
{
	misc_deregister(&miscdevice);  //字符设备节点卸载
	return 0;
}

miscdevice结构体

在miscdevice结构体我们将生成设备节点名字并通过file_operation结构体为上层函数调用提供函数接口。

struct miscdevice {
  int minor,
  const char *name,
  const struct file_operations *fops,
  struct list_head list,
  struct device *parent,
  struct device *this_device,
  const struct attribute_group **groups,
  const char *nodename,
  umode_t mode,
};

例子

static struct miscdevice()//字符设备节点结构体
{
	.minor = MISC_DYNAMIC_MINOR,
	.fops  = &file_operation,//提供上层接口函数
	.name  = "设备节点名称",
}

file_operation结构体

file_operation结构体主要功能是为上层程序提供接口函数。

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(*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
  ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);
  ssize_t(*aio_write) (struct kiocb *, const char __user *, size_t,
  loff_t);
  int (*readdir) (struct file *, void *, filldir_t);
  unsigned int (*poll) (struct file *, struct poll_table_struct *);
  int (*ioctl) (struct inode *, struct file *, unsigned int,
  unsigned long);
  int (*mmap) (struct file *, struct vm_area_struct *);
  int (*open) (struct inode *, struct file *);
  int (*flush) (struct file *);
  int (*release) (struct inode *, struct file *);
  int (*fsync) (struct file *, struct dentry *, int datasync);
  int (*aio_fsync) (struct kiocb *, int datasync);
  int (*fasync) (int, struct file *, int);
  int (*lock) (struct file *, int, struct file_lock *);
  ssize_t(*readv) (struct file *, const struct iovec *, unsigned long,
  loff_t *);
  ssize_t(*writev) (struct file *, const struct iovec *, unsigned long,
  loff_t *);
  ssize_t(*sendfile) (struct file *, loff_t *, size_t, read_actor_t,
  void __user *);
  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);
  };

例子

static struct file_operations 
{
	.owner = THIS_MODULE,
	.open  = open,
	.write = write,
	.read  = read, //提供上层接口
};

接口函数

int open(struct inode *inode,struct file *filp)
{
   return 0;
}

static ssize_t  write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	return 0;
}

static ssize_t  read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	return 0;
}

完毕

发布了6 篇原创文章 · 获赞 2 · 访问量 122

猜你喜欢

转载自blog.csdn.net/qq_44931814/article/details/104981827
今日推荐