ARM开发之杂项设备的编写----以LED驱动为例

平台:S5PV210


杂项设备的好处:

有了字符型设备后,为什么要用杂项设备?

1.节省主设备号,所有杂项设备的主设备号都是10

2.杂项设备开发起来比字符型设备简单


开发步骤:

1.定义1个杂项设备

2.定义杂项设备的文件操作集

3.申请物理内存区

4.获取相应的虚拟地址

5.注册混杂设备

6.示例代码


1.定义杂项设备

static struct miscdevice led_misc = {
	.minor = MISC_DYNAMIC_MINOR, 
	.name = "misc_led",
	.fops = &fops,	
};
如上代码:其中.minor代表动态生成次设备号,不用改。

.name表示这个混杂设备文件结点的名字,用户程序用open在 /dev 目录下打开文件的就是 .name 的值。

.fops代表杂项设备的文件操作集


2.定义文件操作集

static struct file_operations fops =
{
	.owner = THIS_MODULE,
	.open = misc_open,
        .write = misc_write,
};
文件操作集表示了杂项设备用了哪些系统调用,如上代码就是用了 open 和 write。

第一个参数不用变,.owner一定写THIS_MODULE,用于初始化。


3.申请物理内存区

static struct resource *res = NULL;
res = request_mem_region(0xE0200280,8,"LED");
上面表示,控制LED的物理地址为0XE0200280开始,8个字节,并把这段内存起名为LED


4.获取相应虚拟地址。

操作系统操作的都是虚拟地址。

static unsigned int va = NULL;
va = ioremap(0xE02000A0,8);
va就是物理地址映射的虚拟地址的起始地址。


5.注册杂项设备

int ret;
ret = misc_register(&led_misc);
	if(ret < 0)
	{
		printk("misc register is error\n");
		return -1;
	}
misc_register()的参数就是第一步定义的杂项设备变量。



6.示例代码(LED驱动)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/miscdevice.h>

static struct resource* res = NULL;
static unsigned int *GPJ2CON_VA = NULL;
static unsigned int *GPJ2DAT_VA = NULL;
static char wbuf[1];

static ssize_t misc_write(struct file *f, const char __user*buf,
	 size_t len, loff_t *t)
{
	copy_from_user(wbuf,buf,len);
	if(wbuf[0] == '0')
	{
		*GPJ2DAT_VA &=~0xf;
	}

	if(wbuf[0] == '1')
	{
		*GPJ2DAT_VA &=~0xf;
		*GPJ2DAT_VA |=0xf;
	}
	return 0;
}

/*2.定义文件操作集*/
static struct file_operations fops={
	.owner = THIS_MODULE,
	.write = misc_write,
};

/*1.定义misc杂项设备变量*/
static struct miscdevice misc_led={
	.minor = MISC_DYNAMIC_MINOR,
	.name = "led_misc",
	.fops = &fops,
};

static int __init misc_init(void)
{
	int ret;
	/*3.申请物理内存*/
	res = request_mem_region(0xe0200280,8,"LED");
	if(res == NULL)
	{
		printk("failed to request_mem_region\n");
		goto failed_request_mem;
	}

	/*4.获取虚拟地址*/
	GPJ2CON_VA = ioremap(0xe0200280,8);
	if(GPJ2CON_VA == NULL)
	{
		printk("failed to ioremap\n");
		goto failed_ioremap;
	}
	GPJ2DAT_VA = GPJ2CON_VA + 1;

	/*5注册杂项设备*/
	ret = misc_register(&misc_led);
	if(ret<0)
	{
		printk("failed to register misc\n");
		goto failed_register;
	}
	printk("init completed\n");
	return 0;

failed_register:
	iounmap(GPJ2CON_VA);
failed_ioremap:
	release_mem_region(0xe0200280,8);
failed_request_mem:
	return -1;
}

static void __exit misc_exit(void)
{
	iounmap(GPJ2CON_VA);
	release_mem_region(0xe0200280,8);
	misc_deregister(&misc_led);
}

module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

用户程序测试代码:

#include <stdio.h>
#include <fcntl.h>

int main()
{
	char buf[1];
	buf[0]='0';

	int fd = open("/dev/led_misc",O_WRONLY);
	if(fd<0)
	{
		perror("failed to open");
		return -1;
	}
	while(1)
	{
		write(fd,buf,1);
		sleep(1);
		buf[0] = '1';
		write(fd,buf,1);
		sleep(1);
		buf[0] = '0';	
	}
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值