在s3c2440开发板上实现字符设备led驱动程序

在s3c2440开发板上实现字符设备led驱动程序

1.环境准备
看清楚很重要
在Ubuntu虚拟机上,前提配置好相对应版本arm-linux-gcc(不是说越高版本越好,最好是开发板配套的版本)
①准备开发板相对应Linux内核源码(开发板内核版本2.6.22.6)
②打补丁
③编译内核
(网上教程很多)

我的情况:
我的开发板是韦东山老师的S3C2440,提供的内核版本是2.6.22.6。
内核源码内通过查看arch/arm/configs目录,可以查看到不同开发板所需的编译参数设置。

不同版本arm-linux-gcc配置的glibc版本不一样,像之前用的arm-linux-gcc4.4.3使用的glibc是2.4,开发板不支持2.4,如果要升级的话会很麻烦,我就用了配套的arm-linux-gcc3.4.5,它的glibc是2.3.6。

2.led驱动框架
在s3c2440开发板上实现字符设备led驱动程序_第1张图片
3.驱动代码

//led_drv.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static struct class *led_class;
static struct class_device *led_class_dev;

volatile unsigned long *gpfcon=NULL;
volatile unsigned long *gpfdat=NULL;

//open()打开/dev/led设备对应的函数
static int led_open(struct inode *inode,struct file *file)
{
    //初始化LED引脚
    *gpfcon&=~((0x3<<(4*2))|(0x3<<(5*2))|(0x3<<(6*2)));
    *gpfcon|=((0x1<<(4*2))|(0x1<<(5*2))|(0x1<<(6*2)));
    return 0;
}

//write()操作/dev/led设备对应的函数
static ssize_t  led_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
    
    int val;
    //获取用户态传递的参数
    copy_from_user(&val,buf,count);
    //通过查看引脚图,低电平亮
    if(val==1)    //点灯
    {
        *gpfdat&=~((1<<4)|(1<<5)|(1<<6));
    }
    else          //关灯
    {
        *gpfdat|=(1<<4)|(1<<5)|(1<<6);
    }
    return 0;
}

//用file_operations结构体保存对应的函数
static struct file_operations led_fops={
    .owner = THIS_MODULE,
    .open  = led_open,
    .write = led_write,
};

//主设备号
int major;

//入口函数
static int led_init(void)
{
    //自动分配主设备号,把file_operations保存到内核主设备号组中,/proc/devices文件可以查看
    major=register_chrdev(0,"led",&led_fops);
    //创建class类
    led_class = class_create(THIS_MODULE,"led");
    if(IS_ERR(led_class))
    {
        return PTR_ERR(led_class);
    }
    
    //自动创建设备节点/dev/led
    led_class_dev=class_device_create(led_class,NULL,MKDEV(major,0),NULL,"led");
    if(unlikely(IS_ERR(led_class_dev)))
    {
        return PTR_ERR(led_class_dev);
    }   
    //把物理地址映射成虚拟地址
    gpfcon=(volatile unsigned long *)ioremap(0x56000050,16);
    gpfdat=gpfcon+1;
    
    return 0;
}

//出口函数
void led_exit(void)
{
    unregister_chrdev(major,"led");
    class_device_unregister(led_class_dev);
    class_destroy(led_class);
    iounmap(gpfcon);
}

//注册驱动
module_init(led_init);
//卸载驱动
module_exit(led_exit);

MODULE_LICENSE("GPL");

Makefile

#Makefile
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL_PATH:=/home/chouti/linux-2.6.22.6

all:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
    
clean:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules clean
	rm -rf modules.order

obj-m += led_drv.o

4.使用驱动代码

#include 
#include 
#include 
#include 

int main(int argc,char **argv)
{
    int fd;
    int val=1;
    fd=open("/dev/led",O_RDWR);
    if(fd<0)
        printf("open fail!\n");
    
    if(argc!=2)
    {
        printf("Usage :\n");
        printf("%s \n",argv[0]);
        return 0;
    }
        
    if(strcmp(argv[1],"on")==0)
    {
        val=1;
        write(fd,&val,4);
    }
    else if(strcmp(argv[1],"off")==0)
    {
        val=0;
        write(fd,&val,4);
    }
    
    return 0;
}

你可能感兴趣的:(S3C2440开发板,Linux驱动,linux)