使用内核通用的操作接口操作led

驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/slab.h>

struct s5pv210_led_dev{
	unsigned int major;
	struct device * led_dev;
	struct class * led_class;
	volatile unsigned long * GPC0_CON;
    volatile unsigned long * GPC0_DAT;
};

struct s5pv210_led_dev * s5pv210_dev;

int led_open (struct inode * node, struct file * filp)
{
    printk("----------%s------------\n",__FUNCTION__);
    return 0;
}

int led_release (struct inode *node, struct file * filp)
{
	printk("----------%s------------\n",__FUNCTION__);
	return 0;
}

ssize_t led_write(struct file * filp, const char __user * buff, size_t count, loff_t * offset)
{
	ssize_t ret;
	int led_cmd;
	unsigned int value;
	printk("----------%s------------\n",__FUNCTION__);
	//参数1:内核空间的buff地址
	//参数2:用户空间的buff地址
	//参数3:传递的长度
	//返回值: 返回0表示成功,如果拷贝出现异常,返回值表示没有拷贝成功的个数
	ret = copy_from_user(&led_cmd, buff, count); //从用户空间拷贝到内核空间
	//copy_to_user(void __user * to, const void * from, unsigned long n)从内核空间到用户空间的拷贝
	if(ret > 0)
	{
		printk("copy_from_user error\n");
		return ret;
	}
	if(led_cmd == 0) //关灯
	{
		value = __raw_readl(s5pv210_dev->GPC0_DAT);
		value &= ~(0x03 << 3);
		__raw_writel(value, s5pv210_dev->GPC0_DAT);
	}
	else  //开灯
	{
		value = __raw_readl(s5pv210_dev->GPC0_DAT);
		value |= (0x03 << 3);
		__raw_writel(value, s5pv210_dev->GPC0_DAT);
	}
	return 0;
}

const struct file_operations fops ={
	.owner = THIS_MODULE, // 可有可无
	.open = led_open,
	.write = led_write,
	.release = led_release,
};

static int __init drv_led_init(void)
{
    int ret;
	unsigned int value;

    //0. 创建一个全局的对象的空间
    s5pv210_dev = (struct s5pv210_led_dev *)kzalloc(sizeof(struct s5pv210_led_dev), GFP_KERNEL);
	if(s5pv210_dev == NULL)
	{
		printk("kzalloc error\n");
		return -ENOMEM;
	}
    //1. 申请/注册一个设备号
    // 设备号是一个32为的无符号整型,高12位是主设备号,低20位为次设备号
    // 主设备号:表示哪一类设备
    // 次设备号:表示哪一个设备
	//动态申请
    //参数1:0--表示动态申请
    //参数2:设备描述,自定义
    //参数3:struct file_operations结构体变量
    s5pv210_dev->major = register_chrdev(0, "drv_led", &fops);
	if(s5pv210_dev->major < 0)
	{
		printk("register_chrdev error\n");
		ret = s5pv210_dev->major;
		goto err_register_chrdev;
	}
	
	// 2. 创建类
	//参数1: THIS_MODULE,表示当前模块
	//参数2: /sys/class/下创建的目录名称,自定义
	s5pv210_dev->led_class = class_create(THIS_MODULE, "led_class");
	if(IS_ERR(s5pv210_dev->led_class))
	{
		printk("class_create error\n");
		ret = PTR_ERR(s5pv210_dev->led_class);
		goto err_class_create;
	}

	//3. 创建设备结点
	// 手动创建设备节点的方法:	mknod /dev/drv_led c 250 0
	// 参数1: 创建的类
	// 参数2: 设备的父类
	// 参数3: 设备号,包括了主设备号和次设备号,用MKDEV来合成
	// 参数4: 设备文件的私有数据
	// 参数5: 设备节点名称
	s5pv210_dev->led_dev = device_create(s5pv210_dev->led_class, NULL, MKDEV(s5pv210_dev->major, 0), NULL, "drv_led");
	if(IS_ERR(s5pv210_dev->led_dev))
	{
		printk("device_create error\n");
		ret = PTR_ERR(s5pv210_dev->led_dev);
		goto err_device_create;
	}

	//4. 硬件初始化
	//参数1:要映射的物理地址的起始
	//参数2:要映射的大小
	s5pv210_dev->GPC0_CON = ioremap(0xE0200060,8);
	s5pv210_dev->GPC0_DAT = s5pv210_dev->GPC0_CON + 1;
	
	//控制寄存器的[19:12]清零
	//控制寄存器的[19:12]赋值为0001 0001
	value = __raw_readl(s5pv210_dev->GPC0_CON);
	value &= ~(0xff << 12);
	value |= (0x11 << 12);
	__raw_writel(value, s5pv210_dev->GPC0_CON);

    //数据寄存器清零,关闭当前所有的LED 
	value = __raw_readl(s5pv210_dev->GPC0_DAT);
	value &= ~(0x03 << 3);
	__raw_writel(value, s5pv210_dev->GPC0_DAT);
		
	return 0;
	
	err_device_create:
		class_destroy(s5pv210_dev->led_class);
	err_class_create:
		unregister_chrdev(s5pv210_dev->major, "drv_led");
	err_register_chrdev:
		kfree(s5pv210_dev);
	return ret;
}

static void __exit drv_led_exit(void)
{
    iounmap(s5pv210_dev->GPC0_CON);
    device_destroy(s5pv210_dev->led_class, MKDEV(s5pv210_dev->major, 0));
	class_destroy(s5pv210_dev->led_class);
	unregister_chrdev(s5pv210_dev->major, "drv_led");
	kfree(s5pv210_dev);
}

//模块的入口函数
module_init(drv_led_init);
//模块的出口函数
module_exit(drv_led_exit);
//要遵循GPL协议
MODULE_LICENSE("GPL");

应用程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void)
{
    int fd;
	int on;
	int count = 5;
	fd = open("/dev/drv_led",O_RDWR);
	if(fd < 0)
	{
		perror("open");
		exit(1);
	}
    while(count--)
    {
		on = 1;
		write(fd, &on, sizeof(on));
	    sleep(2);
		on = 0;
		write(fd, &on, sizeof(on));
		sleep(2);
    }
	close(fd);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值