字符设备驱动应用---LED设备驱动实现

来源:互联网 发布:编程更改组策略 编辑:程序博客网 时间:2024/05/23 23:33

目标

本次实验将为开发上的LED灯实现驱动代码,应用程序可以通过ioctl系统调用控制LED灯的亮灭。

硬件资源

处理器

本人使用的开发板是讯为科技的iTop4412开发板,CPU是三星的4412,属于A9系列。

原理图

这里写图片描述
这里写图片描述
在开发板的原理图中,可以看到LED是连到GPL2_0引脚的,因此我们要控制LED,就要控制这个引脚。

寄存器物理地址转化成虚拟地址

翻看4412的芯片手册,可以找到控制led的I/O口的相关寄存器,我们需要对其进行设置。
不像裸机代码里,控制某个寄存器可以使用物理地址,在Linux系统里,用户用到的所有地址内核都认为是虚拟地址。内核看到一个地址以后把它当成虚拟地址,当内核需要读写这些地址时,需要经过内存管理子系统翻译成物理地址再读写。因此我们想要控制I/O寄存器,需要将寄存器的地址转化成虚拟地址,然后再通过虚拟地址控制这些寄存器。
内核中提供了如下宏将物理地址转化成虚拟地址:

ioremap(physaddr,size);

physaddr 是待转化的物理地址,size是物理地址的长度,返回虚拟地址。
内核还提供了若干函数给相关虚拟地址写数据:

void writel(unsigend int data,volatile void _iomem *addr);

代码实现

根据字符设备驱动,可以编写基于字符设备驱动模型的LED设备驱动,代码如下:

驱动代码

#include <linux/init.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/io.h>/*设备描述符*/struct cdev led_dev;/*设备号*/dev_t devno;/*控制寄存器地址*/#define LEDCON 0x11000100#define LEDDAT 0x11000104/*控制器转换后的虚拟地址*/unsigned int *led_con;unsigned int *led_dat; /*打开函数*/int led_open(struct inode *inode,struct file *file){    led_con = ioremap(LEDCON,4);    led_dat = ioremap(lEDDAT,4);    writel(0x00000001,led_con);    return 0;}/*控制函数*/long led_ioctl(struct file *file,unsigned int cmd,unsigned long arg){    switch(cmd){        //点亮led        case 1: writel(0x01,led_dat);                break;        //熄灭led        case 0: writel(0x00000000,led_dat);                break;        default:                return -EINVAL;    }    return 0;}/*关闭函数*/int led_close(struct inode *inode, struct file *file){    return 0;}/*文件操作函数集合*/struct file_operations led_ops = {    .open = led_open,    .unblocked_ioctl = led_ioctl,    .release = led_close,};/*模块初始化*/static int led_init(void){    int ret;    //初始化cdev    cdev_init(&led_dev,&led_ops);    //分配设备号    alloc_chrdev_region(&devno,0,1,"myled");    //注册驱动    ret = cdev_add(&led_dev,devno,1);    return ret;}/*模块注销*/static void led_exit(void){    //注销设备结构    cdev_del(&led_dev);    //注销设备号    unregister_chrdev_region(&led_dev,2);}/*遵循协议声明*/MODULE_LICENSE("GPL");/*模块安装和卸载函数*/module_init(led_init);module_exit(led_exit);

应用代码

#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <sys/ioctl.h>#include <stdio.h>#include <fcntl.h>int main(int arg,char *argv[]){    int fd;    int i=0;    if((fd=open("/dev/myled",O_RDWR))<0){        printf("App open file failed!\n");        return 0;    }    while(i++ < 4){        ioctl(fd,0);        sleep(1);        ioctl(fd,1);        sleep(1);    }    return 0;}
0 0
原创粉丝点击