s3c2440基于linux的led字符设备驱动样例及测试.docx
《s3c2440基于linux的led字符设备驱动样例及测试.docx》由会员分享,可在线阅读,更多相关《s3c2440基于linux的led字符设备驱动样例及测试.docx(8页珍藏版)》请在冰豆网上搜索。
s3c2440基于linux的led字符设备驱动样例及测试
#include//配置头文件
#include/*内核头文件,作为系统核心的一部分,设备驱动程序在申请和释放内存时,不是调用malloc和free,而是调用kmalloc和kfree*/
#include//调度,进程睡眠,唤醒,中断申请,中断释放
#include//时钟头文件
#include//用户定义模块初始函数名需引用的头文件
#include//模块加载的头文件
#include
#include//这个是2440的寄存器头文件,asm/srch只是个链接
//实际根据自己的情况查找,一般是../../linux2.*.*/include/asm/arch-s3c2440里编译器
//自己会查询链接,以前不知道,找了半天
//GPIO_LEDDEVICEMAJOR
#defineGPIO_LED_MAJOR 97 //定义主设备号
//defineLEDSTATUS 我的板子LED在GPB0与GPB1 处大家根据自己情况改
#defineLED_ON 0//定义LED灯的状态开
#defineLED_OFF1//
//-------------------READ------------------------ 这个前面要加static否则警告
staticssize_tGPIO_LED_read(structfile*file,char*buf,size_tcount,loff_t*f_ops)
{
returncount;
}
//-------------------WRITE-----------------------
staticssize_tGPIO_LED_write(structfile*file,constchar*buf,size_tcount,loff_t*f_ops)
{
returncount;
}
//-------------------IOCTL-----------------------
staticssize_tGPIO_LED_ioctl(structinode*inode,structfile*file,unsignedintcmd,longdata) //这个函数实现了led灯亮灭的接口
{
switch(cmd)
{
caseLED_ON:
{GPBDAT=0x01;break;} //根据自己情况修改一个亮一个灭
caseLED_OFF:
{GPBDAT=0x02;break;} //交替闪烁
default:
{printk("lcdcontrol:
nocmdrun [--kernel--]\n");return(-EINVAL);}
}
return0;
}
//-------------------OPEN------------------------
staticssize_tGPIO_LED_open(structinode*inode,structfile*file)
{
MOD_INC_USE_COUNT;
return0;
}
//-------------------RELEASE/CLOSE---------------
staticssize_tGPIO_LED_release(structinode *inode,structfile*file)
{
MOD_DEC_USE_COUNT;
return0;
}
//-------------------------------------------------
structfile_operationsGPIO_LED_ctl_ops={
open:
GPIO_LED_open, //这段赋值代码必须放在接口函数申明之后
read:
GPIO_LED_read, //否则编译不过去
write:
GPIO_LED_write,
ioctl:
GPIO_LED_ioctl,
release:
GPIO_LED_release,
};
//-------------------INIT------------------------
staticintGPIO_LED_CTL_init(void)
{
intret=-ENODEV;
printk("--------------------------------------------\n\n");
GPBCON=0x0005; //设置端口为I/O输出模式
GPBUP =0xff; //关闭上拉功能
GPBDAT=0xf; //初始值为高电平熄灭LED灯
ret=register_chrdev(GPIO_LED_MAJOR,"gpio_led_ctl",&GPIO_LED_ctl_ops);
//这个驱动注册函数必须放在复制接口的那个结构体之后
if(ret<0)
{
printk("S3C2410:
init_modulefailedwith%d\n",ret);
returnret;
}
else
{
printk("S3C2410gpio_led_driverregistersuccess!
!
!
\n");
}
returnret;
}
staticint__initS3C2410_GPIO_LED_CTL_init(void)
{
int ret=-ENODEV;
ret=GPIO_LED_CTL_init();
if(ret)
returnret;
return0;
}
staticvoid__exitcleanup_GPIO_LED_ctl(void)
{
unregister_chrdev(GPIO_LED_MAJOR,"gpio_led_ctl");
}
module_init(S3C2410_GPIO_LED_CTL_init);
module_exit(cleanup_GPIO_LED_ctl);
完了编译这个驱动函数
makefile如下:
#################################################
#config
#wherethekernelsourcesarelocated 这是我的内核头文件的路径根据自己的修改
KERNEL_DIR:
=../../../linux-2.4.20
#################################################
#somemagicforusinglinuxkernelsettings
#whencompilingmodule(s)
#fornew-stylekernelMakefiles(2.4)
export-objs :
=led.o //要编译好的对象
list-multi :
=
obj-m :
=led.o
here:
(cd$(KERNEL_DIR);makeSUBDIRS=$(PWD)modules)//make
clean:
-rm-f*.o.*.o.flags*~
include$(KERNEL_DIR)/Rules.make //make的规则根据自己的情况修改
编译好以后,接下来就是测试是否可以使用驱动了
测试函数如下:
#include
#include
#include
#include //open()close()
#include //read()write()
#defineDEVICE_NAME"/dev/gpio_led_ctl" //这是设备驱动名字,一会要建立
//defineLEDSTATUS
#defineLED_ON 0
#defineLED_OFF1
//-------------------------------------main---------------------------------------------
intmain(void)
{
intfd;
intret;
char*i;
printf("\nstartgpio_led_drivertest\n\n");
fd=open(DEVICE_NAME,O_RDWR);
printf("fd=%d\n",fd);
if(fd==-1)
{
printf("opendevice%serror\n",DEVICE_NAME);
}
else
{
while
(1)
{ ioctl(fd,LED_OFF); //GPB0亮GPB1灭
sleep
(1); //等待1秒再做下一步操作
ioctl(fd,LED_ON); //反过来
sleep
(1);
}
//close
ret=close(fd);
printf("ret=%d\n",ret);
printf("closegpio_led_drivertest\n");
}
return0;
}//endmain
makefile如下:
CROSS=/opt/host/armv4l/bin/armv4l-unknown-linux-
//交叉编译工具路径根据自己修改
CC=$(CROSS)gcc
AR=$(CROSS)ar
STRIP=$(CROSS)strip
EXEC=test //生成的可执行文件
OBJS=test.o
all:
$(EXEC)
$(EXEC):
$(OBJS)
$(CC)$(LDFLAGS)-o$@$(OBJS)$(LIBM)$(LDLIBS)$(LIBGCC)-lm //编译
clean:
-rm-f$(EXEC)*.elf*.gdb*.o
接下来就是最后的调试了:
首先把生成的led.o和test载到板子上
然后:
insmodled.o //成功的话,会打印sucess
lsmod //查看内核里面是否已经有led驱动模块
mknod /dev/gpio_led_ctlc971 //新建LED的测试设备节点,给test.c使用
// /dev/gpio_led_ctl是打开的设备名称,要和测试代码匹配
//c代表字符设备
//97是主设备好,与驱动程序匹配 1是从设备号只有一个选1
最后执行:
./test //成功了会打印一些信息这是你会看到你的板子上LED交替亮灭间隔1s
补上一点“
/opt/FriendlyARM/mini2440/linux-2.6.29/arch/arm/plat-s3c24xx/include/plat/map.h
这个是linux2.6.69内核下的24X0寄存器定义头文件,里面定义了特殊功能寄存器的PA向VA的映射。
记在这里,免得以后又找不到了。
在2.6.29上,S3C24xx相关的头文件存放于下面这些目录中
arch/arm/mach-s3c2410/include
arch/arm/mach-s3c2400/include
arch/arm/mach-s3c2412/include
arch/arm/mach-s3c2440/include
arch/arm/mach-s3c2442/include
arch/arm/mach-s3c2443/include
arch/arm/plat-s3c24xx/include
arch/arm/plat-s3c/include
例如:
s3c2410_gpio_cfgpin
为什么是S3C2410的呢?
因为三星出品的S3C2440芯片所用的寄存器名称以及资源分配大部分和S3C2410是相同的,在目前各个版本的Linux系统中,也大都采用了相同的函数定义和宏定义。
它们从哪里定义?
细心的用户或许很快就想到它们和体系结构有关,因此你可以在linux-2.6.32.2/arch/arm/mach-s3c2410/include/mach/hardware.h文件中找到该函数的定义,关于该函数的实际实现则可以在linux-2.6.32.2/arch/arm/plat-s3c24xx/gpio.c中找到,