035_platform_led

一、驅動測試源碼

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

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章