代码拉取完成,页面将自动刷新
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/io.h> //ioremap
#include <linux/uaccess.h>
/*********************************
*
* mmap 好像不能在内核驱动中调用
*
* ***********************************/
//记录各个寄存器的内核虚拟地址
static void *gpiobase;
static unsigned long *gpiocout; //数据寄存器内核虚拟地址
static unsigned long *gpiocoutenb; //输出使能寄存器内核虚拟地址
static unsigned long *gpiocaltfn0; //复用功能选择寄存器的内核虚拟地址
#define GPIO_Base_addr 0xFED0E000
#define GPIO_Page_size 4096
#define GPIO31_CFG_ADDR 0x330 //供电检测引脚
#define GPIO31_PORT_ADDR (GPIO31_CFG_ADDR + 8)
#define GPIO_CFG_Value 0x2003CD00
#define GPIO_PORT_CFG_Value 0x00000003
#define LED_ON 0x100001 //开灯命令
#define LED_OFF 0x100002 //关灯命令
static long voltage_control_ioctl(struct file *file,
unsigned long cmd,
unsigned long arg)
{
//1.分配内核缓冲区
int kindex;
//2.拷贝用户缓冲区数据到内核缓冲区
copy_from_user(&kindex, (int *)arg, sizeof(kindex));
//3.解析用户发送来的命令
switch (cmd)
{
case LED_ON:
if (kindex == 1)
*gpiocout &= ~(1 << 12);
/*
else if(kindex == 2)
....
else if(kindex == 3)
....
else if(kindex == 4)
....
*/
break;
case LED_OFF:
if (kindex == 1)
*gpiocout |= (1 << 12);
/*
else if(kindex == 2)
....
else if(kindex == 3)
....
else if(kindex == 4)
....
*/
break;
default:
return -1;
}
//4.添加调试打印信息,将操作的寄存器的值打印出来
//如果将来发现寄存器的值是对的,但是灯没有反应
//请问:是谁的问题?此问题势必是硬件问题
// printk("GPIOCALTFN0=%#x, GPIOCOUTENB=%#x, GPIOCOUT=%#x\n", *gpiocaltfn0, *gpiocoutenb, *gpiocout);
printk("%d\n",(*((int *)(mem + GPIO31_PORT_ADDR)) & 0x01));
return 0;
}
//定义初始化硬件操作接口对象
static struct file_operations voltage_control_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = voltage_control_ioctl};
//定义初始化混杂设备对象
static struct miscdevice voltage_control_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "my_voltage_control",
.fops = &voltage_control_fops};
static int voltage_control_init(void)
{
//1.注册混杂设备到内核
misc_register(&voltage_control_misc);
#if 0
//2.将各个寄存器的物理地址映射到内核虚拟地址
//一旦完成映射,驱动访问映射的内核虚拟地址就是
//在访问对应的物理地址
gpiobase = ioremap(0xC001C000, 0x24);
gpiocout = (unsigned long *)(gpiobase + 0x00);
gpiocoutenb = (unsigned long *)(gpiobase + 0x04);
gpiocaltfn0 = (unsigned long *)(gpiobase + 0x20);
//3.配置引脚为GPIO功能,配置为输出,输出1(省电)
*gpiocaltfn0 &= ~(0x3 << 24);
*gpiocaltfn0 |= (1 << 24);
*gpiocoutenb |= (1 << 12);
*gpiocout |= (1 << 12);
#endif
uint8_t Value, fd;
char *mem;
uint64_t TMP = 0, i = 0;
uint8_t copy_action[100];
//open /dev/mem with read and write mode
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0)
{
perror("open error");
return -1;
}
//map physical memory 0-10 bytes
mem = mmap(0, GPIO_Page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_Base_addr);
if (mem == MAP_FAILED)
{
perror("mmap error:");
return 1;
}
TMP = GPIO_CFG_Value;
memcpy((mem + GPIO31_CFG_ADDR), &TMP, 4);
TMP = GPIO_PORT_CFG_Value;
memcpy((mem + GPIO31_PORT_ADDR), &TMP, 4);
return 0;
}
static void voltage_control_exit(void)
{
#if 0
// 1.输出1,解除地址映射
*gpiocout |= (1 << 12);
iounmap(gpiobase);
#endif
//2.卸载混杂设备
misc_deregister(&voltage_control_misc);
}
module_init(voltage_control_init);
module_exit(voltage_control_exit);
MODULE_LICENSE("GPL");
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。