Led设备驱动基于字符设备框架,并且用到硬件知识比如EXYNOS中的控制led寄存器地址。还有几个重要函数比如ioremap、ioctl函数会在其他博客中贴出。这里直接贴出代码。
Led.c文件内容
/*6- 包含内核头文件*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
/*7-根据芯片手册 确定物理地址*/
#define FS4412_GPX2CON 0x11000C40
#define FS4412_GPX2DAT 0x11000C44
void *gpx2con;
void *gpx2dat;
#define FS4412_GPX1CON 0x11000C20
#define FS4412_GPX1DAT 0x11000C24
void *gpx1con;
void *gpx1dat;
#define FS4412_GPF3CON 0x114001E0
#define FS4412_GPF3DAT 0x114001E4
void *gpf3con;
void *gpf3dat;
dev_t devno;
int major = 0;/*在/proc/devices查看系统中已经分配的设备号*/
int minor = 0;
/*8-内核中不能直接访问物理地址,需要先映射成虚拟地址*/
int fs4412_led_ioremap(void)
{
gpx2con = ioremap(FS4412_GPX2CON, 4);
gpx2dat = ioremap(FS4412_GPX2DAT, 4);
gpx1con = ioremap(FS4412_GPX1CON, 4);
gpx1dat = ioremap(FS4412_GPX1DAT, 4);
gpf3con = ioremap(FS4412_GPF3CON, 4);
gpf3dat = ioremap(FS4412_GPF3DAT, 4);
return 0;
}
int fs4412_led_iounmap(void)
{
iounmap(gpx2con);
iounmap(gpx2dat);
iounmap(gpx1con);
iounmap(gpx1dat);
iounmap(gpf3con);
iounmap(gpf3dat);
return 0;
}
/*9-初始化goio为输出模式*/
int fs4412_led_init(void)
{
/*配置gpx2_7 bit28-31为输出模式*/
writel((readl(gpx2con)& (~(0xf << 28))) | 0x1 << 28, gpx2con);
/*配置gpx1_0 bit0-3为输出模式*/
writel((readl(gpx1con)& (~(0xf << 0))) | 0x1 << 0, gpx1con);
/*配置gpx3_4/5 bit16-23为输出模式*/
writel((readl(gpf3con)& (~(0xff << 16))) | 0x11 << 16, gpf3con);
return0;
}
int fs4412_led_on(int ledno)
{
switch(ledno)
{
case1:
writel(readl(gpx2dat)|(0x1 << 7), gpx2dat);
break;
case2:
writel(readl(gpx1dat)|(0x1 << 0), gpx1dat);
break;
case3:
writel(readl(gpf3dat)|(0x1 << 4), gpf3dat);
break;
case4:
writel(readl(gpf3dat)|(0x1 << 5), gpf3dat);
break;
}
return0;
}
int fs4412_led_off(int ledno)
{
switch(ledno)
{
case1:
writel(readl(gpx2dat)& (~(0x1 << 7)), gpx2dat);
break;
case2:
writel(readl(gpx1dat)& (~(0x1 << 0)), gpx1dat);
break;
case3:
writel(readl(gpf3dat)& (~(0x1 << 4)), gpf3dat);
break;
case4:
writel(readl(gpf3dat)& (~(0x1 << 5)), gpf3dat);
break;
}
return0;
}
int fs4412_led_open (struct inode *inode,struct file *file)
{
printk("fs4412led open\n");
fs4412_led_on(1);
fs4412_led_on(2);
fs4412_led_on(3);
fs4412_led_on(4);
return0;
}
int fs4412_led_close (struct inode *inode,struct file *file)
{
printk("fs4412led close\n");
fs4412_led_off(1);
fs4412_led_off(2);
fs4412_led_off(3);
fs4412_led_off(4);
return0;
}
#define LED_OFF 0
#define LED_ON 1
long fs4412_led_ioctl (struct file * file,unsigned int cmd, unsigned long ledno)
{
printk("cmd= %d, ledno = %ld\n",cmd,ledno);
switch(cmd)
{
caseLED_OFF:
fs4412_led_off(ledno);
break;
caseLED_ON:
fs4412_led_on(ledno);
break;
default:
break;
}
return0;
}
/*2-1 初始化驱动的操作函数接口*/
struct file_operations fops = {
.open= fs4412_led_open,
.release= fs4412_led_close,
.unlocked_ioctl= fs4412_led_ioctl,
};/*赋值语句加;*/
struct class *pcls;
struct device *pledv;
static int __init led_module_init(void)
{
printk("fs4412module init\n");
/*2-字符设备框架初始化
0自动分配设备号
*/
major= register_chrdev(0, "fs4412-led", &fops);
devno= MKDEV(major,minor);
/*
3-自动生成设备节点 /dev/auto-led 给应用程序访问硬件的节点
*/
pcls= class_create(THIS_MODULE,"led-pcs");
pledv= device_create(pcls, NULL, devno, NULL, "auto-led");
fs4412_led_ioremap();
fs4412_led_init();
return0;
}
static void __exit led_module_exit(void)
{
printk("fs4412led module exit\n");
/*进行释放资源的操作*/
unregister_chrdev(major,"fs4412-led");
device_destroy(pcls,devno);
class_destroy(pcls);
fs4412_led_iounmap();
}
MODULE_LICENSE("GPL"); /*5-声明GPL,如果不加内核接口调用不了*/
module_init(led_module_init);/*1-模块入口函数,insmod led.ko会执行fs4412_led_init*/
module_exit(led_module_exit);/*4-模块出口函数 sudo rmmod led 会执行到 fs4412_led_exit*/
app.c文件内容
/*************************************************************************
@Author: wanghao
@Created Time : Tue 26 Jun 2018 06:26:39 PM PDT
@File Name: test.c
@Description:
************************************************************************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{
intfd = 0;
printf("leddevice test!\n");
fd= open("/dev/auto-led",O_RDWR);
if(fd< 0)
{
perror("openfail!");
returnfd;
}
sleep(1);
close(fd);
return0;
}
Makefile内容:
ifeq ($(KERNELRELEASE),)
#KDIR:= /lib/modules/$(shell uname-r)/build
KDIR:= /home/wanghao/linux-3.14-fs4412
all:
make-C $(KDIR) M=$(shell pwd)
arm-none-linux-gnueabi-gccapp.c -o app
sudocp app /source/rootfs
sudocp led.ko /source/rootfs
clean:
rm*.o *.ko *.mod.c modules.order ledapp
else
obj-m:=led.o
endif