Mercurial > ecos
comparison packages/services/power/common/current/doc/power-controller.html @ 208:e0c0827131d1 ecos
Merge from eCos master repository on 2002-05-20-20:11:54-BST
| author | jlarmour |
|---|---|
| date | Mon, 20 May 2002 22:19:26 +0000 |
| parents | |
| children | 74dbf4c3f2e1 |
comparison
equal
deleted
inserted
replaced
| 207:74c807ddde34 | 208:e0c0827131d1 |
|---|---|
| 1 <!-- Copyright (C) 2001 Red Hat, Inc. --> | |
| 2 <!-- This material may be distributed only subject to the terms --> | |
| 3 <!-- and conditions set forth in the Open Publication License, v1.0 --> | |
| 4 <!-- or later (the latest version is presently available at --> | |
| 5 <!-- http://www.opencontent.org/openpub/). --> | |
| 6 <!-- Distribution of substantively modified versions of this --> | |
| 7 <!-- document is prohibited without the explicit permission of the --> | |
| 8 <!-- copyright holder. --> | |
| 9 <!-- Distribution of the work or derivative of the work in any --> | |
| 10 <!-- standard (paper) book form is prohibited unless prior --> | |
| 11 <!-- permission is obtained from the copyright holder. --> | |
| 12 <HTML | |
| 13 ><HEAD | |
| 14 ><TITLE | |
| 15 >Implementing a Power Controller</TITLE | |
| 16 ><meta name="MSSmartTagsPreventParsing" content="TRUE"> | |
| 17 <META | |
| 18 NAME="GENERATOR" | |
| 19 CONTENT="Modular DocBook HTML Stylesheet Version 1.64 | |
| 20 "><LINK | |
| 21 REL="HOME" | |
| 22 TITLE="eCos Power Management Support" | |
| 23 HREF="services-power.html"><LINK | |
| 24 REL="PREVIOUS" | |
| 25 TITLE="Attached and Detached Controllers" | |
| 26 HREF="power-attached.html"></HEAD | |
| 27 ><BODY | |
| 28 CLASS="REFENTRY" | |
| 29 BGCOLOR="#FFFFFF" | |
| 30 TEXT="#000000" | |
| 31 LINK="#0000FF" | |
| 32 VLINK="#840084" | |
| 33 ALINK="#0000FF" | |
| 34 ><DIV | |
| 35 CLASS="NAVHEADER" | |
| 36 ><TABLE | |
| 37 WIDTH="100%" | |
| 38 BORDER="0" | |
| 39 CELLPADDING="0" | |
| 40 CELLSPACING="0" | |
| 41 ><TR | |
| 42 ><TH | |
| 43 COLSPAN="3" | |
| 44 ALIGN="center" | |
| 45 >eCos Power Management Support</TH | |
| 46 ></TR | |
| 47 ><TR | |
| 48 ><TD | |
| 49 WIDTH="10%" | |
| 50 ALIGN="left" | |
| 51 VALIGN="bottom" | |
| 52 ><A | |
| 53 HREF="power-attached.html" | |
| 54 >Prev</A | |
| 55 ></TD | |
| 56 ><TD | |
| 57 WIDTH="80%" | |
| 58 ALIGN="center" | |
| 59 VALIGN="bottom" | |
| 60 ></TD | |
| 61 ><TD | |
| 62 WIDTH="10%" | |
| 63 ALIGN="right" | |
| 64 VALIGN="bottom" | |
| 65 > </TD | |
| 66 ></TR | |
| 67 ></TABLE | |
| 68 ><HR | |
| 69 ALIGN="LEFT" | |
| 70 WIDTH="100%"></DIV | |
| 71 ><H1 | |
| 72 ><A | |
| 73 NAME="POWER-CONTROLLER" | |
| 74 >Implementing a Power Controller</A | |
| 75 ></H1 | |
| 76 ><DIV | |
| 77 CLASS="REFNAMEDIV" | |
| 78 ><A | |
| 79 NAME="AEN355" | |
| 80 ></A | |
| 81 ><H2 | |
| 82 >Name</H2 | |
| 83 >Implementing a Power Controller -- adding power management support to device drivers and | |
| 84 other packages</DIV | |
| 85 ><DIV | |
| 86 CLASS="REFSECT1" | |
| 87 ><A | |
| 88 NAME="AEN358" | |
| 89 ></A | |
| 90 ><H2 | |
| 91 >Implementing a Power Controller</H2 | |
| 92 ><P | |
| 93 >A system will have some number of power controllers. Usually there | |
| 94 will be one power controller for the cpu, | |
| 95 <TT | |
| 96 CLASS="VARNAME" | |
| 97 >power_controller_cpu</TT | |
| 98 >, typically provided by one of | |
| 99 the HAL packages and responsible for managing the processor itself and | |
| 100 associated critical components such as memory. Some or all of the | |
| 101 device drivers will provide power controllers, allowing the power | |
| 102 consumption of the associated devices to be controlled. There may be | |
| 103 some arbitrary number of other controllers present in the system. The | |
| 104 power management package does not impose any restrictions on the | |
| 105 number or nature of the power controllers in the system, other than | |
| 106 insisting that at most one <TT | |
| 107 CLASS="VARNAME" | |
| 108 >power_controller_cpu</TT | |
| 109 > be | |
| 110 provided.</P | |
| 111 ><P | |
| 112 >Each power controller involves a single data structure of type | |
| 113 <SPAN | |
| 114 CLASS="STRUCTNAME" | |
| 115 >PowerController</SPAN | |
| 116 >, defined in the header file | |
| 117 <TT | |
| 118 CLASS="FILENAME" | |
| 119 >cyg/power/power.h</TT | |
| 120 >. These data | |
| 121 structures should all be placed in the table | |
| 122 <TT | |
| 123 CLASS="LITERAL" | |
| 124 >__POWER__</TT | |
| 125 >, so that the power management package and | |
| 126 other code can easily locate all the controllers in the system. This | |
| 127 table is constructed at link-time, avoiding code-size or run-time | |
| 128 overheads. To facilitate this the package provides two macros which | |
| 129 should be used to define a power controller, | |
| 130 <TT | |
| 131 CLASS="LITERAL" | |
| 132 >POWER_CONTROLLER()</TT | |
| 133 > and | |
| 134 <TT | |
| 135 CLASS="LITERAL" | |
| 136 >POWER_CONTROLLER_CPU()</TT | |
| 137 >.</P | |
| 138 ><P | |
| 139 >The macro <TT | |
| 140 CLASS="LITERAL" | |
| 141 >POWER_CONTROLLER</TT | |
| 142 > takes four arguments:</P | |
| 143 ><P | |
| 144 ></P | |
| 145 ><OL | |
| 146 TYPE="1" | |
| 147 ><LI | |
| 148 ><P | |
| 149 >A variable name. This can be used to access the power controller | |
| 150 directly, as well as via the table.</P | |
| 151 ></LI | |
| 152 ><LI | |
| 153 ><P | |
| 154 >A priority. The table of power controllers is sorted, such that power | |
| 155 controllers with a numerically lower priority come earlier in the | |
| 156 table. The special controller <TT | |
| 157 CLASS="VARNAME" | |
| 158 >power_controller_cpu</TT | |
| 159 > | |
| 160 always comes at the end of the table. When moving from a high-power | |
| 161 mode to a lower-powered mode, the power management package iterates | |
| 162 through the table from front to back. When moving to a higher-powered | |
| 163 mode the reverse direction is used. The intention is that the power | |
| 164 controller for a software-only package such as a TCP/IP stack should | |
| 165 appear near the start of the table, whereas the controllers for the | |
| 166 ethernet and similar devices would be near the end of the table. Hence | |
| 167 when the policy module initiates a mode change to a lower-powered mode | |
| 168 the TCP/IP stack gets a chance to cancel this mode change, before the | |
| 169 devices it depends on are powered down. Similarly when moving to a | |
| 170 higher-powered mode the devices will be re-activated before any | |
| 171 software that depends on those devices.</P | |
| 172 ><P | |
| 173 >The header file <TT | |
| 174 CLASS="FILENAME" | |
| 175 >cyg/power/power.h</TT | |
| 176 > defines three | |
| 177 priorities <TT | |
| 178 CLASS="LITERAL" | |
| 179 >PowerPri_Early</TT | |
| 180 >, | |
| 181 <TT | |
| 182 CLASS="LITERAL" | |
| 183 >PowerPri_Typical</TT | |
| 184 > and | |
| 185 <TT | |
| 186 CLASS="LITERAL" | |
| 187 >PowerPri_Late</TT | |
| 188 >. For most controllers one of these | |
| 189 priorities, possibly with a small number added or subtracted, will | |
| 190 give sufficient control. If an application developer is uncertain | |
| 191 about the relative priorities of the various controllers, a simple | |
| 192 <A | |
| 193 HREF="power-info.html#POWER-INFO-IDS" | |
| 194 >test program</A | |
| 195 > that iterates over | |
| 196 the table will quickly eliminate any confusion.</P | |
| 197 ></LI | |
| 198 ><LI | |
| 199 ><P | |
| 200 >A constant string identifier. If the system has been configured | |
| 201 without support for such identifiers | |
| 202 (<TT | |
| 203 CLASS="VARNAME" | |
| 204 >CYGIMP_POWER_PROVIDE_STRINGS</TT | |
| 205 >) then this identifer | |
| 206 will be discarded at compile-time. Otherwise it will be made available | |
| 207 to higher-level code using the function | |
| 208 <TT | |
| 209 CLASS="FUNCTION" | |
| 210 >power_get_controller_id</TT | |
| 211 >. </P | |
| 212 ></LI | |
| 213 ><LI | |
| 214 ><P | |
| 215 >A function pointer. This will be invoked to perform actual mode | |
| 216 changes, as described below.</P | |
| 217 ></LI | |
| 218 ></OL | |
| 219 ><P | |
| 220 >A typical example of the use of the | |
| 221 <TT | |
| 222 CLASS="LITERAL" | |
| 223 >POWER_CONTROLLER</TT | |
| 224 > macro would be as follows:</P | |
| 225 ><TABLE | |
| 226 BORDER="0" | |
| 227 BGCOLOR="#E0E0E0" | |
| 228 WIDTH="100%" | |
| 229 ><TR | |
| 230 ><TD | |
| 231 ><PRE | |
| 232 CLASS="PROGRAMLISTING" | |
| 233 >#include <pkgconf/system.h> | |
| 234 | |
| 235 #ifdef CYGPKG_POWER | |
| 236 # include <cyg/power/power.h> | |
| 237 | |
| 238 static void | |
| 239 xyzzy_device_power_mode_change( | |
| 240 PowerController* controller, | |
| 241 PowerMode desired_mode, | |
| 242 PowerModeChange change) | |
| 243 { | |
| 244 // Do the work | |
| 245 } | |
| 246 | |
| 247 static POWER_CONTROLLER(xyzzy_power_controller, \ | |
| 248 PowerPri_Late, \ | |
| 249 "xyzzy device", \ | |
| 250 &xyzzy_device_power_mode_change); | |
| 251 #endif</PRE | |
| 252 ></TD | |
| 253 ></TR | |
| 254 ></TABLE | |
| 255 ><P | |
| 256 >This creates a variable <TT | |
| 257 CLASS="VARNAME" | |
| 258 >xyzzy_power_controller</TT | |
| 259 >, | |
| 260 which is a power controller data structure that will end up near the | |
| 261 end of the table of power controllers. Higher-level code can | |
| 262 iterate through this table and report the string <TT | |
| 263 CLASS="LITERAL" | |
| 264 >"xyzzy | |
| 265 device"</TT | |
| 266 > to the user. Whenever there is a mode change | |
| 267 operation that affects this controller, the function | |
| 268 <TT | |
| 269 CLASS="FUNCTION" | |
| 270 >xyzzy_device_power_mode_change</TT | |
| 271 > will be invoked. | |
| 272 The variable is declared static so this controller cannot be | |
| 273 manipulated by name in any other code. Alternatively, if the variable | |
| 274 had not been declared static other code could manipulate this | |
| 275 controller by name as well as through the table, especially if the | |
| 276 package for the xyzzy device driver explicitly declared this | |
| 277 variable in an exported header file. Obviously exporting the variable | |
| 278 involves a slight risk of a name clash at link time.</P | |
| 279 ><P | |
| 280 >The above code explicitly checks for the presence of the power | |
| 281 management package before including that package's header file or | |
| 282 providing any related functionality. Since power management | |
| 283 functionality is optional, such checks are recommended.</P | |
| 284 ><P | |
| 285 >The macro <TT | |
| 286 CLASS="LITERAL" | |
| 287 >POWER_CONTROLLER_CPU</TT | |
| 288 > only takes two | |
| 289 arguments, a string identifier and a mode change function pointer. | |
| 290 This macro always instantiates a variable | |
| 291 <TT | |
| 292 CLASS="VARNAME" | |
| 293 >power_controller_cpu</TT | |
| 294 > so there is no need to provide | |
| 295 a variable name. The resulting power controller structure always | |
| 296 appears at the end of the table, so there is no need to specify a | |
| 297 priority. Typical usage of the <TT | |
| 298 CLASS="LITERAL" | |
| 299 >POWER_CONTROLLER_CPU</TT | |
| 300 > | |
| 301 macro would be:</P | |
| 302 ><TABLE | |
| 303 BORDER="0" | |
| 304 BGCOLOR="#E0E0E0" | |
| 305 WIDTH="100%" | |
| 306 ><TR | |
| 307 ><TD | |
| 308 ><PRE | |
| 309 CLASS="PROGRAMLISTING" | |
| 310 >static void | |
| 311 wumpus_processor_power_mode_change( | |
| 312 PowerController* controller, | |
| 313 PowerMode desired_mode, | |
| 314 PowerModeChange change) | |
| 315 { | |
| 316 // Do the work | |
| 317 } | |
| 318 | |
| 319 POWER_CONTROLLER_CPU("wumpus processor", \ | |
| 320 &wumpus_processor_power_mode_change);</PRE | |
| 321 ></TD | |
| 322 ></TR | |
| 323 ></TABLE | |
| 324 ><P | |
| 325 >This defines a power controller structure | |
| 326 <TT | |
| 327 CLASS="VARNAME" | |
| 328 >power_controller_cpu</TT | |
| 329 >. It should not be declared | |
| 330 static since higher-level code may well want to manipulate the cpu's | |
| 331 power mode directly, and the variable is declared by the power | |
| 332 management package's header file.</P | |
| 333 ><P | |
| 334 >Some care has to be taken to ensure that the power controllers | |
| 335 actually end up in the final executable. If a power controller | |
| 336 variable ends up in an ordinary library and is never referenced | |
| 337 directly then typically the linker will believe that the variable is | |
| 338 not needed and it will not end up in the executable. For eCos packages | |
| 339 this can be achieved in the CDL, by specifying that the containing | |
| 340 source file should end up in <TT | |
| 341 CLASS="FILENAME" | |
| 342 >libextras.a</TT | |
| 343 > rather | |
| 344 than the default <TT | |
| 345 CLASS="FILENAME" | |
| 346 >libtarget.a</TT | |
| 347 >:</P | |
| 348 ><TABLE | |
| 349 BORDER="0" | |
| 350 BGCOLOR="#E0E0E0" | |
| 351 WIDTH="100%" | |
| 352 ><TR | |
| 353 ><TD | |
| 354 ><PRE | |
| 355 CLASS="PROGRAMLISTING" | |
| 356 >cdl_package CYGPKG_HAL_WUMPUS_ARCH { | |
| 357 … | |
| 358 compile -library=libextras.a data.c | |
| 359 }</PRE | |
| 360 ></TD | |
| 361 ></TR | |
| 362 ></TABLE | |
| 363 ><P | |
| 364 >If the file <TT | |
| 365 CLASS="FILENAME" | |
| 366 >data.c</TT | |
| 367 > instantiates a power | |
| 368 controller this is now guaranteed to end up in the final executable, | |
| 369 as intended. Typically HAL and device driver packages will already | |
| 370 have some data that must not be eliminated by the linker, so they will | |
| 371 already contain a file that gets built into | |
| 372 <TT | |
| 373 CLASS="FILENAME" | |
| 374 >libextras.a</TT | |
| 375 >. For power controllers defined inside | |
| 376 application code it is important that the power controllers end up in | |
| 377 <TT | |
| 378 CLASS="FILENAME" | |
| 379 >.o</TT | |
| 380 > object files rather than in | |
| 381 <TT | |
| 382 CLASS="FILENAME" | |
| 383 >.a</TT | |
| 384 > library archive files.</P | |
| 385 ><P | |
| 386 >All the real work of a power controller is done by the mode change | |
| 387 function. If the power management package has been configured to use a | |
| 388 separate thread then this mode change function will be invoked by that | |
| 389 thread (except for the special case of <A | |
| 390 HREF="power-change.html#POWER-CHANGE-CONTROLLER-NOW" | |
| 391 ><TT | |
| 392 CLASS="FUNCTION" | |
| 393 >power_set_controller_mode_now</TT | |
| 394 ></A | |
| 395 >). | |
| 396 If no separate thread is used then the mode change function will be | |
| 397 invoked directly by <TT | |
| 398 CLASS="FUNCTION" | |
| 399 >power_set_mode</TT | |
| 400 > or | |
| 401 <TT | |
| 402 CLASS="FUNCTION" | |
| 403 >power_set_controller_mode</TT | |
| 404 >.</P | |
| 405 ><P | |
| 406 >The mode change function will be invoked with three arguments. The | |
| 407 first argument identifies the power controller. Usually this argument | |
| 408 is not actually required since a given mode change function will only | |
| 409 ever be invoked for a single power controller. For example, | |
| 410 <TT | |
| 411 CLASS="FUNCTION" | |
| 412 >xyzzy_device_power_mode_change</TT | |
| 413 > will only ever be | |
| 414 used in conjunction with <TT | |
| 415 CLASS="VARNAME" | |
| 416 >xyzzy_power_controller</TT | |
| 417 >. | |
| 418 However there may be some packages which contain multiple controllers, | |
| 419 all of which can share a single mode change function, and in that case | |
| 420 it is essential to identify the specific controller. The second | |
| 421 argument specifies the mode the controller should switch to, if | |
| 422 possible: it will be one of <TT | |
| 423 CLASS="LITERAL" | |
| 424 >PowerMode_Active</TT | |
| 425 >, | |
| 426 <TT | |
| 427 CLASS="LITERAL" | |
| 428 >PowerMode_Idle</TT | |
| 429 >, <TT | |
| 430 CLASS="LITERAL" | |
| 431 >PowerMode_Sleep</TT | |
| 432 > | |
| 433 or <TT | |
| 434 CLASS="LITERAL" | |
| 435 >PowerMode_Off</TT | |
| 436 >. The final argument will be one of | |
| 437 <TT | |
| 438 CLASS="LITERAL" | |
| 439 >PowerModeChange_Controller</TT | |
| 440 >, | |
| 441 PowerModeChange_ControllerNow, or | |
| 442 <TT | |
| 443 CLASS="LITERAL" | |
| 444 >PowerModeChange_Global</TT | |
| 445 >, and identifies the call | |
| 446 that caused this invocation. For example, if the mode change function | |
| 447 was invoked because of a call to <TT | |
| 448 CLASS="FUNCTION" | |
| 449 >power_set_mode</TT | |
| 450 > | |
| 451 then this argument will be <TT | |
| 452 CLASS="LITERAL" | |
| 453 >PowerModeChange_Global</TT | |
| 454 >. | |
| 455 It is up to each controller to decide how to interpret this final | |
| 456 argument. A typical controller might reject a global request to switch | |
| 457 to <SPAN | |
| 458 CLASS="TYPE" | |
| 459 >off</SPAN | |
| 460 > mode if the associated device is still busy, but | |
| 461 if the request was aimed specifically at this controller then it could | |
| 462 instead abort any current I/O operations and switch off the device.</P | |
| 463 ><P | |
| 464 >The <SPAN | |
| 465 CLASS="STRUCTNAME" | |
| 466 >PowerController</SPAN | |
| 467 > data structure contains | |
| 468 one field, <TT | |
| 469 CLASS="STRUCTFIELD" | |
| 470 ><I | |
| 471 >mode</I | |
| 472 ></TT | |
| 473 >, that needs to be updated | |
| 474 by the power mode change function. At all times it should indicate the | |
| 475 current mode for this controller. When a mode change is requested the | |
| 476 desired mode is passed as the second argument. The exact operation of | |
| 477 the power mode change function depends very much on what is being | |
| 478 controlled and the current circumstances, but some guidelines are | |
| 479 possible:</P | |
| 480 ><P | |
| 481 ></P | |
| 482 ><OL | |
| 483 TYPE="1" | |
| 484 ><LI | |
| 485 ><P | |
| 486 >If the request can be satisfied without obvious detriment, do so and | |
| 487 update the <TT | |
| 488 CLASS="STRUCTFIELD" | |
| 489 ><I | |
| 490 >mode</I | |
| 491 ></TT | |
| 492 > field. Reducing the power | |
| 493 consumption of a device that is not currently being used is generally | |
| 494 harmless.</P | |
| 495 ></LI | |
| 496 ><LI | |
| 497 ><P | |
| 498 >If a request is a no-op, for example if the system is switching | |
| 499 from <SPAN | |
| 500 CLASS="TYPE" | |
| 501 >idle</SPAN | |
| 502 > to <SPAN | |
| 503 CLASS="TYPE" | |
| 504 >sleep</SPAN | |
| 505 > mode and the controller | |
| 506 does not distinguish between these modes, simply act as if the request | |
| 507 was satisfied.</P | |
| 508 ></LI | |
| 509 ><LI | |
| 510 ><P | |
| 511 >If a request is felt to be unsafe, for example shutting down a | |
| 512 device that is still in use, then the controller may decide | |
| 513 to reject this request. This is especially true if the request was a | |
| 514 global mode change as opposed to one intended specifically for this | |
| 515 controller: in the latter case the policy module should be given due | |
| 516 deference. There are a number of ways in which a request can be | |
| 517 rejected:</P | |
| 518 ><P | |
| 519 ></P | |
| 520 ><OL | |
| 521 TYPE="a" | |
| 522 ><LI | |
| 523 ><P | |
| 524 >If the request cannot be satisfied immediately but may be feasible in | |
| 525 a short while, leave the <TT | |
| 526 CLASS="STRUCTFIELD" | |
| 527 ><I | |
| 528 >mode</I | |
| 529 ></TT | |
| 530 > field | |
| 531 unchanged. Higher-level code in the policy module can interpret this | |
| 532 as a hint to retry the operation a little bit later. This approach is | |
| 533 also useful if the mode change can be started but will take some time | |
| 534 to complete, for example shutting down a socket connection, and | |
| 535 additional processing will be needed later on.</P | |
| 536 ></LI | |
| 537 ><LI | |
| 538 ><P | |
| 539 >If the request is felt to be inappropriate, for example switching off | |
| 540 a device that is still in use, the mode change function can | |
| 541 call <TT | |
| 542 CLASS="FUNCTION" | |
| 543 >power_set_controller_mode</TT | |
| 544 > to reset the | |
| 545 desired mode for this controller back to the current mode. | |
| 546 Higher-level code can then interpret this as a hint that there is more | |
| 547 activity in the system than had been apparent.</P | |
| 548 ></LI | |
| 549 ><LI | |
| 550 ><P | |
| 551 >For a global mode change, if the new mode is felt to be inappropriate | |
| 552 then the power controller can call <TT | |
| 553 CLASS="FUNCTION" | |
| 554 >power_set_mode</TT | |
| 555 > | |
| 556 to indicate this. An example of this would be the policy module | |
| 557 deciding to switch off the whole unit while there is still I/O | |
| 558 activity.</P | |
| 559 ></LI | |
| 560 ></OL | |
| 561 ></LI | |
| 562 ></OL | |
| 563 ><P | |
| 564 >Mode change functions should not directly manipulate any other fields | |
| 565 in the <SPAN | |
| 566 CLASS="STRUCTNAME" | |
| 567 >PowerController</SPAN | |
| 568 > data structure. If it | |
| 569 is necessary to keep track of additional data then static variables | |
| 570 can be used.</P | |
| 571 ><P | |
| 572 >It should be noted that the above are only guidelines. Their | |
| 573 application in any given situation may be unclear. In addition the | |
| 574 detailed requirements of specific systems will vary, so even if the | |
| 575 power controller for a given device driver follows the above | |
| 576 guidelines exactly it may turn out that slightly different behaviour | |
| 577 would be more appropriate for the actual system that is being | |
| 578 developed. Fortunately the open source nature of | |
| 579 <SPAN | |
| 580 CLASS="PRODUCTNAME" | |
| 581 >eCos</SPAN | |
| 582 > allows system developers to fine-tune | |
| 583 power controllers to meet their exact requirements.</P | |
| 584 ></DIV | |
| 585 ><DIV | |
| 586 CLASS="NAVFOOTER" | |
| 587 ><HR | |
| 588 ALIGN="LEFT" | |
| 589 WIDTH="100%"><TABLE | |
| 590 WIDTH="100%" | |
| 591 BORDER="0" | |
| 592 CELLPADDING="0" | |
| 593 CELLSPACING="0" | |
| 594 ><TR | |
| 595 ><TD | |
| 596 WIDTH="33%" | |
| 597 ALIGN="left" | |
| 598 VALIGN="top" | |
| 599 ><A | |
| 600 HREF="power-attached.html" | |
| 601 >Prev</A | |
| 602 ></TD | |
| 603 ><TD | |
| 604 WIDTH="34%" | |
| 605 ALIGN="center" | |
| 606 VALIGN="top" | |
| 607 ><A | |
| 608 HREF="services-power.html" | |
| 609 >Home</A | |
| 610 ></TD | |
| 611 ><TD | |
| 612 WIDTH="33%" | |
| 613 ALIGN="right" | |
| 614 VALIGN="top" | |
| 615 > </TD | |
| 616 ></TR | |
| 617 ><TR | |
| 618 ><TD | |
| 619 WIDTH="33%" | |
| 620 ALIGN="left" | |
| 621 VALIGN="top" | |
| 622 >Attached and Detached Controllers</TD | |
| 623 ><TD | |
| 624 WIDTH="34%" | |
| 625 ALIGN="center" | |
| 626 VALIGN="top" | |
| 627 > </TD | |
| 628 ><TD | |
| 629 WIDTH="33%" | |
| 630 ALIGN="right" | |
| 631 VALIGN="top" | |
| 632 > </TD | |
| 633 ></TR | |
| 634 ></TABLE | |
| 635 ></DIV | |
| 636 ></BODY | |
| 637 ></HTML | |
| 638 > |
