《[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

/*代码代换:platform_led_dev_, "platform_led"*/#include 
#include
#include
#include
#include
#include
#include
//文件系统相关的函数和头文件#include
#include
//cdev结构的头文件包含
static struct resource platform_led_dev_resource[] = { /* 参考s3c2440芯片手册 GPFCON 0x56000050//本驱动使用,注意unsigned long 为4字节(4*8 bit),相当与ff GPFDAT 0x56000054//本驱动使用 GPFUP 0x56000058//本驱动不使用,上拉电阻在驱动中不使用到, */ [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

   

/* *代码代换:platform_led_drv_, "platform_led" */#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, /* 这是一个宏,推向编译模块时自动创建的__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); /*/proc/devices*/ platform_led_drv_cls = class_create(THIS_MODULE, "platform_led");/* /sys/class/platform_led */ class_device_create(platform_led_drv_cls, NULL, MKDEV(major, 0), NULL, "platform_led"); /* /dev/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"); /* 卸载字符设备驱动程序 */ /* iounmap */ 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.koall:    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.symversobj-m   += platform_led_dev.oobj-m   += platform_led_drv.o

   应用测试程序

   

#include 
#include
#include
#include
//myledint 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-gccmyled.bin:$(objs)    $(myarmgcc) -o $@ $^    cp *.bin /opt/fsmini/%.o:%.c    $(myarmgcc) -c -o $@ $

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