标签:
1 basic
在设备驱动程序中经常会见到和platform相关的字段,分布在驱动程序的多个角落,这也是2.6内核中比较重要的一种机制,把它的原理弄懂了,对以后分析驱动程序很有帮助,下面简单介绍一下: 在linux2.6设备模型中,关心总线,设备,驱动这三个实体,总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动。相反,在系统每注册一个驱动的时候,寻找与之匹配的设备,匹配是由总线来完成的。
一个现实的Linux 设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、I2C、SPI 等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC 系统中集成的独立的外设控制器、挂接在SoC 内存空间的外设等确不依附于此类总线。基于这一背景,Linux 发明了一种虚拟的总线,称为platform 总线
SOC系统中集成的独立外设单元(I2C,LCD,SPI,RTC等)都被当作平台设备来处理,而它们本身是字符型设备。
从Linux2.6内核起,引入一套新的驱动管理和注册机制:platform_device 和 platform_driver 。Linux 中大部分的设备驱动,都可以使用这套机制,设备用 platform_device 表示;驱动用platform_driver 进行注册
platform模型驱动编程,需要实现platform_device(设备)与platform_driver(驱动)在platform(虚拟总线)上的注册、匹配,相互绑定,然后再做为一个普通的字符设备进行相应的应用,总之如果编写的是基于字符设备的platform驱动,在遵循并实现platform总线上驱动与设备的特定接口的情况下,最核心的还是字符设备的核心结构:cdev、 file_operations(他包含的操作函数接口)、dev_t(设备号)、设备文件(/dev)等,因为用platform机制编写的字符驱动,它的本质是字符驱动。
驱动与设备是否成功注册,我们都可以在/sys/bus/platform/devices (drivers)/下查看
2 device.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
static void mini2440_led_platform_device_release(struct device * dev)
{
return ;
}
static struct resource mini2440_led_resource[] = {
[0] = {
.start = 0x56000010,
.end = 0x56000010 + 12,
.flags = IORESOURCE_MEM
},
};
static struct platform_device mini2440_platform_device_led = {
.name = "mini2440_led_platform_device_driver",
.id = -1,
.num_resources = ARRAY_SIZE(mini2440_led_resource),
.resource = mini2440_led_resource,
.dev = {
.release = mini2440_led_platform_device_release,
},
};
static int __init mini2440_led_platform_device_init(void)
{
printk("mini2440_led_platform_device add ok!\n");
return platform_device_register(&mini2440_platform_device_led);
}
static void __exit mini2440_led_platform_device_exit(void)
{
printk("mini2440_led_platform_device remove ok!\n");
platform_device_unregister(&mini2440_platform_device_led);
}
MODULE_AUTHOR("litingting");
MODULE_LICENSE("GPL");
module_init(mini2440_led_platform_device_init);
module_exit(mini2440_led_platform_device_exit);
makefile;
ifneq ($(KERNELRELEASE),)
obj-m :=devices.o
else
KERNELDIR :=/home/litingting/gec2440/linux-2.6.30.4
all:
make -C $(KERNELDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.o *.ko *.mod.o *.mod.c *.symvers modul* *.*~
endif
3 driver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#define GLOBAL_LED_MAJOR 250
static unsigned int global_led_major = GLOBAL_LED_MAJOR;
static struct cdev *led_cdev = NULL;
static struct class *led_class = NULL;
static volatile unsigned long *gpfcon = NULL;
static volatile unsigned long *gpfdat = NULL;
static volatile unsigned long *gpfup = NULL;
static int mini2440_led_open(struct inode * inode,struct file * file)
{
printk("mini2440_open[kernel_space]\n");
*gpfcon &=~((0x3<<0) | (0x3<<8) |(0x3<<10) |(0x3<<12)|(0x3<<14));
*gpfcon |= (0x1<<0) | (0x1<<8) |(0x1<<10) |(0x1<<12)|(0x1<<14);
return 0;
}
static ssize_t mini2440_led_read(struct file * file,const char __user * in,size_t size,loff_t * off)
{
printk("mini2440_read[kernel_space]\n");
return 0;
}
static ssize_t mini2440_led_write(struct file * file,const char __user * in,size_t size,loff_t * off)
{
int ret;
char ker_buf;
printk("mini2440_write[kernel_space]\n");
ret = copy_from_user(&ker_buf,in,size);
printk("ker_buf =%d\n",ker_buf);
if(ker_buf)
{
*gpfdat |= (1 << 5)|(1 << 6)|(1 << 8)|(1 << 7);
}
else
{
*gpfdat |=(0x1<<4)|(0x1<<5)|(0x1<<6)|(0x1<<7);
*gpfdat &= ~(0x1<<0);
}
return 0;
}
struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = mini2440_led_open,
.read = mini2440_led_read,
.write = mini2440_led_write,
};
static int __devinit mini2440_led_probe(struct platform_device *pdev)
{
int ret;
int err;
dev_t devno;
struct resource *pIORESOURCE_MEM;
devno = MKDEV(global_led_major,0);
printk(KERN_ALERT"mini2440_led_probe!\n");
if (devno)
{
ret = register_chrdev_region(devno,1,"mini2440_led_platfor_driver");
}
else
{
ret = alloc_chrdev_region(&devno,0,1,"mini2440_led_platfor_driver");
global_led_major = MAJOR(devno);
}
if (ret < 0)
{
return ret;
}
led_cdev = cdev_alloc();
cdev_init(led_cdev,&led_fops);
led_cdev->owner = THIS_MODULE;
err = cdev_add(led_cdev,devno,1);
led_class = class_create(THIS_MODULE,"mini2440_led_platfor_driver");
device_create(led_class,NULL,MKDEV(global_led_major,0),NULL,"platfor_driver_for_mini2440_led");
pIORESOURCE_MEM = platform_get_resource(pdev,IORESOURCE_MEM,0); //取得资源
gpfcon = ioremap(pIORESOURCE_MEM->start,pIORESOURCE_MEM->end - pIORESOURCE_MEM->start);//地址
gpfdat = gpfcon + 1;
gpfup = gpfcon + 2;
*gpfdat |=(0x1<<5)|(0x1<<7);
if (err)
{
printk(KERN_NOTICE"Error %d adding led_cdev",err);
return -1;
}
else
{
printk(KERN_NOTICE"platform_driver_for_mini2440_led init ok!\n");
return 0;
}
}
static int __devexit mini2440_led_remove(struct platform_device *pdev)
{
printk("mini2440_led_remove!\n");
cdev_del(led_cdev);
iounmap(gpfcon);
unregister_chrdev_region(MKDEV(global_led_major,0),1);
device_destroy(led_class, MKDEV(global_led_major,0));
class_destroy(led_class);
return 0;
}
static struct platform_driver mini2440_led_platform_driver = {
.probe = mini2440_led_probe,
.remove = __devexit_p(mini2440_led_remove),
.driver = {
.name = "mini2440_led_platform_device_driver",
.owner = THIS_MODULE,
}
};
static int __init mini2440_led_platform_driver_init(void)
{
printk("platform_driver_for_mini2440_led init\n");
return platform_driver_register(&mini2440_led_platform_driver);
}
static void __exit mini2440_led_platform_driver_exit(void)
{
printk("platform_driver_for_mini2440_led exit\n");
platform_driver_unregister(&mini2440_led_platform_driver);
}
MODULE_AUTHOR("litingting");
MODULE_LICENSE("GPL");
module_param(global_led_major,int,S_IRUGO);
module_init(mini2440_led_platform_driver_init);
module_exit(mini2440_led_platform_driver_exit);
makefile:
ifneq ($(KERNELRELEASE),)
obj-m :=driver.o
else
KERNELDIR :=/home/litingting/gec2440/linux-2.6.30.4
all:
make -C $(KERNELDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.o *.ko *.mod.o *.mod.c *.symvers modul* *.*~
endif
4 测试程序 test.c
#include<stdint.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<linux/input.h>
#include<unistd.h>
int main(int argc, char *argv[])
{
int fd, no;
fd = open("/dev/platfor_driver_for_mini2440_led", O_RDWR);
if(fd<0)
{
printf("can not open file.\n");
return -1;
}
write(fd, "1", 1); // write(fd,buff,sizeof(buff));//写数据
close(fd);
return 0;
}
makefile:
all:test
arm-linux-gcc -static -o test test.c
clean:
rm test
linux2.6.30.4 s3c2440 platform总线 led驱动
标签:
原文地址:http://blog.csdn.net/u012590688/article/details/46009115