【Tiny6410 And Linux】——LED 驱动程序设计——代码

换了个博客写东西,可能因为这个博客更专业点吧,新浪博客我以后就会对我的爱好做个专门的总结,我的欧美音乐,就是你啦!!!!

还有就是 CSDN 贴代码真的好方便,大爱啊!!

今天呢,还是五一放假中,所以还是特别的悠闲的,不过五一过了之后就一定要继续学,嵌入式 Linux 内核的深入,(*^__^*) 嘻嘻……,期待,等待!!

LED 驱动程序设计,原理以前在新浪早就写了,是国嵌的课件,好了,废话不多说,那就先上程序,然后贴图!

1、驱动程序

①、led.h

#ifndef _LED_H_#define _LED_H_#define DEVICE_NAME"tiny6410_led"#define LED_IOC_MAGIC'l'// 幻数#define LED_IOCGETDAT_IOR(LED_IOC_MAGIC,1,int)// LED 命令#define LED_IOCSETDAT_IOW(LED_IOC_MAGIC,2,int)#define LED_IOC_MAXNR2#endif

②、led.c

#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/cdev.h>#include <linux/slab.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/ioport.h>#include <asm/io.h>#include <linux/miscdevice.h>#include "led.h"unsigned long GPIOK_VA_BASE;// led 对应 GPIOK 虚拟地址#define GPIOK_CON0_VAGPIOK_VA_BASE// led 对应 GPIOK 寄存器虚拟地址#define GPIOK_CON1_VAGPIOK_VA_BASE + 0X4#define GPIOK_DAT_VAGPIOK_VA_BASE + 0X8#define GPIOK_PUD_VAGPIOK_VA_BASE + 0XC#define GPIOK_PA_BASE0X7F008800// led 对应 GPIOK 物理地址struct resource tiny6410_led_resource = {.name = "led_io_mem",.start = GPIOK_PA_BASE,.end = GPIOK_PA_BASE + 0X10,.flags  = IORESOURCE_MEM,};/* * tiny6410_led_pin_setup * 完成申请,映射,映射获得的虚拟地址由全局变量 GPIOK_VA_BASE 获得。 * 同时,对 GPIOK 的配置寄存器进行初始化,设置 led 对应端口为输出。 */static void tiny6410_led_pin_setup(void){unsigned long start = tiny6410_led_resource.start;unsigned long size = tiny6410_led_resource.end - start;unsigned long tmp;/* 申请 I/O 内存 */request_mem_region(start,size,tiny6410_led_resource.name);/* 映射 I/O 内存 */GPIOK_VA_BASE = (unsigned long)ioremap(start,size);printk("<1>[GPIOK_VA_BASE = 0x%lx]\n",GPIOK_VA_BASE);/* 对应管教设置为输出 */tmp = readl(GPIOK_CON0_VA);tmp = (tmp & ~(0xffff << 16)) | (0x1111 << 16);writel(tmp,GPIOK_CON0_VA);/* 对应管脚置高,使 led 全灭 */tmp = readl(GPIOK_DAT_VA);tmp &= ~(0xf << 4);writel(tmp,GPIOK_DAT_VA);}/*  * tiny6410_led_pin_release(void) * led 端口释放函数比较简单,仅仅是进行申请和映射的逆过程 */static void tiny6410_led_pin_release(void){iounmap((void *)GPIOK_VA_BASE);release_mem_region(tiny6410_led_resource.start,tiny6410_led_resource.end - tiny6410_led_resource.start);}/*  * 读 led 对应 GPIO 数据寄存器值的操作函数。 */static unsigned long tiny6410_led_getdat(void){return((readl(GPIOK_DAT_VA) >> 4) & 0XF);}/*  * 写 led 对应 GPIO 数据寄存器值的操作函数 */static void tiny6410_led_setdat(int dat){unsigned long tmp;tmp = readl(GPIOK_DAT_VA);tmp = (tmp & ~(0xf << 4)) | ((dat & 0xf) << 4);writel(tmp,GPIOK_DAT_VA);}/* * 实现 led 的 I/O 操作函数 * 对于命令 LED_IOCGETDAT,我们调用函数 tiny6410_led_getdat() 获得对应端口 * 寄存器的值,并通过 put_user() 函数将它传回用户空间。同样,对于命令 * LED_IOCSETDAT,则将用户空间传过来的值,通过函数 tiny6410_led_setdat()  * 设置对应的寄存器。 */static long led_ioctl(struct file *filp,unsigned int cmd,unsigned long arg){int ioarg,ret;int err = 0;/* 检测命令的有效性,通过系统定义的宏操作 */if(_IOC_TYPE(cmd) != LED_IOC_MAGIC)return -EINVAL;if(_IOC_NR(cmd) > LED_IOC_MAXNR)return -EINVAL;/* 根据命令类型,来检测参数空间是否可以访问 */if(_IOC_DIR(cmd) & _IOC_READ)/* 这里 access_ok() 返回值中:1 成功!0 失败! */err = !access_ok(VERIFY_WRITE,(void *)arg,_IOC_SIZE(cmd));else if(_IOC_DIR(cmd) & _IOC_WRITE)err = !access_ok(VERIFY_READ,(void *)arg,_IOC_SIZE(cmd));if(err)return -EFAULT;/* 根据命令,执行相应的操作 */switch(cmd){/* 获取 led 对应的 rGPIOKDAT */case LED_IOCGETDAT:ioarg = tiny6410_led_getdat();ret = __put_user(ioarg,(int *)arg);break;/* 设置 led 对应的 rGPIOKDAT */case LED_IOCSETDAT:ret = __get_user(ioarg,(int *)arg);tiny6410_led_setdat(ioarg);break;/* default */default:return -EINVAL;}return ret;}/* * 文件操作结构体 */static const struct file_operations dev_fops ={.unlocked_ioctl = led_ioctl,.owner = THIS_MODULE,};/*  * 混杂设备 * 在编写混杂型字符设备驱动中,主设备号已经确定,此设备号可以指定 * MISC_DYNAMIC_MINOR,这样在注册设备时,内核会自动分配次设备号。 */static struct miscdevice misc ={.minor = MISC_DYNAMIC_MINOR,// 次设备号.name = DEVICE_NAME,// 设备名.fops = &dev_fops,// 文件操作};/* * 设备驱动模块加载函数 */static int __init dev_init(void){int ret;tiny6410_led_pin_setup();ret = misc_register(&misc);printk("<1>Initialized minor = %d\n",misc.minor);// 在使用 misc_register() 注册// 混杂设备后,还会在 /dev 目录// 下自动创建设备节点,节点名称// 由设备名 DEVICE_NAME 指定。return ret;}/* 模块卸载函数 */static void __exit dev_exit(void){tiny6410_led_pin_release();misc_deregister(&misc);}module_init(dev_init);module_exit(dev_exit);

③、Makefile

ifneq ($(KERNELRELEASE),)obj-m := led.oelseKDIR := /home/_Jana/linux-2.6.38all:make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-clean:rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.orderendif

2、测试程序

①、led.h(跟上面的一样!)

②、app_led.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include "led.h"#define DEV_NAME"/dev/"DEVICE_NAMEint binstr_to_int(char *binstr){int ret = 0;int i = 0;char bnum[5];memset(bnum,'0',4);int len = strlen(binstr);if(len > 4)strcpy(bnum,binstr + len - 4);elsestrcpy(bnum + 4 - len,binstr);for(i = 0;i < 4;i ++){ret <<= 1;ret += (bnum[i] == '0' ? 1 : 0);}return ret;}int main(int argc,char **argv){if(argc > 2){printf("Usage: %s <binary code>\n""example: %s 1001 -- Will turn on led 0 and 3,""and turn off led 1 and 2.\n",argv[0],argv[0]);_exit(EXIT_FAILURE);}int fd,arg;if((fd = open("/dev/tiny6410_led",O_RDWR)) == -1){printf("Open dev error!\n");_exit(EXIT_FAILURE);}if(argc == 1){ioctl(fd,LED_IOCGETDAT,&arg);printf("led dat: %d.\n",arg);}else{arg = binstr_to_int(argv[1]);printf("arg = %d.\n",arg);ioctl(fd,LED_IOCSETDAT,&arg);}_exit(EXIT_SUCCESS);}

3、测试结果

看着它洗涤一缕缕阳光,看着它映衬一片片星辉,

【Tiny6410 And Linux】——LED 驱动程序设计——代码

相关文章:

你感兴趣的文章:

标签云: