社区
C语言
帖子详情
Device Driver怎样通知应用程序?用消息还是callback?实现的函数?
rayyang2000
2000-01-27 04:48:00
...全文
177
3
打赏
收藏
Device Driver怎样通知应用程序?用消息还是callback?实现的函数?
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
3 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
茂奇软件
2000-04-13
打赏
举报
回复
there is a demo of file system filter.
the url is :
http://www.sysinternals.com/filesrc.zip
Would you please reference the function:
LogRecord, which is a function pass message to
the GUI application.
yours jansen.
CoGi
2000-04-11
打赏
举报
回复
共享内存虽可解决问题,但需要应用程序不断查询内存,效率不高。
最好用DDK的自带例程。
xiaotiao
2000-01-29
打赏
举报
回复
VxD可以使用SendMessage函数,但DD则不行,你可以用共享内存空间
unix分析关于UNIX的一些浅析
内核版本:2.6.31.6 首先在S3C2440平台的初始化
函数
中,主要是将开发平台的设备注册进了系统,也就是将
device
注册到了platform虚拟的总线上,并进行了一些初始化的工作,这里我们只关注I2C的部分。 static void __init smdk2440_machine_init(void) { s3c24xx_fb_set_platdata(&smdk2440_fb_info); s3c_i2c0_set_platdata(NULL); platform_add_
device
s(smdk2440_
device
s, ARRAY_SIZE(smdk2440_
device
s)); smdk_machine_init(); } s3c_i2c0_set_platdata()
函数
将S3C2440上的I2C控制器进行了一些初始化,但是并没有写入硬件寄存器,仅仅是保存在了s3c2410_platform_i2c结构体中。 void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd) { struct s3c2410_platform_i2c *npd; if (!pd) pd = &default_i2c_data0; npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL); if (!npd) printk(KERN_ERR "%s: no memory for platform data\n", __func__); else if (!npd->cfg_gpio) npd->cfg_gpio = s3c_i2c0_cfg_gpio; /* s3c_i2c0_cfg_gpio为 配置I2C控制器GPIO
函数
指针 */ s3c_
device
_i2c0.dev.platform_data = npd; /*最后将struct
device
中的platform_data指针直指向了初始化后的 s3c2410_platform_i2c结构体 */ }
函数
s3c_i2c0_cfg_gpio()很简单,实际上就是配置GPIO为I2C的工作模式 void s3c_i2c0_cfg_gpio(struct platform_
device
*dev) { s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA); s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL); } s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
函数
实际上就是把初始化数据段中的default_i2c_data0结构体复制过来,然后对GPIO进行配置的
函数
指针进行了初始化。default_i2c_data0结构体如下: static struct s3c2410_platform_i2c default_i2c_data0 __initdata = { .flags = 0, .slave_addr = 0x10, .frequency = 100*1000, .sda_delay = 100, }; s3c2410_platform_i2c结构体原型如下,根据英文注释即可大致理解其意思 /** * struct s3c2410_platform_i2c - Platform data for s3c I2C. * @bus_num: The bus number to use (if possible). * @flags: Any flags for the I2C bus (E.g. S3C_IICFLK_FILTER). * @slave_addr: The I2C address for the slave
device
(if enabled). * @frequency: The desired frequency in Hz of the bus. This is * guaranteed to not be exceeded. If the caller does * not care, use zero and the
driver
will select a * useful default. * @sda_delay: The delay (in ns) applied to SDA edges. * @cfg_gpio: A
callback
to configure the pins for I2C operation. */ struct s3c2410_platform_i2c { int bus_num; unsigned int flags; unsigned int slave_addr; unsigned long frequency; unsigned int sda_delay; void (*cfg_gpio)(struct platform_
device
*dev); }; 在
函数
smdk2440_machine_init(void)中,调用了 platform_add_
device
s(smdk2440_
device
s, ARRAY_SIZE(smdk2440_
device
s)); 即将smdk2440_
device
s结构体数组中platform_
device
添加到了系统中,也就是添加到了platform总线上。smdk2440_
device
s的具体内容如下: static struct platform_
device
*smdk2440_
device
s[] __initdata = { &s3c_
device
_usb, &s3c_
device
_lcd, &s3c_
device
_wdt, &s3c_
device
_i2c0, &s3c_
device
_iis, &s3c_
device
_dm9000, &s3c_
device
_rtc, }; 其中s3c_
device
_i2c0保存了S3C2440中的I2C控制器的一些内部资源等信息,具体内容如下: struct platform_
device
s3c_
device
_i2c0 = { .name = "s3c2410-i2c", /*设备名,platform总线的match
函数
中会用设备名和驱动名的比较来绑定设备和驱动程序*/ #ifdef CONFIG_S3C_DEV_I2C1 .id = 0, #else .id = -1, #endif .num_resources = ARRAY_SIZE(s3c_i2c_resource), .resource = s3c_i2c_resource, }; 其中s3c_i2c_resource结构体保存了S3C2440中I2C控制器寄存器的物理地址和中断号等具体的硬件信息。 static struct resource s3c_i2c_resource[] = { [0] = { .start = S3C_PA_IIC, .end = S3C_PA_IIC + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_IIC, .end = IRQ_IIC, .flags = IORESOURCE_IRQ, }, }; 在后面注册具体设备驱动时也会添加到paltform总线上,platform总线会将具体的设备和驱动进行绑定,这样驱动就可以操作具体的设备了。platform实际上是一个虚拟的总线,本质上也是一个设备。 好了,上面是一些板级的硬件设备资源向系统的注册,没有设计到具体的硬件操作,在加载驱动程序时,驱动程序会根据已经注册到系统的具体设备的硬件资源进行初始化,也就是进行一些硬件操作,控制硬件设备的正常工作,下面来分析驱动程序的加载过程。 S3C2440平台上的I2C的驱动程序在linux/
driver
s/i2c/busses/i2c-s3c2410.c文件中, 在驱动的加载程序中,将platform_
driver
类型的s3c24xx_i2c_
driver
注册到了系统中。 static int __init i2c_adap_s3c_init(void) { return platform_
driver
_register(&s3c24xx_i2c_
driver
); } 分析platform_
driver
_register(&s3c24xx_i2c_
driver
);的源代码可知,实际上是将s3c24xx_i2c_
driver
注册到了platform总线上。 int platform_
driver
_register(struct platform_
driver
*drv) { drv->
driver
.bus = &platform_bus_type; /*将
device
_
driver
中的probe,remove,shutdown
函数
指针指向platform_
driver
中的
函数
,后面进行驱动和设备绑定后会调用probe
函数
*/ if (drv->probe) drv->
driver
.probe = platform_drv_probe; if (drv->remove) drv->
driver
.remove = platform_drv_remove; if (drv->shutdown) drv->
driver
.shutdown = platform_drv_shutdown; return
driver
_register(&drv->
driver
); } 下图即为Linux 2.6中引入的设备驱动模型的结构图(只是个总体框架,并不是指这的platform总线,设备和驱动)。 总线上包括设备和驱动的集合,总线上所有设备组成双向循环链表,包含在platform_
device
的设备集合中,总线上所有驱动组成双向循环链表,包含在platform_dirver的驱动集合中。 platform_
driver
_register(struct platform_
driver
*drv)
函数
实际上是对
driver
_register(struct
device
_
driver
*drv)
函数
的一个简单封装。
driver
_register()
函数
的调用关系如下
driver
_register() —>bus_add_
driver
(drv); —>
driver
_attach(drv); —> bus_for_each_dev(drv->bus, NULL, drv, __
driver
_attach); bus_for_each_dev(drv->bus, NULL, drv, __
driver
_attach)
函数
会遍历总线上所有的设备,并调用__
driver
_attach
函数
,判断驱动是否和设备匹配,若匹配则将struct
device
中的 struct
device
_
driver
*
driver
指向此驱动,也就是进行了驱动和设备的绑定,若不匹配,则继续遍历下一个设备。事实上,在向总线注册设备时,同样会进行类似的操作,遍历总线上所有驱动程序,找到则进行设备与驱动程序的绑定。 static int __
driver
_attach(struct
device
*dev, void *data) { struct
device
_
driver
*drv = data; /* * Lock
device
and try to bind to it. We drop the error * here and always return 0, because we need to keep trying * to bind to
device
s and some
driver
s will return an error * simply if it didn't support the
device
. * *
driver
_probe_
device
() will spit a warning if there * is an error. */ /*调用platform总线的match()
函数
,即platform_match
函数
,判断设备和驱动是否匹配,若匹配则返真,找到对应的设备,继续执行后面的程序,若没有找到,则返回假,
函数
执行结束 。这里我们的I2C驱动找到了可以驱动的设备,所以会继续执行*/ if (!
driver
_match_
device
(drv, dev)) return 0; if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); down(&dev->sem); /*设备是否已经找到驱动?显然,这里没有找到驱动,因为设备在向系统中platform总线注册时还没有驱动注册到platform总线上,所以dev->drive = NULL */ if (!dev->
driver
)
driver
_probe_
device
(drv, dev); up(&dev->sem); if (dev->parent) up(&dev->parent->sem); return 0; }
driver
_probe_
device
(drv, dev)
函数
进行驱动与设备的绑定。 /** *
driver
_probe_
device
- attempt to bind
device
&
driver
together * @drv:
driver
to bind a
device
to * @dev:
device
to try to bind to the
driver
* * This function returns -ENODEV if the
device
is not registered, * 1 if the
device
is bound sucessfully and 0 otherwise. * * This function must be called with @dev->sem held. When called for a * USB interface, @dev->parent->sem must be held as well. */ int
driver
_probe_
device
(struct
device
_
driver
*drv, struct
device
*dev) { int ret = 0; if (!
device
_is_registered(dev)) //判断设备是否已经注册 return -ENODEV; pr_debug("bus: '%s': %s: matched
device
%s with
driver
%s\n", drv->bus->name, __func__, dev_name(dev), drv->name); ret = really_probe(dev, drv); return ret; } really_probe
函数
中 进行
device
和
driver
的绑定,并调用用户在
device
_
driver
中注册的probe()例程。 static int really_probe(struct
device
*dev, struct
device
_
driver
*drv) { int ret = 0; atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing
driver
%s with
device
%s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); WARN_ON(!list_empty(&dev->devres_head)); /*将
device
中的
device
_
driver
指针指向了这个
driver
,即完成
device
和
driver
的绑定*/ dev->
driver
= drv; f (
driver
_sysfs_add(dev)) { printk(KERN_ERR "%s:
driver
_sysfs_add(%s) failed\n", __func__, dev_name(dev)); goto probe_failed; } /*若总线设置了probe
函数
,则调用总线的probe
函数
,然而platform总线并没有设置 */ if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret) goto probe_failed; } /* 否则,调用驱动注册在
device
_
driver
里的probe,这个
函数
中一般进行获得硬件资源,初始化硬件等操作,这里实际调用了s3c24xx_i2c_probe
函数
*/ else if (drv->probe) { ret = drv->probe(dev); if (ret) goto probe_failed; } /*将设备添加到
driver
所支持的设备列表中(因为一个驱动可以支持多个设备),并
通知
bus上的设备,表明BUS_NOTIFY_BOUND_
DRIVER
*/
driver
_bound(dev); ret = 1; pr_debug("bus: '%s': %s: bound
device
%s to
driver
%s\n", drv->bus->name, __func__, dev_name(dev), drv->name); goto done; probe_failed: devres_release_all(dev);
driver
_sysfs_remove(dev); dev->
driver
= NULL; if (ret != -ENODEV && ret != -ENXIO) { /*
driver
matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev_name(dev), ret); } /* * Ignore errors returned by ->probe so that the next
driver
can try * its luck. */ ret = 0; done: atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret; } 到这里,I2C设备软件层次上的驱动模型已经建立好了,接着会执行s3c24xx_i2c_probe
函数
,获取系统开始注册的一些硬件资源信息,进行硬件上的一些操作,以及真正的涉及到数据传输驱动程序的注册等操作。
Linux设备模型(5)_
device
和
device
driver
中,如果存在相同名称的
device
和
device
_
driver
(注:还存在其它方式,我们先不关注了),内核就会执行
device
_
driver
中的probe回调
函数
,而该
函数
就是所有
driver
的入口,可以执行诸如硬件设备初始化、字符设备注册、设备文件操作ops注册等动作(”remove”是它的反操作,发生在
device
或者
device
_
driver
任何一方从内核注销时,其原理类似,就不再单独说明了)。在sysfs中有这样一个目录:/sys/
device
s,系统中所有的设备,都归集在该目录下。
【Linux kernel】Linux设备模型(5)_
device
和
device
driver
device
和
device
driver
是Linux驱动开发的基本概念。Linux kernel的思路很简单:驱动开发,就是要开发指定的软件(
driver
)以驱动指定的设备,所以kernel就为设备和驱动它的
driver
定义了两个数据结构,分别是
device
和
device
_
driver
。因此本文将会围绕这两个数据结构,介绍Linux设备模型的核心逻辑,包括:设备及设备驱动在kernel中的抽象、使用和维护;设备及设备驱动的注册、加载、初始化原理;设备模型在实际驱动开发过程中的使用方法。注:在介绍
device
Linux设备模型剖析系列之三(
device
和
device
driver
)
【摘要】
device
和
device
driver
是Linux驱动开发的基本概念。Linux kernel的思路很简单:驱动开发,就是要为指定的设备(
device
)开发指定的软件(
device
_
driver
),所以kernel就为设备和驱动定义了两个数据结构,分别是
device
和
device
_
driver
。下文将会围绕这两个数据结构,介绍Linux设备模型的核心逻辑,包括:设备及设备驱动在kernel中的抽象、使用和维护;设备及设备驱动的注册、加载、初始化原理;设备模型在实际驱动开发过程中的使用方法。
platform_
driver
device
_
driver
dts自动加载platform_
device
及休眠唤醒的关系
platform总线是我们驱动编程中经常用的一种,之间的大体关系如下: 1.platform_bus_init 由start_kernel在加载各自init之前调用。主要就是注册一个bus,最终会添加到bus_kset链表中去,总线本身不会涉及到休眠唤醒,其休眠唤醒
函数
都是一个中间过程。为各自具体的设备驱动准备的。 2.platform_
device
_register 如上图描述所示,主要内部逻辑有下: 1):首先将dev添加到
device
s_kset链表中去 2):其次将dev添加到总线的
device
C语言
69,371
社区成员
243,082
社区内容
发帖
与我相关
我的任务
C语言
C语言相关问题讨论
复制链接
扫一扫
分享
社区描述
C语言相关问题讨论
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章