<!-- [if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:PunctuationKerning/> <w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing> <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery> <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>EN-US</w:LidThemeOther> <w:LidThemeAsian>ZH-CN</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:SpaceForUL/> <w:BalanceSingleByteDoubleByteWidth/> <w:DoNotLeaveBackslashAlone/> <w:ULTrailSpace/> <w:DoNotExpandShiftReturn/> <w:AdjustLineHeightInTable/> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:DontVertAlignCellWithSp/> <w:DontBreakConstrainedForcedTables/> <w:DontVertAlignInTxbx/> <w:Word11KerningPairs/> <w:CachedColBalance/> <w:UseFELayout/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="--"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument> </xml><![endif]--><!-- [if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="0" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="0" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="0" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Priority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="0" Name="header"/> <w:LsdException Locked="false" Priority="0" Name="footer"/> <w:LsdException Locked="false" Priority="0" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="0" Name="page number"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="0" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/> <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/> <w:LsdException Locked="false" Priority="0" Name="Document Map"/> <w:LsdException Locked="false" Priority="0" Name="No List"/> <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/> <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 1"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/> <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/> <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/> <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 6"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/> <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/> <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/> <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/> <w:LsdException Locked="false" Priority="32" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/> <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/> <w:LsdException Locked="false" Priority="37" Name="Bibliography"/> <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> </w:LatentStyles> </xml><![endif]--><!-- [if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman","serif";} </style> <![endif]-->
Linux2.6 内核引入了一套新的驱动管理机制: Platform_device 和 Platform_driver 。设备用 Platform_device 表示,驱动用 Platform_driver 表示,另外设备描述了使用的资源,驱动则负责电源管理和使用资源。由于驱动和资源之间的独立,使得程序的可移植性和可扩展性大大增强。
plarform 设备用 platform_device 来表示,如 程序清单 1 .1 所示。
程序清单 1 . 1 platform_device
/* include/linux/platform_device.h */
struct platform_device {
const char * name; ①
int id; ②
struct device dev; ③
u32 num_resources; ④
struct resource * resource; ⑤
};
各个成员的解释如下:
① name 指向设备的名字字符串,这个名字用来和同名的 platform_driver 进行匹配。
② id 是设备编号(如果有多个同类设备的话),如果只有一个则需设为 -1 。
③ 设备模型用到的成员。
④ 使用到的资源的数量。
⑤ 资源数组头地址。
最后一个成员 resource 指向此设备用到的资源的数组, struct resource 的定义如 程序清单 1 .2 所示。
程序清单 1 . 2 struct resource
/* include/linux/ioport.h */
struct resource {
resource_size_t start; ①
resource_size_t end; ②
const char *name; ③
unsigned long flags; ④
struct resource *parent, *sibling, *child; ⑤
};
#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
#define IORESOURCE_IO 0x00000100 /* Resource type */
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_DMA 0x00000800
#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
#define IORESOURCE_READONLY 0x00002000
#define IORESOURCE_CACHEABLE 0x00004000
#define IORESOURCE_RANGELENGTH 0x00008000
#define IORESOURCE_SHADOWABLE 0x00010000
#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */
#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */
#define IORESOURCE_DISABLED 0x10000000
#define IORESOURCE_UNSET 0x20000000
#define IORESOURCE_AUTO 0x40000000
#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */
各个成员的解释如下:
① start 记录资源范围的起始值,比如一段内存空间的首地址。
② end 记录资源范围的结束位置。
③ name 资源的名字。
④ flags 用来记录资源类型以及是否可写、忙碌等信息,各位的定义如 程序清单 1 .2 所示。
⑤ 分别记录资源树的父节点、兄弟节点和子节点。
注册 platform_device 有两个接口 platform_add_devices 和 platform_device_register ,它们的代码如所示。
程序清单 1 . 3 platform_device 注册接口
/* drivers/base/platform.c */
int platform_add_devices(struct platform_device **devs, int num)
{
int i, ret = 0;
for (i = 0; i < num; i++) {
ret = platform_device_register(devs[i]);
if (ret) {
while (--i >= 0)
platform_device_unregister(devs[i]);
break;
}
}
return ret;
}
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
platform_add_devices 注册多个设备,循环调用了 platform_device_register 。 platform_device_register 只有两步,第一步初始化 platform_device 的 dev 成员,接下来调用 platform_device_add 函数,它的实现如 程序清单 1 .4 所示。
程序清单 1 . 4 platform_device_add
/* drivers/base/platform.c */
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent) ①
pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1) ②
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
for (i = 0; i < pdev->num_resources; i++) { ③
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = pdev->dev.bus_id;
p = r->parent;
if (!p) { ④
if (r->flags & IORESOURCE_MEM)
p = &iomem_resource;
else if (r->flags & IORESOURCE_IO)
p = &ioport_resource;
}
if (p && insert_resource(p, r)) { ⑤
printk(KERN_ERR
"%s: failed to claim resource %d\n",
pdev->dev.bus_id, i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
pdev->dev.bus_id, pdev->dev.parent->bus_id);
ret = device_add(&pdev->dev); ⑥
if (ret == 0)
return ret;
failed:
while (--i >= 0)
if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(&pdev->resource[i]);
return ret;
}
代码的解释如下:
① 处初始化设备的父设备和总线类型。
② 处填写该设备在设备模型中的名字:如果编号不为 -1 则名字为设备名加编号,否则只包含设备名。
③ 处循环处理设备的每一个资源。
④ 如果父资源指针为空,则为 IO 端口和 IO 内存设置默认的父资源节点。这里看到,中断资源和 DMA 资源并不设置父节点,因为内核没有为这两类资源建立资源树,它们的使用情况使用另外的方式记录。
⑤ 如果有父资源节点,则将资源注册进内核资源树(仅仅针对 IO 端口和 IO 内存)。
⑥ 将本设备注册进内核的驱动模型中。
platform 驱动用 platform_driver 来表示,它的定义如 程序清单 1 .5 所示。
程序清单 1 . 5 platform_driver
/* include/linux/platform_device.h */
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct pm_ext_ops *pm;
struct device_driver driver;
};
platform_driver 的各个成员主要用来进行电源管理。其成员 driver.name 用来匹配支持的设备,它支持的 platfirm_device 必须使用这个名字。当有 platform_device 和该驱动名字匹配时, probe 成员会被调用,传入匹配的设备指针。解除绑定时 remove 被调用。
platform_driver 的注册较为简单,如 程序清单 1 .6 所示。
程序清单 1 . 6 platform_driver_register
/* drivers/base/platform.c */
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
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;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
if (drv->pm)
drv->driver.pm = &drv->pm->base;
return driver_register(&drv->driver);
}
注册过程就是将 platform_driver 的成员函数赋给 driver 成员的成员函数指针,然后注册进设备模型。
platform 提供了设备的资源视图,可以比较集中的管理资源的使用。在 Linux 内核硬件相关的文件当中, Linux 使用 platform 机制定义了很多驱动使用的资源,可以在一个文件中看到多个驱动的资源分配情况,有利于资源的规划和分配。对于 smartarm3250 来说,这个文件是 arch/arm/mach-lpc32xx/arch-lpc32xx.c ,这个文件定义了看门狗、 rtc 、 i2c 、 spi 等各种总线 / 设备用到的资源,定义了这些模块的驱动 platform_device ,对于 i2c 的定义如 程序清单 1 .7 所示。
程序清单 1 . 7 i2c 的 platform_device
/* arch/arm/mach-lpc32xx/arch-lpc32xx.c */
#if defined (CONFIG_MACH_LPC32XX_I2C0_ENABLE)
static struct i2c_pnx_algo_data lpc32xx_algo_data0 = {
.base = I2C1_BASE,
.irq = IRQ_I2C_1,
};
static struct i2c_adapter lpc32xx_adapter0 = {
.name = I2C_CHIP_NAME "0",
.algo_data = &lpc32xx_algo_data0,
};
static struct i2c_pnx_data i2c0_data = {
.suspend = i2c_lpc32xx_suspend,
.resume = i2c_lpc32xx_resume,
.calculate_input_freq = calculate_input_freq,
.set_clock_run = set_clock_run,
.set_clock_stop = set_clock_stop,
.adapter = &lpc32xx_adapter0,
};
static struct platform_device i2c0_device = {
.name = "pnx-i2c",
.id = 0,
.dev = {
.platform_data = &i2c0_data,
},
};
#endif
这里资源的传递没有通过 struct resource 来传递,而是使用了 struct platform_device 的 dev. platform_data 传递过去的,这种用法不多见,其它模块的资源通过 struct platform_device 的 resource 成员来传递。可见这里已经定义好了设备的一切资源。
lpc32xx 的 platform_device 是通过 phy3250_board_init()->lpc32xx_init()->platform_add_devices() 来注册的。而 phy3250_board_init 是在硬件架构的初始化时被调用的。
上面的内容是 platform_device 的定义,完整的驱动模型包含驱动和设备两部分。对应的 platform_driver 定义在 driver/i2c/busses/i2c-pnx.c ,如所示。
程序清单 1 . 8 lpc32xx 的 platform_driver
/* driver/i2c/busses/i2c-pnx.c */
static struct platform_driver i2c_pnx_driver = {
.driver = {
.name = "pnx-i2c",
.owner = THIS_MODULE,
},
.probe = i2c_pnx_probe,
.remove = __devexit_p(i2c_pnx_remove),
.suspend = i2c_pnx_controller_suspend,
.resume = i2c_pnx_controller_resume,
};
static int __init i2c_adap_pnx_init(void)
{
return platform_driver_register(&i2c_pnx_driver);
}
static void __exit i2c_adap_pnx_exit(void)
{
platform_driver_unregister(&i2c_pnx_driver);
}
subsys_initcall(i2c_adap_pnx_init);
module_exit(i2c_adap_pnx_exit);
可以看到这个驱动的名字和 platform_device 的名字是一致的,因为名字是它们相互绑定的依据。在 Linux 设备模型中,当发现新注册的驱动和已经注册的设备符合绑定条件之后,驱动的 probe 函数将被调用, probe 的主要职能是申请设备定义的资源(比如中断和 IO 内存空间)并初始化设备的硬件,注册设备的其它子系统资源(比如 i2c 的适配器结构体)。
由于 i2c_adap_pnx_init 是在子系统初始化的时候被调用的,因此比 platform_device 的初始化要晚。
最典型的 platform 应用就是 1.3.1 节的所示的形式,在一个文件中定义设备的资源和数据结构,在另一个文件的驱动中进行申请和初始化。设备和驱动的绑定由 Linux 设备模型负责。驱动和设备的分离使得每个驱动可以对应多个同类的设备,资源独立之后可以在不修改设备资源配置的情况下升级驱动模块。
典型的应用是在内核编译之前就定义好了各种平台设备和它们的资源,如果想在驱动模块中定义 platform_device 并申请资源也是可以的。可以使用以下接口动态申请一个 platform_device:
struct platform_device *platform_device_alloc( const char *name, int id);
进行适当的初始化之后就可以使用 platform_device_register() 进行注册了。当然也可以直接动态构并注册:
struct platform_device *platform_device_register_simple(
const char *name, int id,
struct resource *res, unsigned int nres);
在模块当中定义 platform_devic 和 platform_driver 并不是内核文档推荐的用法,因为 platform_devic 可能被其他模块或者子系统所依赖或引用。当本模块卸载时,其它模块可能还在使用。因此在驱动模块中定义设备是不合适的,因为驱动的职责不包含设备的定义,这违背了 Linux 设备模型的思想。但是如果保证不会和其它模块产生依赖,使用平台设备可以添加设备电源管理的接口,这对需要低功耗的嵌入式设备具有重大意义。因此如果对功耗没有要求,尽量不要用 platform ,如果有需求则需要小心使用,如果这个设备比较固定,最好将设备的定义添加到内核中。
我们看到 Linux 的平台设备使用了资源的概念,如 程序清单 1 .2 所示。如 程序清单 1 .4 所示, platform_device 注册过程中会将没有设置父节点的 IO 端口和 IO 内存资源的父节点指针指向默认的两个节点: ioport_resource 和 iomem_resource ,内核会以倒置的兄弟节点树的形式来记录资源的使用情况。它们的定义如 程序清单 1 .9 所示。
程序清单 1 . 9 ioport_resource 和 iomem_resource
/* kernel/resource.c */
struct resource ioport_resource = {
.name = "PCI IO",
.start = 0,
.end = IO_SPACE_LIMIT,
.flags = IORESOURCE_IO,
};
struct resource iomem_resource = {
.name = "PCI mem",
.start = 0,
.end = -1,
.flags = IORESOURCE_MEM,
};
对于中断和 DMA 类的资源,内核中并没有相应的资源树。
在使用 IO 端口和 IO 内存资源之前,首先要进行申请,也就是从资源树中申请。 IO 端口空间的申请接口如下所示:
/* include/linux/ioport.h */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name));
#define release_region(start,n) __release_region(&ioport_resource, (start), (n));
static inline int __deprecated check_region(resource_size_t s, resource_size_t n);
这三个接口分别用来申请一段 IO 端口资源、释放一段资源和检查一段资源是否被占用。但是最后一个接口是不安全的,不推荐使用,因为检查和申请资源并不是原子的。
IO 内存资源的管理接口如下:
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name));
#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n));
#define check_mem_region(start,n) __check_region(&iomem_resource, (start), (n));
这三个接口的功能 分别用来申请一段 IO 内存资源、释放一段资源和检查一段资源是否被占用。同样 check_mem_region 也是不安全的。
资源树仅仅用来使用的记录,实际使用 IO 端口和 IO 内存之前还要进行物理地址到虚拟地址之间的映射。