前些天,把案件驱动改成了input子系统,今天学习下platform子系统。
在linux2.6以后的设备驱动模型中,需关心总线、设备和驱动这3个实体。
1.总线:总线将设备和驱动绑定。在系统通过某一总线每注册一个设备的时候,会寻找与之匹配的驱动。同样,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
总线中重要的结构体是:这个一般不需要我们来操作,系统会把需要的总线初始化好。
- struct bus_type {
- .
- .
- const char *name;
- .
- .
- }
2.设备:就是要操作的硬件的描述。
重要的结构体:
- struct device {
- .
- .
- struct bus_type *bus; /* type of bus device is on */
- struct device_driver *driver; /* which driver has allocated this
- device */
- void *platform_data; /* Platform specific data, device
- core doesn't touch it */
- .
- .
- }
对应的注册和卸载函数:
- device_register(struct device * dev)
- device_unregister(struct device * dev)
3.设备驱动:具体操作硬件的操作函数。
- struct device_driver {
- .
- .
- const char *name;
- struct bus_type *bus;
- int (*probe) (struct device *dev);
- int (*remove) (struct device *dev);
- .
- .
- }
对应的注册和卸载函数:
- driver_register(struct device_driver * drv)
- driver_unregister(struct device_driver * drv)
-------------------------------------------------------------------------------------------------
本次设计到的platform总线,类似于继承了上述的设备和设备驱动。
在
设备层对应的重要的数据结构为(
我直接实例化了这个数据结构的重要成员变量):
- struct platform_device pt_platform_dev =
- {
- .name = "pt2262",
- .resource = pt2262_resource,
- .num_resources = ARRAY_SIZE(pt2262_resource),
- .dev =
- {
- .platform_data = pt2262_devs,
- .release = pt2262_release,
- }
- };
对应的注册和注销函数
- platform_driver_unregister(&pt_platform_drv);
- platform_device_unregister(&pt_platform_dev);
在
设备驱动层对应的重要的数据结构为(
我也直接实例化了这个数据结构的重要成员变量):
- struct platform_driver pt_platform_drv =
- {
- .driver =
- {
- .name = "pt2262",
- .owner = THIS_MODULE,
- },
- .probe = pt_probe,
- .remove = pt_remove,
- };
对应的注册和注销函数
- ret = platform_driver_register(&pt_platform_drv);
- platform_driver_unregister(&pt_platform_drv);
以上关于
platform部分,我都是从我的代码中直接复制下来的。
完整的代码如下:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include "pt2262.h"
- const int gpio_num[4]={49,60,51,50};
- MODULE_LICENSE("GPL");
- struct resource pt2262_resource[]=
- {
- {
- .flags = IORESOURCE_IRQ,
- },
- {
- .flags = IORESOURCE_IRQ,
- },
- {
- .flags = IORESOURCE_IRQ,
- },
- {
- // .start = gpio_to_irq(gpio_num[3]),
- // .end = gpio_to_irq(gpio_num[3]),
- .flags = IORESOURCE_IRQ,
- }
- };
- struct pt2262_dev pt2262_devs[] =
- {
- {
- .desc = "A",
- .gpio = 49,
- .code = KEY_A,
- },
- {
- .desc = "B",
- .gpio = 60,
- .code = KEY_B,
- },
- {
- .desc = "C",
- .gpio = 51,
- .code = KEY_C,
- },
- {
- .desc = "D",
- .gpio = 50,
- .code = KEY_D,
- }
- };
- void pt2262_release(struct device *dev)
- {
- printk(KERN_INFO "pt2262 release func.n");
- }
- struct platform_device pt_platform_dev =
- {
- .name = "pt2262",
- .resource = pt2262_resource,
- .num_resources = ARRAY_SIZE(pt2262_resource),
- .dev =
- {
- .platform_data = pt2262_devs,
- .release = pt2262_release,
- }
- };
- irqreturn_t pt_irq_handler(int irq, void *pdev)
- {
- struct pt2262_dev * pt2262_devp = (struct pt2262_dev*)pdev;
- int i;
- for(i=0; i
- {
- if(0 == strcmp(pt2262_devp->desc ,pt2262_devs[i].desc))
- {
- printk(KERN_INFO "pt2262's code is %dtdesc is %sti is %d.n", pt2262_devp->code, pt2262_devp->desc, i);
- break;
- }
- continue;
- }
- return IRQ_HANDLED;
- }
- int pt_probe(struct platform_device *plat_pdev)
- {
- int i,j,ret;
- char buf[16];
- struct pt2262_dev* pt2262_pdev_tmp = plat_pdev->dev.platform_data;
- for(i=0; inum_resources; i++)
- {
- //j = plat_pdev->dev.platform_data
- j = pt2262_pdev_tmp[i].gpio;
- sprintf(buf, "pt_gpio_%d", j);
- ret = gpio_request(j, buf);
- if(ret < 0)
- goto fail;
- gpio_direction_input(j);
- ((plat_pdev->resource)+i)->start = gpio_to_irq(j);
- ((plat_pdev->resource)+i)->end = gpio_to_irq(j);
- ret = request_irq(((plat_pdev->resource)+i)->start,pt_irq_handler,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,"pt_irq_handler", pt2262_pdev_tmp+i);
- if(ret < 0)
- goto fail2;
- }
- printk(KERN_INFO "num_resources is %d.n", plat_pdev->num_resources);
- return ret;
- fail:
- printk(KERN_ERR "failed to request %sn",buf);
- return ret;
- fail2:
- printk(KERN_ERR "failed to request irq %sn",buf);
- return ret;
- }
- int pt_remove(struct platform_device *plat_pdev)
- {
- int i;
- struct pt2262_dev* pt2262_pdev_tmp = plat_pdev->dev.platform_data;
- printk("pt_remove goodbye.n");
- for(i=0; inum_resources; i++)
- {
- free_irq(plat_pdev->resource[i].start, pt2262_pdev_tmp+i);
- gpio_free((pt2262_pdev_tmp+i)->gpio);
- }
- return 0;
- }
- struct platform_driver pt_platform_drv =
- {
- .driver =
- {
- .name = "pt2262",
- .owner = THIS_MODULE,
- },
- .probe = pt_probe,
- .remove = pt_remove,
- };
- int __init pt_init(void)
- {
- int ret;
- ret = platform_device_register(&pt_platform_dev);
- ret = platform_driver_register(&pt_platform_drv);
- return ret;
- }
- module_init(pt_init);
- void __exit pt_exit(void)
- {
- platform_driver_unregister(&pt_platform_drv);
- platform_device_unregister(&pt_platform_dev);
- }
- module_exit(pt_exit);
还有一个头文件pt2262.h:
- #ifndef __PT2262_H__
- #define __PT2262_H__
- struct pt2262_dev
- {
- char desc[8];
- int gpio;
- int code;
- };
- #endif
安装之后的效果如下图:
在
/sys/bus/platform/drivers目录下多出来pt2262这一项。