供学习交流之用
#include
#include
#include
#include
#include
#include
#include
#include
// 中断
#include
// 等待队列
#include
#include
// poll
#include
#include "adc.h"
#define ADCCON (0x0)
#define ADCDAT (0xC)
#define ADCCLRINT (0x18)
#define ADCMUX (0x1C)
//cdev 属性继承cdev
struct adc_dev{
struct cdev cdev;
dev_t devno;//定义设备编号变量
int resolution;//定义分辨率
struct resource *res;//设备结构体资源变量
void __iomem *reg;//寄存器指针变量 告诉是一个io内存
int irqno;//定义中断号变量
// 1.1 分配内存
wait_queue_head_t readq;//等待队列头 变量
};
struct class *adc_class;//定义类变量
//实现设备的中断服务程序(ISR)
irqreturn_t adc_irq_isr(int irqno, void *dev_id)// 4.
实现中断处理函数
{
struct adc_dev *adc = (struct adc_dev
*)dev_id;//将描述设备结构体指针来进行强转
printk("%s\n", __func__);
// 3. 在需要唤醒的地方(中断处理函数),调用wake_up_interruptible唤醒等待的所有进程
wake_up_interruptible(&adc->readq);
// 清除中断锁存
writel(0, adc->reg + ADCCLRINT);//写任意值清除中断锁存
return IRQ_HANDLED;//中断已经处理
}
void adc_dev_init(struct adc_dev *adc)//adc设备初始化函数
{
unsigned long reg;//对寄存器进行操作
reg = readl(adc->reg + ADCCON);
reg &= ~(0x1ff << 6);
reg |= (0x1ff << 6);
reg |= 1 << 16;
writel(reg, adc->reg + ADCCON);
reg = readl(adc->reg + ADCMUX);
reg &= ~0xf;
reg |= 0x3;
writel(reg, adc->reg + ADCMUX);
reg = readl(adc->reg + ADCCON);
reg &= ~(1 << 2);
reg |= 1 << 1;
writel(reg, adc->reg + ADCCON);
readl(adc->reg + ADCDAT);
}
int adc_dev_is_read(struct adc_dev *adc)//判断adc设备是否读函数
{
return (readl(adc->reg + ADCCON) & (1 <<
15));
}
int adc_dev_read(struct adc_dev *adc)//adc设备读函数
{
return readl(adc->reg + ADCDAT) & 0xfff;
}
int adc_open(struct inode *inode, struct file
*filp)//被应用程序的read系统调用间接调用,被vfs直接调用
{
int ret = 0;
printk("%s\n", __func__);
// 根据结构成员变量地址,求结构体变量地址
// ptr 结构体成员变量地址
// type 结构体
// cdev 结构体成员变量在结构体中的成员名
// 结构体变量指针
//
// 获得描述设备结构体指针
filp->private_data = container_of(inode->i_cdev, struct
adc_dev, cdev);
return ret;
}
// 被应用程序的read系统调用间接调用,被vfs直接调用
//vfs中的file结构体地址
//应用程序空间的内存
//希望读取数据的字节数
//file结构体中的f_pos成员地址,用于改变文件的位置指针
//@return @li > 0 实际读取的字节数
// @li = 0 读到文件的结尾
// @li < 0 错误码
// @notes __user buf为应用程序空间的内存
ssize_t adc_read(struct file *filp, char __user *buf, size_t
size, loff_t *loff)
{
int vol;
int ret = sizeof(vol);
struct adc_dev *adc = (struct adc_dev
*)filp->private_data;
printk("%s\n", __func__);
if (filp->f_flags & O_NONBLOCK) {
// 非阻塞
if (!adc_dev_is_read(adc)){
ret = -EAGAIN;
goto exit;
}
} else {
// 阻塞
// 休眠等待(在中断中唤醒)
// 谁在等?(进程) 等什么事件?(设备有数据)
// 2. 在read函数中,调用wait_event_interruptabile让当前进程等待
wait_event_interruptible(adc->readq,
adc_dev_is_read(adc));
}
vol = adc_dev_read(adc);
ret = copy_to_user(buf, &vol,
sizeof(vol));//拷贝数据到应用程序空间的内存
unsigned int adc_poll(struct file *filp, poll_table
*wait)
{
unsigned int mask = 0;
struct adc_dev *adc = (struct adc_dev
*)filp->private_data;
// 加读等待队列头
poll_wait(filp, &adc->readq,
wait);
// 加写等待队列头
// poll_wait(filp, &dev->w_wait,
wait);
if (adc_dev_is_read(adc)) {
// 可读
mask |= POLLIN | POLLRDNORM;
}
// if (...) {
// 可写
// mask |= POLLOUT |
POLLWRNORM;
// }
return mask;
}
// filp 文件结构(文件在操作过程中的状态)
// requests 系统调用传下来的请求
// arg 系统调用传下来的参数
// @li >= 0 直接返回给系统调用返回给应用程序
// @li < 0 错误码
//@notes arg 将ioctl的第三个参数
long adc_unlocked_ioctl(struct file *filp, unsigned int req,
unsigned long arg)//响应ioctl系统调用
{
long ret = 0;
struct adc_dev *adc = (struct adc_dev
*)filp->private_data;
printk("%s\n", __func__);
switch (req){
case CTL_SET_RES:
printk("%s: CTL_SET_RES (%lu)\n", __func__, arg);
adc->resolution = (int)arg;
break;
case CTL_GET_RES:
printk("%s: CTL_SET_RES (%p)\n", __func__, (void *)arg);
ret = copy_to_user((void *)arg, &adc->resolution,
sizeof(int));
if (ret){
ret = -EFAULT;
}
break;
default:
ret = -ENOTTY;
break;
}
return ret;
}
int adc_release(struct inode *inode, struct file
*filp)//被应用程序的close系统调用间接调用,被vfs直接调用
{
struct adc_dev *adc = (struct adc_dev
*)filp->private_data;
adc = adc;
printk("%s\n", __func__);
return 0;
}
const struct file_operations fops = {
// 将fops变量的成员初始化
.open = adc_open,
.read = adc_read,
.poll = adc_poll,
.unlocked_ioctl = adc_unlocked_ioctl,
.release = adc_release
};
static int num_devno = 0;
//@brief 设备和驱动匹配上之后,调用这个函数初始化设备(初始化硬件,创建字符设备)
//@param pdev 设备结构体指针
//@return @li 0 成功
// @li < 0 错误码
int adc_probe(struct platform_device *pdev)
{
int ret = 0;
struct resource *res_iomem, *res_irq;//设备结构体中的资源变量
struct adc_dev *adc;
struct device *device;
printk("%s\n", __func__);
// pdev 设备结构体指针
//@param type 资源类型
// @IORESOURCE_MEM io内存
// @IORESOURCE_IRQ 中断
// @IORESOURCE_DMA dma
// @param num 获取资源编号,0, 1, ...
//
// @return 资源结构体指针
// @NULL 资源不存在
// struct resource *platform_get_resource(struct
platform_device *pdev, unsigned int type, unsigned int num);
res_iomem = platform_get_resource(pdev, IORESOURCE_MEM,
0);//获取设备结构体中的资源
if (NULL == res_iomem){
ret = -ENOENT;
goto exit;
}
printk("%s: reg =