目标:利用混杂设备实现对IO口的操作,进而开启或关闭相连的LED
-用混杂设备的原因是因为方便实现,不要陷入太复杂的细节中,把握整个框架才是最重要的
-在 /dev/ 目录下建立设备节点: vled(也就是驱动模块名)
-可以打开关闭节点,利用 ioctl() 函数控制 GPIO 口的电平
代码示例
1. 新建驱动目录 ~/kernel/drivers/vled,分别增加以下文件:
/*
vled.c
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "vled.h"
#define GRF_BASE_ADDR 0x20008000
#define GPIO0_BASE_ADDR 0x20034000
#define GPIO1_BASE_ADDR 0x2003E000
#define GPIO6_BASE_ADDR 0x2000A000
#define GPIO_SWPORT_DR 0x0000
#define GPIO_SWPORT_DDR 0x0004
#define GPIO_EXT_PORT 0x0050
void * pvir = NULL;
int vled_open(struct inode * inode, struct file * file)
{
return 0;
}
int vled_close(struct inode * inode, struct file * file)
{
return 0;
}
long vled_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case IOC_VLED_SET:
iowrite32(ioread32(pvir + GPIO_SWPORT_DDR) | (0x01 << 8), pvir + GPIO_SWPORT_DDR);
iowrite32(ioread32(pvir + GPIO_SWPORT_DR) | (0x01 << 8), pvir + GPIO_SWPORT_DR);
break;
case IOC_VLED_CLR:
iowrite32(ioread32(pvir + GPIO_SWPORT_DDR) | (0x01 << 8), pvir + GPIO_SWPORT_DDR);
iowrite32(ioread32(pvir + GPIO_SWPORT_DR) & (~(0x01 << 8)), pvir + GPIO_SWPORT_DR);
break;
default:
printk("vled drv:invalid nc decoder ioctl cmd[0x%02X]\n", cmd);
break;
}
return 0;
}
static struct file_operations vled_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = vled_ioctl,
.open = vled_open,
.release = vled_close
};
static struct miscdevice vled_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "vled",
.fops = &vled_fops,
};
static int __init vled_module_init(void)
{
int ret = 0;
ret = misc_register(&vled_dev);
if (ret)
{
printk("ERROR: could not register vled devices\n");
}
// P6.B.0 = 0;
printk(KERN_ALERT "Set P6.B.0 = 0\n");
pvir = ioremap(GPIO6_BASE_ADDR, 0x64);
if(NULL == pvir) {
printk(KERN_ALERT "ioremap error!\n");
return -1;
}
printk(KERN_ALERT "Virrual addr: 0x%x\n", (unsigned int)pvir);
iowrite32(ioread32(pvir + GPIO_SWPORT_DDR) | (0x01 << 8), pvir + GPIO_SWPORT_DDR);
iowrite32(ioread32(pvir + GPIO_SWPORT_DR) & (~(0x01 << 8)), pvir + GPIO_SWPORT_DR);
printk(KERN_ALERT "DDR: 0x%x, DR: 0x%x\n", ioread32(pvir + GPIO_SWPORT_DDR), ioread32(pvir + GPIO_SWPORT_DR));
printk(KERN_ALERT "vled init ok!\n");
return ret;
}
static void __exit vled_module_exit(void)
{
iounmap(pvir);
misc_deregister(&vled_dev);
}
module_init(vled_module_init);
module_exit(vled_module_exit);
MODULE_LICENSE("GPL");
/*
vled.h
*/
#ifndef VLED_H
#define VLED_H
#define IOC_VLED_SET 0
#define IOC_VLED_CLR 1
#endif