writel/readl/ioremap 读写CPU寄存器

本文介绍在Linux内核中使用writel、readl等函数读写CPU寄存器的方法。通过这些函数可以实现对硬件底层的直接操作,是进行设备驱动开发和系统级编程的重要手段。
#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; } 这是我的应用层,
08-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值