天天看点

Linux驱动实现灯循环闪烁,[arm驱动]platform第一个程序led灯循环

《[arm驱动]Platform设备驱动》涉及内核驱动函数二个,内核结构体一个,分析了内核驱动函数二个;可参考的相关应用程序模板或内核驱动模板零个,可参考的相关应用程序或内核驱动一个

一、关键是device程序中resource结构体

结构体一)resource结构体struct resource {

resource_size_t start; //定义资源的起始地址

resource_size_t end; //定义资源的结束地址

const char *name; //定义资源的名称

unsigned long flags; //定义资源的类型,例如MEM, IO ,IRQ, DMA类型

struct resource *parent, *sibling, *child; //资源链表指针

};

函数一)driver程序中获取资源struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)

参数:

dev: 资源所属的设备

type: 获取的资源类型  IORESOURCE_IO IORESOURCE_MEM IORESOURCE_IRQ IORESOURCE_DMA

num: 获取的资源数

例:platform_get_resource(pdev, IORESOURCE_IRQ, 0)获取第一个中断号

内核源码一)platform_get_resource内核源码

platform_get_resource(struct platform_device *dev, unsigned int type,

unsigned int num)

{

int i;

for (i = 0; i < dev->num_resources; i++) {

struct resource *r = &dev->resource[i];

//从下面两个if中看出num = 0并不等同于要取resource[0],而是获取第一个flag为type的resource

if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|

IORESOURCE_IRQ|IORESOURCE_DMA))

== type)

if (num-- == 0)

return r;

}

return NULL;

}

函数二)driver中获取第num+1个中断资源platform_get_irq(struct platform_device * dev, unsigned int num)

内核源码二)platform_get_irq内核源码int platform_get_irq(struct platform_device *dev, unsigned int num)

{

struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);

//调用了platform_get_resource

return r ? r->start : -ENXIO;

}

实例一)实现一个s3c2440的platform led流水灯

platform_led_dev.c

#include

#include

#include

#include

#include

#include

#include //文件系统相关的函数和头文件

#include

#include //cdev结构的头文件包含

static struct resource platform_led_dev_resource[] = {

[0] = {

.start = 0x56000050,

.end = 0x56000050 + 8 - 1,

.flags = IORESOURCE_MEM,

},

};

static void platform_led_dev_release(struct device * dev){

printk("device say the device is release\n");

return;

}

static struct platform_device platform_led_dev_device = { //添加设备结构体

.name = "platform_led",

.id = -1,

.num_resources = ARRAY_SIZE(platform_led_dev_resource),//一定要加,因为platform_get_resource中要用到

.resource = platform_led_dev_resource,

.dev = {

.release = platform_led_dev_release,//解决"Device 'platform_dev' does not have a release() function“问题

}

};

static int __init platform_led_dev_init(void){

platform_device_register(&platform_led_dev_device); //注册设备到内核

return 0;

}

static void platform_led_dev_exit(void){

platform_device_unregister(&platform_led_dev_device); //卸载设备

printk(KERN_ALERT "good bye\n");

}

module_init(platform_led_dev_init);

module_exit(platform_led_dev_exit);

MODULE_LICENSE("GPL");

platform_led_drv.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

static struct class *platform_led_drv_cls;

static volatile unsigned long *gpiof_con;//注意unsigned long 为4字节(4*8 bit),相当与ff

static volatile unsigned long *gpiof_dat;

static int major;

static int platform_led_drv_open(struct inode *inode, struct file *file)

{

printk("driver\tplatform_led open\n");

*gpiof_con &= ~((0x3 << (4*2)) | (0x3 << (5*2)) | (0x3 << (6*2)));

*gpiof_con |= ((0x1 << (4*2)) | (0x1 << (5*2)) | (0x1 << (6*2) ));

return 0;

}

static ssize_t platform_led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

{

int val;

int on;

copy_from_user(&val, buf, count);

on = val % 10;

val = val / 10 + 4;

if(on == 0){

*gpiof_dat &= ~(1 << val);

}else{

*gpiof_dat |= (1 << val);

}

return 0;

}

static struct file_operations platform_led_drv_fops = {

.owner = THIS_MODULE,

.open = platform_led_drv_open,

.write = platform_led_drv_write,

};

static int platform_led_drv_probe(struct platform_device *dev)//

{

struct resource *res;

//获得GPFCON,GPFDAT

res = platform_get_resource(dev, IORESOURCE_MEM, 0);

printk("driver say the driver found the device\n");

gpiof_con = (volatile unsigned long *)ioremap(res->start, res->end - res->start + 1);//将0x56000050-0x56000057进行IO映射,gpiof_con等于ioremap的首地址,占4个字节

gpiof_dat = gpiof_con + 1;//相当与0x56000050 + 4

major = register_chrdev(0, "platform_led", &platform_led_drv_fops);

platform_led_drv_cls = class_create(THIS_MODULE, "platform_led");

class_device_create(platform_led_drv_cls, NULL, MKDEV(major, 0), NULL, "platform_led");

printk("driver say the driver probe ok\n");

return 0;

}

static int platform_led_drv_remove(struct platform_device *dev)

{

printk("driver say the device is polled out\n");

class_device_destroy(platform_led_drv_cls, MKDEV(major, 0));

class_destroy(platform_led_drv_cls);

unregister_chrdev(major, "platform_led");

iounmap(gpiof_con);

return 0;

}

//platform 总线相关文件挂载/sys/bus/platform/路径下

static struct platform_driver platform_led_drv_driver = {//driver是驱动的意思,相关文件在/sys/bus/platform/drivers

.probe = platform_led_drv_probe,//注册时要执行的函数

.remove = platform_led_drv_remove,//注销时会执行的函数

.driver = {

.owner = THIS_MODULE,

.name = "platform_led",//会在"/sys/bus/platform/drivers"下创建platform_dev文件夹

},

};

static int __init platform_led_drv_driver_init(void)

{

return platform_driver_register(&platform_led_drv_driver);

}

static void platform_led_drv_driver_exit(void)

{

platform_driver_unregister(&platform_led_drv_driver);

}

module_init(platform_led_drv_driver_init);

module_exit(platform_led_drv_driver_exit);

MODULE_LICENSE("GPL");

上面两个c文件对于的Makefile

KERN_DIR = /workspacearm/linux-2.6.2.6

#platform_led_dev.ko

#platform_led_drv.ko

all:

make -C $(KERN_DIR) M=`pwd` modules

cp platform_led_dev.ko /opt/fsmini/

cp platform_led_drv.ko /opt/fsmini/

clean:

make -C $(KERN_DIR) M=`pwd` modules clean

rm -rf modules.order

rm -rf Module.symvers

obj-m += platform_led_dev.o

obj-m += platform_led_drv.o

应用测试程序

#include

#include

#include

#include

//myled

int main(int argc, char **argv)

{

int fd;

int val = 1;

fd = open("/dev/platform_led", O_RDWR);

if (fd < 0)

{

printf("can't open!\n");

}

while(1){

if(val > 10){

val = val - 10;

write(fd, &val, 4);

val = val + 10;

}else{

val = 21;

write(fd, &val, 4);

val = 1;

}

val -=1;

write(fd, &val, 4);

sleep(1);

val += 11;

if(val > 22 )val = 1;

}

//write(fd, &val, 4);

close(fd);

return 0;

}

应用程序对应的Makefile

objs := $(patsubst %c, %o, $(shell ls *.c))

myarmgcc := /workspacearm/armlinuxgcc2626/bin/arm-linux-gcc

myled.bin:$(objs)

$(myarmgcc) -o [email protected] $^

cp *.bin /opt/fsmini/

%.o:%.c

$(myarmgcc) -c -o [email protected] $<

clean:

rm -f *.bin *.o

总结:可以看出,将device可drive分开写,驱动(driver)可以达到平台(device)无关性,这也是总线的初衷