#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
//通过cat proc/devices
#define MA 100
#define MI 0
#define ADCCON 0x126C0000
#define ADCDAT 0x126C000C
#define ADCMUX 0x126C001C
//虚拟地址转物理地址
void __iomem *adccon;
void __iomem *adcdat;
void __iomem *adcmux;
//reg, init, add需要的变量以及参数
static dev_t from = 0;
static unsigned count = 1;
static const char *name = "mycdev";
static struct cdev cdev = {0};
//用户读写数据的交换缓冲区
static char *rwbuf = "";
static int myopen(struct inode *mycdev, struct file *fp)
{
printk("myopen is ok\n");
return 0;
}
static int myclose(struct inode *mycdev, struct file *fp)
{
printk("myclose is ok\n");
return 0;
}
static ssize_t myread(struct file *fp, char __user *buf, size_t len, loff_t *off)
{
int ret = -1;
ret = copy_to_user(buf, rwbuf, len);
if(0 != ret)
{
return -1;
}
printk("read is ok\n");
return 0;
}
static const struct file_operations fops =
{
.open = myopen,
.release = myclose,
.read = myread,
};
static int addr_map(void) // 改为返回 int 表示成功或失败
{
adccon = ioremap(ADCCON, 4);
if (!adccon) {
pr_err("Failed to map ADCCON\n");
return -ENOMEM; // 返回错误代码
}
adcdat = ioremap(ADCDAT, 4);
if (!adcdat) {
pr_err("Failed to map ADCDAT\n");
iounmap(adccon); // 回滚:释放第一个映射
return -ENOMEM;
}
adcmux = ioremap(ADCMUX, 4);
if (!adcmux) {
pr_err("Failed to map ADCMUX\n");
iounmap(adcdat); // 回滚:释放第二个映射
return -ENOMEM;
}
return 0; // 成功
}
// 调用 addr_map 的地方需要检查返回值
// if (addr_map() != 0) { /* 处理错误 */ }
static void addr_unmap(void)
{
iounmap(adccon);
iounmap(adcdat);
iounmap(adcmux);
}
static void dev_init(void)
{
writel(readl(adccon) | (0x1 << 16) , adccon);
writel(readl(adccon) | (0x1 << 14) , adccon);
writel(readl(adccon) & (~(0xff << 6) | (19 << 6)) , adccon);
writel(readl(adccon) & (~(0x01 << 2)) , adccon);
writel(readl(adccon) & (~(0x01 << 1)) , adccon);
writel(readl(adcmux) | (0x03 << 0) , adcmux);
}
static void dev_exit(void)
{
writel(readl(adccon) & (~(0x1 << 16)) , adccon);
writel(readl(adccon) & (~(0x1 << 14)) , adccon);
/*
writel(readl(adccon) & (~(0xff << 6) | (19 << 6)) , adccon);
writel(readl(adccon) & (~(0x01 << 2)) , adccon);
writel(readl(adccon) & (~(0x01 << 1)) , adccon);
*/
writel(readl(adcmux) & (~(0x03 << 0)) , adcmux);
}
//2 入口和出口函数
static int myinit(void)
{
//up: kernel
//1. reg:将设备编号,设备数,设备名注册到内核
int ret = -1;
from = MKDEV(MA, MI);
ret = register_chrdev_region(from, count, name);
if(0 != ret)
{
return -1;
}
//2. init,将设备结构体cdev,进行初始化(将fops操作复制给结构体里面的fops)
cdev_init(&cdev, &fops);
//3. add(将设备添加到系统)
ret = cdev_add(&cdev, from, count);
if(0 != ret)
{
unregister_chrdev_region(from, count);
return -1;
}
//down: hardware
//1. 映射
ret = addr_map();
if(0 != ret)
{
return ret;
}
//2. dev_init
dev_init();
printk("myinit is ok\n");
return 0;
}
static void myexit(void)
{
//退出顺序应该与初始化顺序相反
//up: kernel
//1. del
cdev_del(&cdev);
//2. unreg
unregister_chrdev_region(from, count);
//down: hardware
//1. dev_exit(exit 必须在unmap之前,因为exit使用到了虚拟地址)
dev_exit();
//2. 取消映射
addr_unmap();
printk("myexit is ok\n");
}
//3 注册入口和出口函数
module_init(myinit);
module_exit(myexit);
//4 模块信息
MODULE_LICENSE("GPL");
请在我的这个框架下完成adc驱动编写,
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
char rbuf[16] = {0};
int main(int argc, char *argv[])
{
int fd = open("/dev/mycdev", O_RDWR);
if(0 > fd)
{
perror("open");
return 0;
}
int ret = -1;
while(1)
{
ret = read(fd, buf, 16);
if (-1 == ret)
return ret;
float v = (((float)buf * 1.8) / 4095);
printf("v is %f\n", v);
}
close(fd);
return 0;
}
这是我的应用层,