通过静态映射和动态映射设置LED灯,同时通过应用层传入的值来设置灯灭和灯亮
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>
#include <linux/string.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
char kbuf[100];
static dev_t mydev;
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)
#define GPJ0CON_PA 0xe0200240
#define GPJ0DAT_PA 0xe0200244
#define MYMAJOR 243
#define NAME "testchar"
unsigned int *pGPJ0CON;
unsigned int *pGPJ0DAT;
//static struct cdev testchar_cdev;
static struct cdev *pcdev;
static int test_open(struct inode *inode, struct file *file)
{
printk("test_open-----");
return 0;
}
static int test_release(struct inode *inode, struct file *file)
{
printk("test_release----------");
return 0;
}
static ssize_t test_read( struct file *file, char *buf, size_t count, loff_t *ppos )
{
int ret = -1;
printk("test_read----------");
//使用该函数将应用层传过来的ubuf中的内容拷贝到驱动空间的一个buf中
ret = copy_to_user(buf, kbuf, count);
if(ret)
{
printk("copy to user failed\n");
return -EINVAL;
}
return 0;
}
//写函数的本质就是将应用层传递过来的数据先复制到内核中,然后以正确的方式写入硬件,完成操作
static ssize_t test_write( struct file *file, const char *buf, size_t count,
loff_t *ppos )
{
int ret = -1;
rGPJ0CON = 0x11111111;
printk("test_write----------");
memset(kbuf, 0, sizeof(kbuf));
//使用该函数将应用层传过来的ubuf中的内容拷贝到驱动空间的一个buf中
ret = copy_from_user(kbuf, buf, count);
if(ret)
{
printk("copy from user failed\n");
return -EINVAL;
}
if(kbuf[0] == '1')
{
rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
}
else if(kbuf[0] == '0')
{
rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
}
printk("copy from user successful\n");
//从应用层过来的数据可以用来真正操控硬件
return 0;
}
//定义一个file_operation结构体
static const struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = test_open, //将来应用open打开这个设备实际调用
.release = test_release, //就是这个close对应的函数
.read = test_read,
.write = test_write,
};
static int __init chrdev_init(void)
{
int retval;
//在这里注册file_operation结构体,在module_init宏调用的函数中去注册字符设备驱动
printk("chrdev_init\n");
//使用新的接口cdev来注册字符设备驱动
//新的接口注册字符设备驱动需要两步
//1. 注册/分配主次设备号
retval = alloc_chrdev_region(&mydev, 0, 1, NAME);
if (retval < 0) {
printk("can't register character device\n");
goto out3;
}
printk("major = %d, minor = %d\n", MAJOR(mydev), MINOR(mydev));
//2. 注册设备驱动
pcdev = cdev_alloc();
//cdev_init(pcdev, &test_fops);
cdev->owner = THIS_MODULE;
cdev-> = &test_fops;
retval = cdev_add(&testchar_cdev, mydev, 1);
if (retval) {
printk("unable to cdev_add");
goto out2;
}
printk("register_chrdev successful\n");
//使用动态映射的方法来操控寄存器
if(!request_mem_region(GPJ0CON_PA, 4, "GPJ0CON"))
goto out1;
if(!request_mem_region(GPJ0DAT_PA, 4, "GPJ0DAT"))
goto out;
pGPJ0CON = ioremap(GPJ0CON_PA, 4);
pGPJ0DAT = ioremap(GPJ0DAT_PA, 4);
*pGPJ0CON = 0x11111111;
*pGPJ0DAT = ((0<<3) | (0<<4) | (0<<5)); //亮
out:
release_mem_region(GPJ0DAT_PA, 4);
out1:
release_mem_region(GPJ0CON_PA, 4);
out2:
//使用新的接口注销
//1.真正的注销字符设备驱动 cdev_del
cdev_del(pcdev);
out3:
//2.注销申请的主次设备号
unregister_chrdev_region(mydev, 1);
return 0;
}
static void __exit chrdev_exit(void)
{
//解除映射
iounmap(pGPJ0DAT);
iounmap(pGPJ0CON);
release_mem_region(GPJ0DAT_PA, 4);
release_mem_region(GPJ0CON_PA, 4);
cdev_del(pcdev);
unregister_chrdev_region(mydev, 1);
//在module_exit宏调用的函数中去注销字符设备驱动
printk("chrdev_exit\n");
}
module_init(chrdev_init);
module_exit(chrdev_exit);
MODULE_LICENSE("GPL");