二 spi 子系统(spidev.c)

一.spidev.c文件

看一个设备驱动的方法:

概览下重要的结构体spidev_data及全局变量device_list,bufsiz,SPIDEV_MAJOR...

module_init标识的入口初始化函数spidev_init,(module_exit标识的出口函数)

设备与设备驱动匹配时候调用的probe方法spidev_probe

设备驱动的操作函数集file_operations--->spidev_fops

先看open方法spidev_open

接着看读写方法spidev_read & spidev_write

再接着看ioctl方法-->spidev_ioctl

再看其他剩余的方法

#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <asm/uaccess.h>

#define SPIDEV_MAJOR			153	//spidev主设备号
#define N_SPI_MINORS			32	/* ... up to 256 */
static DECLARE_BITMAP(minors, N_SPI_MINORS);	//声明次设备位图
#define SPI_MODE_MASK (SPI_CPHA|SPI_CPOL|SPI_CS_HIGH|SPI_LSB_FIRST|SPI_3WIRE|SPI_LOOP|SPI_NO_CS|SPI_READY)

struct spidev_data {
	dev_t	devt;				//设备号
	spinlock_t	spi_lock;		//自旋锁
	struct spi_device	*spi;	//spi设备结构体
	struct list_head	device_entry;
	struct mutex	buf_lock;	//互斥锁
	unsigned		users;		//使用者计数
	u8			*buffer;		//缓冲区
};

static LIST_HEAD(device_list);	//声明spi设备链表
static DEFINE_MUTEX(device_list_lock);	//定义互斥锁
static unsigned bufsiz = 4096;	//最大传输缓冲区大小
module_param(bufsiz, uint, S_IRUGO);
MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");

static void spidev_complete(void *arg)
{
	complete(arg);	//调用complete
}

static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
	DECLARE_COMPLETION_ONSTACK(done);
	int status;

	message->complete = spidev_complete;	//设置spi消息的complete方法 回调函数
	message->context = &done;

	spin_lock_irq(&spidev->spi_lock);
	if (spidev->spi == NULL)	//判断是否有指定对应的spi设备
		status = -ESHUTDOWN;
	else
		status = spi_async(spidev->spi, message);	//spi异步同步
	spin_unlock_irq(&spidev->spi_lock);

	if (status == 0) {
		wait_for_completion(&done);	//等待传输完成
		status = message->status;	//获取spi消息传输事务状态
		if (status == 0)
			status = message->actual_length;	//status等于传输的实际长度
	}
	return status;	//返回实际传输长度
}

static inline ssize_t spidev_sync_write(struct spidev_data *spidev, size_t len)
{
	struct spi_transfer	t = {
			.tx_buf		= spidev->buffer,	//发送缓冲区
			.len		= len,	//发送数据长度
		};
	struct spi_message	m;

	spi_message_init(&m);	//初始化spi消息(初始化spi传递事务队列)
	spi_message_add_tail(&t, &m);	//添加spr传递到该队列
	return spidev_sync(spidev, &m);	//同步读写
}

static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len)
{
	struct spi_transfer	t = {
			.rx_buf		= spidev->buffer,	//接收缓冲区
			.len		= len,	//接收数据长度
		};
	struct spi_message	m;

	spi_message_init(&m);	//初始化spi消息(初始化spi传递事务队列)
	spi_message_add_tail(&t, &m);	//添加spr传递到该队列
	return spidev_sync(spidev, &m);	//同步读写
}

static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	struct spidev_data	*spidev;
	ssize_t	status = 0;

	if (count > bufsiz)	//传输数据大于缓冲区容量
		return -EMSGSIZE;
	spidev = filp->private_data;	//从文件私有数据指针获取spidev_data
	mutex_lock(&spidev->buf_lock);	//上互斥锁
	status = spidev_sync_read(spidev, count);	//同步读,返回传输数据长度
	if (status > 0) {
		unsigned long	missing;	//丢失的数据个数
		missing = copy_to_user(buf, spidev->buffer, status);	//内核空间复制到用户空间
		if (missing == status)		//丢失的数据个数等于要传输的数据个数
			status = -EFAULT;
		else
			status = status - missing;	//传输成功的数据个数
	}
	mutex_unlock(&spidev->buf_lock);//解互斥锁
	return status;	//返回读取成功的数据个数
}

static ssize_t spidev_write(struct file *filp, const char __user *buf,size_t count, loff_t *f_pos)
{
	struct spidev_data	*spidev;
	ssize_t			status = 0;
	unsigned long		missing;

	if (count > bufsiz)	//传输数据大于缓冲区容量
		return -EMSGSIZE;
	spidev = filp->private_data;	//从文件私有数据指针获取spidev_data
	mutex_lock(&spidev->buf_lock);	//上互斥锁
	missing = copy_from_user(spidev->buffer, buf, count);	//用户空间复制到内核空间
	if (missing == 0) {	//传输失败个数为0
		status = spidev_sync_write(spidev, count);	//同步写,返回传输数据长度
	} 
	else
		status = -EFAULT;
	mutex_unlock(&spidev->buf_lock);//解互斥锁
	return status;	//返回写数据的实际个数
}

static int spidev_message(struct spidev_data *spidev,struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
{
	struct spi_message	msg;
	struct spi_transfer	*k_xfers;
  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值