c语言 应用层调度,adc(字符设备驱动)驱动代码实现以及各函数用法(总结版本) 包含中断处理,硬件实现代码,应用层系...

供学习交流之用

#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 =

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值