整理一下思路,刚刚看的mini2440 led驱动。
mini2440的led接了4个GPIO,分别是GPB5-8
关于这几个GPIO的寄存器描述可以看三星的文档,主要是GPBCON,GPBDAT和GPBUP,GPBCON寄存器可以表示某引脚是输入功能还是输出功能,因为这些引脚是复用的。GPBDAT用来给某引脚读写数据的。GPBUP表示是否使用内部上拉电阻,这里没有用上,貌似,不懂。
linux对ARM支持很好,有关gpio的操作都有函数写好了,直接用就可以。
以前真是傻呀,自己写,呵呵。
linux/arch/arm/plat-s3c24xx/gpio.c描述了对gpio的操作,这里用到两个函数:
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i], 0);
第一个函数是设置led_table[i]表示的引脚为输入或者输出(led_cfg_table[i]定义的),其实就是设置GPBCON寄存器;
第二个函数是设置引脚读写数据为0或者其他值,比如1.
led_table[i], led_cfg_table[i]在这个文件里都有定义,定义中涉及的宏S3C2410_GPB6 和S3C2410_GPB6_OUTP 之类都在arch/arm/mach-s3c2410/include/mach/regs-gpio.h中定义好了。
下面的就是LED的驱动程序:
#include <linux/miscdevice.h> #include <linux/delay.h> #include <asm/irq.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/string.h> #include <linux/list.h> #include <linux/pci.h> #include <asm/uaccess.h> #include <asm/atomic.h> #include <asm/unistd.h>
#define DEVICE_NAME "leds" 设备名
static unsigned long led_table [] = { 4个对应的引脚 S3C2410_GPB5, S3C2410_GPB6, S3C2410_GPB7, S3C2410_GPB8, };
static unsigned int led_cfg_table [] = { 引脚功能都是输出 S3C2410_GPB5_OUTP, S3C2410_GPB6_OUTP, S3C2410_GPB7_OUTP, S3C2410_GPB8_OUTP, };
static int sbc2440_leds_ioctl( ioctl具体实现,对应应用程序中的ioctl struct inode *inode, struct file *file, 这个参数对应应用程序中的第一个参数,文件 unsigned int cmd, 两个值,0或1,led灭或者亮 unsigned long arg) 参数个数,不能超过4,表示只有4个led { switch(cmd) { case 0: case 1: if (arg > 4) { return -EINVAL; } s3c2410_gpio_setpin(led_table[arg], !cmd); 设置某个led数据0或1 return 0; default: return -EINVAL; } }
file_operations 数据结构填充 static struct file_operations dev_fops = { .owner = THIS_MODULE, .ioctl = sbc2440_leds_ioctl,对应的ioctl函数实现 };
misc设备,也就是非字符,非块,非网络,其他设备。这种设备统一采用一个主设备号 static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, 次设备号 .name = DEVICE_NAME, .fops = &dev_fops, };
static int __init dev_init(void) 初始化设备 { int ret;
int i; for (i = 0; i < 4; i++) { 设置引脚为输出功能
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); 各引脚写入0,即都是不亮的
s3c2410_gpio_setpin(led_table[i], 0); }
ret = misc_register(&misc); 注册misc设备
printk (DEVICE_NAME"\tinitialized\n");
return ret; }
static void __exit dev_exit(void) { misc_deregister(&misc); 注销misc设备 }
module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("FriendlyARM Inc.");
|
led的应用程序如下:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h>
int main(int argc, char **argv) 带参数,一共是三个 { int on; int led_no; int fd;
//if条件表示,有三个参数,on的值只能是0或者1,led_no的值只能是0-3
//sscanf的返回值为0,出错,否则返回正确格式化数据的个数,这样就确保main参数每个都读的争取 if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 || on < 0 || on > 1 || led_no < 0 || led_no > 3) { fprintf(stderr, "Usage: leds led_no 0|1\n"); exit(1); } fd = open("/dev/leds0", 0); 不知道什么意思? if (fd < 0) { fd = open("/dev/leds", 0); 读取设备 } if (fd < 0) { perror("open device leds"); exit(1); } ioctl(fd, on, led_no); 调用ioctl,和驱动里的对应。不过那个ioctl函数貌似四个参数,第一个参数是inode节点,后面三个和这里是对应的,有点茫然。 close(fd); return 0; }
|
交叉编译后,执行:
#./led 2 1
第三个led亮
阅读(903) | 评论(0) | 转发(0) |