1)引脚功能设为输出。 2)要点亮LED,令引脚输出为0. 3)要熄灭LED,令引脚输出为1.
下边给出详细的源码注释:
必要的头文件
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <machhardware.h>
#include <linux/gpio.h>
#define DEVICE_NAME "leds_control" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
#define LED_MAJOR 231 /* 主设备号 */ #define IOCTL_LED_ON 0 /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */ #define IOCTL_LED_OFF 1 static unsigned long led_table [] = { /* 用来指定LED所用的GPIO引脚 */ S3C2410_GPB(5), S3C2410_GPB(6), S3C2410_GPB(7), S3C2410_GPB(8), }; static unsigned int led_cfg_table [] = { /* 用来指定GPIO引脚的功能:输出 */ S3C2410_GPIO_OUTP, S3C2410_GPIO_OUTP, S3C2410_GPIO_OUTP, S3C2410_GPIO_OUTP, }; //应用程序对设备文件/dev/leds执行open(...)时,就会调用s3c2410_leds_open函数 static int s3c2410_leds_open(struct inode *inode, struct file *file) { int i; for (i = 0; i < 4; i++) { // 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能 s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); } return 0; } //应用程序对设备文件/dev/leds执行ioclt(...)时,就会调用s3c2410_leds_ioctl函数 static int s3c2410_leds_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { if (arg > 4) { return -EINVAL; } switch(cmd) { case IOCTL_LED_ON: // 设置指定引脚的输出电平为0 s3c2410_gpio_setpin(led_table[arg], 0); return 0; case IOCTL_LED_OFF: // 设置指定引脚的输出电平为1 s3c2410_gpio_setpin(led_table[arg], 1); return 0; default: return -EINVAL; } } //字符设备驱动程序的核心,当应用程序操作设备文件时所调用的open、read、write等函数,最终会调用这个结构中指定的对应函数 static struct file_operations s3c2410_leds_fops = { .owner = THIS_MODULE,
.open = s3c2410_leds_open, .ioctl = s3c2410_leds_ioctl, }; //执行“insmod s3c2410_leds.ko”命令时就会调用这个函数 static int __init s3c2410_leds_init(void) { int ret; /* 注册字符设备驱动程序 * 参数为主设备号、设备名字、file_operations结构; * 这样,主设备号就和具体的file_operations结构联系起来了, * 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数 * LED_MAJOR可以设为0,表示由内核自动分配主设备号 */ ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c2410_leds_fops); if (ret < 0) { printk(DEVICE_NAME " can't register major number\n"); return ret; } printk(DEVICE_NAME " initialized\n"); return 0; }
//执行”rmmod s3c24xx_leds.ko”命令时就会调用这个函数 static void __exit s3c2410_leds_exit(void) { unregister_chrdev(LED_MAJOR, DEVICE_NAME);/* 卸载驱动程序 */
}
module_init(s3c2410_leds_init); /* 指定驱动程序的初始化函数和卸载函数 */
module_exit(s3c2410_leds_exit);
怎么使用,使用方法有两种(假设保存为leds_control.c):
方法一:
将代码放到内和drivers/char目录下,在drivers/char/Makefile中增加一行obj-m += leds_control.o,然后在内核根目录下执行make modules,就可以生成模块drivers/char/leds_control.ko。
方法二:
直接在当前驱动源码目录下,建立Makefile文件,内容如下:
CROSS=arm-linux-
#依赖的内核源代码目录,不一定是当前系统的,要是开发板系统源码的目录
KERNELDIR = /opt/linux-2.6.32.2
PWD := $(shell pwd)
.PHONY:
<tab>modules clean
obj-m += leds_control.o
modules:
<tab>$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
<tab>rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
然后执行make,可以看到在当前目录下也会生成leds_control.ko.
通过以上两不,生成了leds_control.ko,下面就用ftp下载到开发板上,用:
insmod ./leds_control.ko
mknod /dev/leds_control c 150 0
就建好了驱动模块和设备节点