之前的字符设备驱动程序的例子是虚拟的一个内存,现在以以一个实际的硬件的设计来为例子
首先LED的程序是一种字符设备程序
字符设备方法open和 ioctrl
本文博客地址:http://blog.csdn.net/b2997215859/article/details/47183419
转载请注明来源:http://blog.csdn.net/b2997215859/article/details/47183419
然后以下是源代码
首先是模块的初始化函数
static intled_init()
{
cdev_init(&cdev,&led_fops);
allo_chrdev_region(&devno, 0 , 1 ,'myled');
cdev_add(&cdev, devno , 1);
return0 ;
}
我们把硬件的初始化后放到open里来做,open和ioctl均定义在file_operations里面
static structfile_operations led_fops =
{
.open = led_open ,
.unlocked_ioctl = led_ioctl,
};
注:分好要加上,不然会报错;并且之间是用逗号隔开,不是用分号
--------------------
然后顺手完成对设备的注销
static voidled_exit()
{
cdev_del(&cdev);
unregister_chrdev_region(&devno,1);
}
第一个语句是对设备的注销
第二个语句是对设备号的注销
-------------------
添加#inlcude<linux/cdev.h>来包括cdev等初始化、注销等操作
添加##include<linux/fs.h>来包括struct file_operation等相关东东
-------------------
然后就开始实现设备函数
首先是open,在open里实现硬件的初始化,
#define GPBCON 0x56000010 //定义控制寄存器的宏
unsigned int *led_config ; //定义存放GPBCON的虚拟地址
led_config = ioremap(GPBCON , 4); //物理地址转化为虚拟地址
#define GPBDAT 0x56000014 //定义数据寄存器的宏
unsigned int *led_data; 定义存放GPBDAT的虚拟地址
writel(0x400 , led_config); // l表示写入32位的值
led_data = ioremap(GPBDAT , 4)//同时将led_data初始化
--------------------
然后是led_ioctl的实现
首先在此之前分析led_ioctl的功能有俩个,关闭和点亮,故建立led.h来定义命令
#define LED_MAGIC 'L' //定义该设备的幻数
#define LED_ON _IO(LED_MAGIC , 0); //_Io的作用见之前页面对字符设备的介绍,led没有参数传入,故使用__IO
#define LED_OFF _IO(LED_MAGIC ,1); //第一个参数是设备的幻数,第二是命令的区分符而已
定义好命令之后,便可以通过switch语句进行判别了
如果是LED_ON,则赋值0x00,如果是LED_OFF,则赋值0x11
longled_ioctl(struct file *filp, unsigned int cmd , unsigned long arg)
{
switch(cmd)
{
caseLED_ON:
writel(0x00 ,led_data);
return0;
caseLED_OFF:
writel(0xff , led_data);
return0;
default:
return-EINVAL;
}
}
注:关闭led的时候赋值是0xff而不是0x11
-----------------------
#include<linux/io.h> //writel的使用
#include "led.h" //包含头文件“led.h”
在编译的时候会出现很多问题,需要细心去调bug<,比如说这次我在led.h的后面的define语句加了分号,然后在led.c的驱动程序中就会报错,和符号什么有关,在led.c中报错233333
然后编写驱动程序即可
贴出源码如下
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include"led.h"
int main(int argc,char *argv[])
{
int fd;
int cmd;
if (argc <2 )
{
printf("please enter the secondpara!\n");
return0;
}
cmd = atoi(argv[1]);
fd = open("/dev/myled",O_RDWR);
if (cmd == 1)
ioctl(fd,LED_ON);
else
ioctl(fd,LED_OFF);
return 0;
}
----------------------------------------------------------------
Led驱动程序的源代码如下
#include<linux/module.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/io.h>
#include "led.h"
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
unsigned int *led_config ;
unsigned int *led_data;
struct cdev cdev ;
dev_t devno;
int led_open(struct inode *node, struct file *filp)
{
led_config = ioremap(GPBCON,4);
writel(0x400,led_config);//l表示写入的是32位的值
led_data = ioremap(GPBDAT,4);
return 0;
//mov r1, #0x0
}
long led_ioctl(struct file *filp, unsigned int cmd , unsigned long arg)
{
switch(cmd)
{
case LED_ON:
writel(0x00,led_data);
return 0;
case LED_OFF:
writel(0xff,led_data);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations led_fops =
{
.open = led_open ,
.unlocked_ioctl = led_ioctl,
};
static int led_init()
{
cdev_init(&cdev,&led_fops);
alloc_chrdev_region(&devno , 0 , 1 ,"myled");
cdev_add(&cdev , devno , 1);
return 0 ;
}
static void led_exit()
{
cdev_del(&cdev);
unregister_chrdev_region(devno,1);
}
module_init(led_init);
module_exit(led_exit);