LED燈比較簡單,在linux系統中,LED被看做一個字元裝置來使用。是以它有字元裝置的操作方法。
字元裝置重要的結構體
硬體電路

編寫驅動程式
編寫方法可以參考“裸機代碼”。具體如下
< driver / led.c >建立目錄driver且在目錄下建立led.c檔案
/*
*
*This is a led driver test.(2014/8/26)
*The author is Alan
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#define DEVICE_NAME "leds"
static int led_gpios[]={
S5PV210_GPJ2(0),
S5PV210_GPJ2(1),
S5PV210_GPJ2(2),
S5PV210_GPJ2(3),
};
#define LED_NUM ARRAY_SIZE(led_gpios)
//實作系統的IO控制指令
static long gec210_leds_ioctl(struct file *flip,unsigned int cmd,
unsigned long arg)
{
switch(cmd)
{
case 0:
case 1:
if(arg>LED_NUM)
return -EINVAL;
gpio_set_value(led_gpios[arg],cmd);//(原代碼有錯)
break;
default:
return -EINVAL;
}
return 0;
}
//初始化file_operations結構體,實作系統調用
static struct file_operations gec210_led_dev_fops={
.owner = THIS_MODULE,
.unlocked_ioctl = gec210_leds_ioctl,
};
//初始化雜項裝置結構體
static struct miscdevice gec210_led_dev={
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &gec210_led_dev_fops,
};
//驅動裝載函數
static int __init gec210_led_dev_init(void)
{
int ret;
int i;
for(i=0;i<LED_NUM;i++)//輪詢請求IO資源
{
ret=gpio_request(led_gpios[i],"LED");
if(ret)//請求不成功
{
printk("%s: request GPIO %d for LED failed,ret = %d\n",
DEVICE_NAME,led_gpios[i],ret);
return ret;
}
s3c_gpio_cfgpin(led_gpios[i],S3C_GPIO_OUTPUT);//配置GPIO為輸出
gpio_set_value(led_gpios[i],1);//設定GPIO輸出1,即LED滅
}
ret = misc_register(&gec210_led_dev); //注冊雜項裝置
printk("\t%s initalized\n",DEVICE_NAME);//(原代碼有錯)
return ret;
}
//驅動解除安裝函數
static void __exit gec210_led_dev_exit(void)
{
int i;
for(i=0; i<LED_NUM;i++)//輪詢釋放IO資源
gpio_free(led_gpios[i]);
misc_deregister(&gec210_led_dev);//登出雜項裝置
}
module_init(gec210_led_dev_init);
module_exit(gec210_led_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ALAN");
編寫驅動程式的makefile
< driver / Makefile >
ifneq ($(KERNELRELEASE),)
obj-m :=led.o
else
module-objs :=led.o
KERNELDIR :=/home/gec/linux_kernel/linux2.6.35.7/
PWD :=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
$(RM) *.ko *.mod.c *.mod.o *.o *.order *.symvers *.cmd
編寫了驅動程式,接下來就要寫使用驅動程式的代碼,我們稱為app吧。
< app / led_test.c >
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#define IOCTL_LED_ON 0
#define IOCTL_LED_OFF 1
void usage(char *exename)//使用說明
{
printf("Usage:\n");
printf(" %s <led_no> <on/off>\n",exename);
printf(" led_no=1,2\n");
}
int main(int argc, char **argv)
{
unsigned int led_no;
int fd = -1;
if(argc != 3)
{
goto err;
}
fd = open("/dev/leds",O_RDWR);//打開檔案
if(fd < 0)
{
printf("Can't open /dev/leds\n");
return -1;
}
led_no = strtoul(argv[1],0,0) - 1;//擷取LED号
if (led_no > 3)
goto err;
if(!strcmp(argv[2],"on"))
{
ioctl(fd,IOCTL_LED_ON,led_no); //點亮LED燈
}
else if(!strcmp(argv[2],"off"))
{
ioctl(fd,IOCTL_LED_OFF,led_no);//熄滅LED燈
}
else
{
goto err;
}
close(fd);
return 0;
err:
if(fd > 0)
close(fd);
usage(argv[0]);
return -1;
}
< app / Makefile >
#
# General Makefile
Exec := led_test
Obj := led_test.c
CC := arm-linux-gcc #此編譯器需根據自己的核心編譯器來更改
$(Exec) : $(Obj)
$(CC) -o [email protected] $(Obj) $(LDLIBS$(LDLIBS-$(@)))
clean:
rm -vf $(Exec) *.elf *.o
測試
将led1打開。