一、驅動測試源碼
platform_led_device.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
MODULE_LICENSE("GPL");
// LED2
#define GPL2CON 0x11000100
#define GPL2DAT 0x11000104
// LED3
#define GPK1CON 0x11000060
#define GPK1DAT 0x11000064
struct resource res[] = {
[0] = {
.start = GPL2CON,
.end = GPL2CON+3,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = GPL2DAT,
.end = GPL2DAT+3,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = GPK1CON,
.end = GPK1CON+3,
.flags = IORESOURCE_MEM,
},
[3] = {
.start = GPK1DAT,
.end = GPK1DAT+3,
.flags = IORESOURCE_MEM,
},
};
static void platform_led_device_release(struct device *dev)
{
printk("%s,%d\n", __func__, __LINE__);
return ;
}
static struct platform_device pdevice = {
.name = "platform_led",
.num_resources = ARRAY_SIZE(res),
.resource = res,
.dev = {
.release = platform_led_device_release,
},
};
static int __init platform_led_device_init(void)
{
printk("%s,%d\n", __func__, __LINE__);
platform_device_register(&pdevice);
return 0;
}
static void __exit platform_led_device_exit(void)
{
printk("%s,%d\n", __func__, __LINE__);
platform_device_unregister(&pdevice);
return ;
}
module_init(platform_led_device_init);
module_exit(platform_led_device_exit);
platform_led_driver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
dev_t devno;
int minor = 0;
int count = 1;
struct cdev *pdev;
struct class *pclass;
struct device *devicep;
void __iomem * gpl2con;
void __iomem * gpl2dat;
void __iomem * gpk1con;
void __iomem * gpk1dat;
struct resource *res0;
struct resource *res1;
struct resource *res2;
struct resource *res3;
static int itop4412_open(struct inode *inodep, struct file *filep)
{
unsigned int dat = 0;
printk("%s,%d\n", __func__, __LINE__);
//點亮LED2
dat = readl(gpl2dat);
dat = dat|(0x1 << 0);
writel(dat, gpl2dat);
//點亮LED3
dat = readl(gpk1dat);
dat = dat|(0x1 << 1);
writel(dat, gpk1dat);
return 0;
}
static int itop4412_release(struct inode *inodep, struct file * filep)
{
unsigned int dat = 0;
printk("%s,%d\n", __func__, __LINE__);
//熄滅LED2
dat = readl(gpl2dat);
dat = dat&(~(0x1 << 0));
writel(dat, gpl2dat);
//熄滅LED3
dat = readl(gpk1dat);
dat = dat&(~(0x1 << 1));
writel(dat, gpk1dat);
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = itop4412_open,
.release = itop4412_release,
};
static int platform_led_driver_probe(struct platform_device * pdevice) // 探測函數,一旦設備與驅動匹配成功,就回調此函數
{
int ret = 0;
unsigned int dat = 0;
printk("*************probe ok!*************\n");
res0 = platform_get_resource(pdevice, IORESOURCE_MEM, 0);
if(res0 == NULL)
{
printk("Failed to platform_get_resource.\n");
return -1;
}
printk("res0:%#x , %#x\n", (unsigned int)res0->start, (unsigned int)res0->end);
res1 = platform_get_resource(pdevice, IORESOURCE_MEM, 1);
if(res1 == NULL)
{
printk("Failed to platform_get_resource.\n");
return -1;
}
printk("res1:%#x , %#x\n", (unsigned int)res1->start, (unsigned int)res1->end);
res2 = platform_get_resource(pdevice, IORESOURCE_MEM, 2);
if(res2 == NULL)
{
printk("Failed to platform_get_resource.\n");
return -1;
}
printk("res2:%#x , %#x\n", (unsigned int)res2->start, (unsigned int)res2->end);
res3 = platform_get_resource(pdevice, IORESOURCE_MEM, 3);
if(res3 == NULL)
{
printk("Failed to platform_get_resource.\n");
return -1;
}
printk("res3:%#x , %#x\n", (unsigned int)res3->start, (unsigned int)res3->end);
ret = alloc_chrdev_region(&devno, minor, count, "platform_led");
if(ret)
{
printk("Failed to alloc_chrdev_region.\n");
return ret;
}
printk("devno:%d , major:%d minor:%d\n", devno, MAJOR(devno), MINOR(devno));
pdev = cdev_alloc();
if(pdev == NULL)
{
printk("Failed to cdev_alloc.\n");
goto err;
}
cdev_init(pdev, &fops);
ret = cdev_add(pdev, devno, count);
if(ret)
{
printk("Failed to cdev_add.\n");
goto err1;
}
// 自動創建設備結點
pclass = class_create(THIS_MODULE, "myclass");
if(IS_ERR(pclass))
{
ret = PTR_ERR(pclass);
goto err2;
}
devicep = device_create(pclass, NULL, devno, NULL, "platform_led");
if(IS_ERR(devicep))
{
ret = PTR_ERR(devicep);
goto err3;
}
gpl2con = ioremap(res0->start, 4);
if(gpl2con == NULL)
{
printk("Failed to ioremap.\n");
goto err4;
}
gpl2dat = ioremap(res1->start, 4);
if(gpl2dat == NULL)
{
printk("Failed to ioremap.\n");
goto err5;
}
gpk1con = ioremap(res2->start, 4);
if(gpk1con == NULL)
{
printk("Failed to ioremap.\n");
goto err6;
}
gpk1dat = ioremap(res3->start, 4);
if(gpk1dat == NULL)
{
printk("Failed to ioremap.\n");
goto err7;
}
// 設置輸出模式
dat = readl(gpl2con);
dat = (dat & (~(0xf << 0)))|(0x1 << 0);
writel(dat, gpl2con);
dat = readl(gpk1con);
dat = (dat & (~(0xf << 4)))|(0x1 << 4);
writel(dat, gpk1con);
return 0;
err7:
iounmap(gpk1con);
err6:
iounmap(gpl2dat);
err5:
iounmap(gpl2con);
err4:
device_destroy(pclass, devno);
err3:
class_destroy(pclass);
err2:
cdev_del(pdev);
err1:
kfree(pdev);
err:
unregister_chrdev_region(devno,count);
return ret;
}
static int platform_led_driver_remove(struct platform_device * pdevice) // 移除函數
{
printk("%s,%d\n", __func__, __LINE__);
iounmap(gpl2con);
iounmap(gpl2dat);
iounmap(gpk1con);
iounmap(gpk1dat);
device_destroy(pclass, devno);
class_destroy(pclass);
cdev_del(pdev);
kfree(pdev);
unregister_chrdev_region(devno,count);
return 0;
}
static struct platform_device_id ids[] = {
{.name = "platform_led", },
{/*Nothing to be done.*/},
};
static struct platform_driver platform_led_driver = {
.probe = platform_led_driver_probe,
.remove = platform_led_driver_remove,
.driver = {
.name = "platform_led1",
},
.id_table = ids,
};
//module_platform_driver(platform_led_driver);
#if 1
static int __init platform_led_driver_init(void)
{
printk("%s,%d\n", __func__, __LINE__);
platform_driver_register(&platform_led_driver);
return 0;
}
static void __exit platform_led_driver_exit(void)
{
printk("%s,%d\n", __func__, __LINE__);
platform_driver_unregister(&platform_led_driver);
return ;
}
module_init(platform_led_driver_init);
module_exit(platform_led_driver_exit);
#endif
二、Makefile
$(warning KERNELRELEASE = $(KERNELRELEASE))
ifeq ($(KERNELRELEASE),)
#內核的源碼路徑, ?= 條件賦值, uname -r 得到內核版本號
#KERNELDIR ?= /lib/modules/$(shell uname -r)/build
KERNELDIR ?= /home/mint/itop/linux_3.0
# := 立即賦值, 得到當前的絕對路徑
PWD := $(shell pwd)
# -C 切換工作路徑, $(MAKE) = make
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*
.PHONY: modules clean
else
# 生成模塊
obj-m := platform_led_device.o platform_led_driver.o
endif
install:
cp *.ko ~/nfs/fs/
三、應用層測試源碼
test_module_platform_led.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{
int fd;
fd = open("/dev/platform_led", O_RDWR);
if(fd < 0)
{
perror("Failed to open.");
return -1;
}
else
{
printf("open success.\n");
}
getchar();
close(fd);
return 0;
}
四、Makefile
CC=/home/mint/itop/arm-2009q3/bin/arm-none-linux-gnueabi-gcc
OBJ=test_module_platform_led
OBJS=*.c
CFLAGS= -Wall -g -static
$(OBJ):$(OBJS)
$(CC) $(CFLAGS) $^ -o $@
$*.o:$%.c
$(CC) $(CFLAGS) -c $< -o $@
.PHONY:clean
clean:
$(RM) *.o $(OBJ)
install:
cp $(OBJ) ~/nfs/fs/
五、測試
1、加載驅動
insmod platform_led_device.ko
insmod platform_led_driver.ko
2、查看信息
cat /proc/devices | grep "platform_led"
ls /dev/platform_led -l
ls /sys/class/myclass/platform_led/
3、運行應用程序
./test_module_platform_led
此時會發現板子上的led燈被點亮,按下任意鍵,應用程序退出運行,LED2 LED3熄滅。
4、卸載驅動
rmmod platform_led_device
rmmod platform_led_driver