【1:引言: linux字符设备驱动的基本编程流程】
1.实现模块加载函数 a.申请主设备号 register_chrdev(major,name,file_operations); b.创建字符设备cdev,注册字符设备 cdev_alloc cdev_init cdev_add c.创建设备文件 class_create device_create d.注册中断 ret =request_irq(中断号,...,...,...,...); e.映射 虚拟地址=ioremap(物理地址,大小) f.初始化(初始化等待队列头,初始化tasklet,初始化工作队列) ...2.实现模块卸载函数3.构建file_operations结构体变量4.实现操作硬件的方法 xxx_open xxx_write xxx_read为了提高驱动的可移植性,减少驱动开发周期,最好将跟硬件/平台相关的东西分离出来,以便增强驱动的可移植性
中断号,物理地址----->归为设备资源
最好将设备资源与设备驱动分离开来
平台设备驱动机制 platform_device platform_driver 设备资源(设备) < -- -- -- > 设备驱动
【2:设备总线驱动模型:内核用来管理设备与驱动的一种方式】
设备总线驱动模型:以对象的思想来实现的
每一个设备对应唯一的一个驱动 每个驱动则可能服务多个设备 系统中有很多总线:1)实际的物理总线(如:i2c总线,usb总线,SDIO总线,SPI总线...) 2)虚拟总线(只有一条:平台总线)【对象思想】
/*1.在系统用来表示一个设备*/ struct device { struct device_driver *driver; //设备驱动 struct bus_type *bus; //所属总线 struct device *parent; //父设备 dev_t devt; //设备号 void *platform_data; //私有数据 .... } /*2.在系统中用来表示设备驱动*/ struct device_driver { const char *name; //驱动名字 struct bus_type *bus; //所属总线 struct module *owner; //拥有者 int ( *probe) ( struct device *dev); //probe函数 } /*3.在系统中用来表示总线*/ struct bus_type { const char *name; //总线名字 /*mach函数,匹配函数,每条总线里面都会有自己的 *mach,但不同总线的mach的匹配方法可能会不同 */ int ( *match)( struct device *dev, struct device_driver *drv); /*当设备与驱动匹配成功的时候,便会调用probe函数 *不过,一般总线中不会实现probe函数,在匹配成功 *的时候,会直接调用设备驱动中的probe函数 */ int ( *probe)( struct device *dev); int ( *remove)( struct device *dev); }
【设备总线驱动模型里面的操作函数】
/*1.总线注册*/ int bus_register( struct bus_type *bus) void bus_unregister( struct bus_type *bus) /*2.设备注册*/ int device_register( struct device *dev) void device_unregister( struct device *dev) /*3.设备驱动注册*/ int driver_register( struct device_driver *drv) void driver_unregister( struct device_driver *drv)
【3:平台设备驱动机制】
借助于设备总线驱动模型,虚拟出一条总线,用来实现设备资源与设备驱动的匹配===============================================
平台设备驱动机制采用了:分离的思想,对象的思想分离的思想:设备资源与设备驱动分离开
【对象思想】
/*1.平台设备结构体*/ struct platform_device { const char * name; //名字 int id; struct device dev; //设备结构体 u32 num_resources; //资源数量 struct resource * resource; //设备资源 const struct platform_device_id *id_entry; /* arch specific additions */ struct pdev_archdata archdata; }; /*2.平台驱动结构体*/ struct platform_driver { int ( *probe)( struct platform_device *); //probe函数 int ( *remove)( struct platform_device *); void ( *shutdown)( struct platform_device *); int ( *suspend)( struct platform_device *, pm_message_t state); int ( *resume)( struct platform_device *); struct device_driver driver; //设备驱动 const struct platform_device_id *id_table; }; /*3.虚拟总线:平台总线结构体*/ struct bus_type platform_bus_type = { .name = "platform", //总线名字 .dev_attrs = platform_dev_attrs, .match = platform_match, //匹配函数 .uevent = platform_uevent, .pm = &platform_dev_pm_ops, }; /*4.资源结构体*/ struct resource { resource_size_t start; //起始 resource_size_t end; //结束 const char *name; //名字 unsigned long flags; //标号 struct resource *parent, *sibling, *child; }; //平台设备驱动机制中如何来实现设备与驱动的匹配 static int platform_match( struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* match against the id table first :可能支持多个设备*/ if (pdrv - >id_table) return platform_match_id(pdrv - >id_table, pdev) != NULL; /*平台设备里面的名字,与设备驱动里面的名字匹配*/ return (strcmp(pdev - >name, drv - >name) == 0); }
【总线注册】
/*内核启动时的第一个C语言入口函数*/ start_kernel //init/main.c rest_init /*创建一个内核线程*/ kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); kernel_init do_basic_setup //init/main.c driver_init platform_bus_init /*1.注册平台总线*/ bus_register( &platform_bus_type);
【平台设备驱动模型的关键接口函数】
/*1.注册平台设备*/ int platform_device_register( struct platform_device *pdev) void platform_device_unregister( struct platform_device *pdev) /*2.注册平台驱动*/ int platform_driver_register( struct platform_driver *drv) void platform_driver_unregister( struct platform_driver *drv) /*3.获取平台资源*/ platform_get_resource( struct platform_device * dev, unsigned int type, unsigned int num)
【linux设备驱动之设备总线驱动模型】
【设备总线驱动模型】
@成鹏致远(wwwlllll@126.com)