LED的驱动程序很简单,按照张字符型设备驱动设计方法顺下来即可实现,这里主要讲几个注意事项。
一、在linux系统中,操作硬件不能够使用物理地址,一定要用虚拟地址。将物理地址转化为虚拟地址的函数如下:
#define ioremap(cookie,size)
其中cookie为要转化的物理地址,size为转化空间的大小,单位为字节。返回值为转化后的虚拟地址。
二、在执行程序时我们需要顺带输入参数进去,但是是以字符串的形式输入的,不方便操控。所以用atoi函数将字符串转化为整数,函数原型如下:
int atoi(const char *nptr);
三、点亮LED是对设备的控制,而不是读写。即在驱动程序中ioctl函数里相对应的寄存器的虚拟地址写入值即可。向某个地址写入值的函数为writel函数,原型:
static inline void writel(unsigned int b, volatile void __iomem *addr)
第一个参数为写入的值,第二个参数是虚拟地址。
接下来也没什么了,最关键的就是驱动程序模型。要想写出字符设备驱动一定要学好它,特别重要!!
头文件:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/io.h> #define LED_MAGIC 'L'
#define LED_OFF _IO(LED_MAGIC,0)
#define LED_1 _IO(LED_MAGIC,1)
#define LED_2 _IO(LED_MAGIC,2)
#define LED_3 _IO(LED_MAGIC,3)
#define LED_4 _IO(LED_MAGIC,4)
#define LED_ALL _IO(LED_MAGIC,5)
驱动程序代码:
#include "led.h" #define GPBCON 0x56000010
#define GPBDAT 0x56000014 /*控制LED寄存器的物理地址*/
unsigned int *led_config;
unsigned int *led_data; /*存储设备号*/
dev_t devno; /*分配cdev*/
struct cdev cdev; int led_open(struct inode *node, struct file *filp)
{
/*将物理地址转为虚拟地址*/
led_config = ioremap(GPBCON,);
led_data = ioremap(GPBDAT,); /*向某一地址写入值*/
writel(0x15400,led_config); return ;
}
/*驱动程序里的设备控制函数*/
long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case LED_1:
writel(0b00011100000,led_data);
return ;
case LED_2:
writel(0b00101100000,led_data);
return ;
case LED_3:
writel(0b00110100000,led_data);
return ;
case LED_4:
writel(0b00111000000,led_data);
return ;
case LED_OFF:
writel(0b00111100000,led_data);
return ;
case LED_ALL:
writel(,led_data);
return ; default:
return -EINVAL;
}
} /*函数映射关系表*/
struct file_operations led_fops =
{
.open = led_open,
.unlocked_ioctl = led_ioctl,
}; static int led_init()
{ /*初始化cdev*/
cdev_init(&cdev, &led_fops);
/*注册cdev*/
alloc_chrdev_region(&devno, , ,"myled"); //动态分配设备号,第四个参数为设备名称
cdev_add(&cdev, devno, );
return ;
} static void led_exit()
{
/*删除设备*/
cdev_del(&cdev);
/*释放设备号*/
unregister_chrdev_region(devno,);
} MODULE_LICENSE("GPL");
module_init(led_init);
module_exit(led_exit);
应用程序代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include "led.h" int main(int argc, char *argv[])
{
int fd;
int cmd; if (argc < )
{
printf("please enter the second para!\n");
return ;
} cmd = atoi(argv[]); fd = open("/dev/myled",O_RDWR); if(cmd == )
ioctl(fd,LED_OFF);
if(cmd == )
ioctl(fd,LED_1);
if(cmd == )
ioctl(fd,LED_2);
if(cmd == )
ioctl(fd,LED_3);
if(cmd == )
ioctl(fd,LED_4);
if(cmd == )
ioctl(fd,LED_ALL); return ;
}