本文通过操作寄存器实现led灯的亮灭,使用开发板iTop4412
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "led_ctrl"
int led_major = 0;
int led_minor = 0;
#define GPX2_CONFIG (0x11000000+0x0060)
#define GPX2_DATA (0x11000000+0x0064)
module_param(led_major, int, S_IRUGO);
static struct class *led_class;
void led_ctrl(int sw)
{
int val = 0;
void *virt_config = NULL;
void *virt_data = NULL;
virt_config = ioremap(GPX2_CONFIG,4);
virt_data = ioremap(GPX2_DATA,4);
val = readl(virt_config)&(~(0xF<<4))|(1<<4);
writel(val,virt_config);
if(sw)
val = readl(virt_data)|(1<<1);
else
val = readl(virt_data)&(~(0x1<<1));
writel(val,virt_data);
iounmap(virt_config);
iounmap(virt_data);
}
int led_open(struct inode *inode, struct file *file)
{
printk(KERN_EMERG "led_open!!\n");
return 0;
}
ssize_t led_write(struct file *file, const char __user *a, size_t s, loff_t* l)//向设备发送数据
{
printk(KERN_EMERG "led_write!!\n");
return 0;
}
ssize_t led_read(struct file *file, char __user *a, size_t s, loff_t *l)//从设备中同步读取数据
{
printk(KERN_EMERG "led_read!!\n");
return 0;
}
int led_release(struct inode *inode, struct file *file)
{
printk(KERN_EMERG "led_release!!\n");
return 0;
}
long led_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
if(cmd > 1)
printk(KERN_EMERG "cmd is 0 or 1\n");
if(arg > 1)
printk(KERN_EMERG "arg is only 1\n");
led_ctrl(cmd);
return 0;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.read = led_read,
.release = led_release,
.unlocked_ioctl = led_unlocked_ioctl,
};
struct led_dev_t {
struct cdev cdev;
};
struct led_dev_t *led_device;
void led_setup_cdev(struct led_dev_t *dev,int index)
{
int err,devno = MKDEV(led_major,led_minor+index);
cdev_init(&dev->cdev,&fops);
err = cdev_add(&dev->cdev, devno, 1);
if(err)
printk(KERN_NOTICE "error %d adding led%d\n",err,led_minor);
else
printk(KERN_NOTICE "OK %d adding led%d\n",err,led_minor);
}
//设备驱动模块加载函数
static int __init led_init(void)
{
int ret = 0;
dev_t devno = MKDEV(led_major,led_minor);
//获取字符设备号
if(led_major)
{
//静态获取设备号
ret = register_chrdev_region(devno,1,DEVICE_NAME);
}
if((ret < 0)||(!led_major))
{
//动态申请设备号
ret = alloc_chrdev_region(&devno,0, 1,DEVICE_NAME);
/*
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name);
dev: 内核会将分配给你的设备号放里面,设备号类型 dev_t
baseminor: 指定次设备号从数字几开始申请,代码中是0
count: 申请设备号的个数,设备号是连续的
name: 名字,自己随便写,char* 类型
返回值: 小于等于0 失败,大于0为主设备号
*/
}
if(ret <0)
{
printk(KERN_NOTICE "led_init is error\n");
return ret;
}
led_major = MAJOR(devno);
led_minor = MINOR(devno);
led_class = class_create(THIS_MODULE,DEVICE_NAME);//注册一个类,可以在"/dev/"目录下面建立设备节点
led_device = kzalloc(sizeof(struct led_dev_t), GFP_KERNEL);
if(!led_device)
{
printk(KERN_NOTICE "led_device error!\n");
ret = -ENOMEM;
goto fail;
}
led_setup_cdev(led_device,0);//内含注册字符设备
/*
实现一个字符设备对象
1.创建一个struct cdev cdev对象,名为cdev
2.初始化cdev
使用函数:void cdev_init(struct cdev * cdev,const struct file_operations * fops);
*cdev: 为创建的cdev对象,一定要传入地址进来
*fops: file_operations结构体对象,该结构体包含open read等函数
3.将cdev对象添加到内核中
int cdev_add(struct cdev *cdev,dev_t dev,unsigned count);
*cdev: cdev对象
dev: 设备号,前面申请的
count: 一次添加几个设备
返回值 <0 错误
*/
device_create(led_class,NULL,devno,NULL,DEVICE_NAME);//创建设备节点
/*
创建设备节点
1.定义static struct class *led_class;
2.注册一个类,可以在"/dev/"目录下面建立设备节点
led_class = class_create(owner,name);
owner: 恒等于THIS_MODULE,指向当前模块的指针
name: 设备节点名称,随便取
返回值NULL 错误
3.创建设备节点
device_create(led_class,NULL,devno,NULL,DEVICE_NAME);
led_class: 已经注册好的类名
parent: NULL
devno: 设备号,该文件的设备号,和字符设备对象一致
drvdata: null
DEVICE_NAME:名称,随便写
*/
return 0;
fail:
unregister_chrdev_region(devno, 1);
return ret;
}
//设备驱动模块卸载函数
static void __exit led_exit(void)
{
/*释放资源,逆序*/
device_destroy(led_class,MKDEV(led_major,led_minor));
class_destroy(led_class);//销毁设备节点
cdev_del(&led_device->cdev);//删除字符设备
kfree(led_device);//释放内存
unregister_chrdev_region(MKDEV(led_major,led_minor), 1);//释放设备号
printk(KERN_NOTICE "led_exit ok!\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("CHEN");
MODULE_LICENSE("GPL");
对应的测试APP代码如下:
#include
#include "stdio.h"
#include
#include
#include
#include
main()
{
int fd;
char *hello_node = "/dev/led_ctrl";
if((fd = open(hello_node,O_RDWR|O_NDELAY)) < 0)
{
printf("APP open %s failed\n",hello_node);
}
else
{
printf("APP open %s success\n",hello_node);
while(1)
{
ioctl(fd,1,1);
sleep(1);
ioctl(fd,0,1);
sleep(1);
}
}
close(fd);
}