Выбрать главу

Device drivers often need access to physical resources, such as memory-mapped registers or DMA buffers, yet drivers cannot directly access physical memory because the system only works with virtual addresses. For device drivers to gain access to physical memory, the physical addresses must be mapped to virtual addresses.

Dynamically Accessing Physical Memory

If a driver requires physically contiguous memory, as in the case of buffers required for DMA operations, the driver can allocate contiguous physical memory by using the AllocPhysMem function. If the allocation is successful, AllocPhysMem returns a pointer to the virtual address that corresponds to the specified physical address. Because the system allocates memory, it is important to free the memory later on when it is no longer needed by calling FreePhysMem.

On the other hand, if a driver requires non-paged access to a physical memory region defined in Config.bib, you can use the MmMapIoSpace function. MmMapIoSpace returns a non-paged virtual address that is directly mapped to the specified physical address. This function is typically used to access device registers.

Statically Reserving Physical Memory

Occasionally, it may be necessary to share a common region of physical memory between drivers or between a driver and the OAL (such as between an IST and an ISR). Similar to sharing a memory region for boot arguments between boot loader and kernel, you can reserve a shared memory region for driver communication purposes in the Config.bib file. A standard practice is to use the DRIVER_GLOBALS structure defined in Drv_glob.h, as mentioned in Lesson 1.

Communication between Drivers and the OAL

In addition to the standard set of IOCTLs required by the kernel, drivers can communicate with the OAL through custom IOCTLs implemented in OEMIoControl. Kernel-mode drivers call OEMIoControl indirectly through KernelIoControl, passing in the custom IOCTL. The kernel does no processing, other than passing the parameters straight through to OEMIoControl. However, user-mode drivers cannot directly call custom OAL IOCTLs by default. The KernelIOControl calls from user-mode drivers or processes are passed to OEMIoControl through a kernel-mode component (Oalioctl.dll), which maintains a list of user-accessible OAL IOCTL codes. The call is rejected if the requested IOCTL code is not listed in this module, but you can customize this list by modifying the Oalioctl.cpp file that is located in the %_WINCEROOT%\Public\Common\Oak\Oalioctl folder.

Lesson Summary

A good understanding of the Windows Embedded CE 6.0 memory architecture is a must for every CE developer. Specifically for BSP developers, it is important to know how CE 6.0 maps available physical memory into the virtual memory address space. Accessing memory from OAL, kernel-mode modules, and user-mode drivers and applications requires a detailed understanding of static and dynamic mapping techniques that are available in kernel mode or user mode. For more information about the communication between kernel-mode and user-mode components, refer to Chapter 6, "Developing Device Drivers."

Lesson 3: Adding Power Management Support to an OAL

As discussed in Chapter 3, "Performing System Programming," Windows Embedded CE 6.0 provides a comprehensive set of power management features based on a Power Manager component that OEM developers can customize to implement system power state definitions as appropriate for their hardware platforms. In relationship to the OAL, implementing power management capabilities is a twofold task. You need to enable the operating system to control the power state of the hardware components and you need to enable the hardware platform to inform the operating system about power state changes. Most embedded devices require at least basic power management support to reduce power consumption and prolong battery life.

After this lesson, you will be able to:

■ Describe how to reduce processor power consumption.

■ Identify the transition paths to suspend and resume the system.

Estimated lesson time: 15 minutes.

Power State Transitions

Embedded devices that are not constantly in use, such as personal digital assistants (PDAs), operate for extended periods of time in an idle state, thus providing an opportunity to preserve energy by switching from full-power mode to a reduced-power mode or suspend state. Most embedded processors available on the market today support these transitions, as illustrated in Figure 5-9.

Figure 5-9 Power state transitions

Windows Embedded CE can respond to power-related events in the following ways:

■ Battery critically low The system switches into Critical Off state in response to a nonmaskable interrupt (NMI) that a voltage comparator on the board triggers, so that the user can replace the battery and resume.

■ Idle The system switches the CPU into reduced-power mode if the CPU has no worker threads to run and wakes up when an interrupt occurs.

■ Suspend The system switches the device into Suspend state when the user presses the Off button or in response to an inactivity timeout and resumes in response to a wakeup event, such as the user pressing the power button again. On some embedded devices, the Suspend state corresponds to a true power-off state, in which case the system resumes with a cold boot.

Reducing Power Consumption in Idle Mode

To switch the device into reduced-power mode, Windows Embedded CE relies on the OEMIdle function, which the kernel calls when the scheduler has no threads to run. The OEMIdle function is a hardware-specific routine that depends on the capabilities of the platform. For example, if the system timer uses a fixed interval, then the OEMIdle function cannot really provide the expected power saving functionality because the system wakes up every time a timer interrupt occurs. On the other hand, if the processor supports programmable interval timers, you can use the kernel's dwReschedTime variable to specify the amount of time spent in reduced-power mode.

On waking up from reduced-power mode, the system must update the kernel global variables used by the scheduler. This is particularly important for the CurMSec variable, which the system uses to keep track of the number of milliseconds since the last system boot. The wakeup source can be either the system timer or another interrupt. If the wakeup source is the system timer then the CurMSec variable is already updated before execution is passed back to the OEMIdle function. In other cases, the CurMSec does not contain an updated value. To learn more about the OEMIdle implementation details, refer to the Idle.c source code file, located in the %_WINCEROOT%\Platform\Common\Src\Common\Timer\Idle folder.

NOTE
Kernel global variables

For detailed information about global variables that the kernel exports for scheduling, see the section "Kernel Global Variables for Scheduling" in the Windows Embedded CE 6.0 Documentation, available on the Microsoft MSDN Web site at http://msdn.microsoft.com/en-us/library/aa915099.aspx.

Powering Off and Suspending the System

The maximum power saving state that a Windows Embedded CE device can support is the Power Off or Suspend state. The system can request the device to enter the Suspend state by calling GwesPowerOffSystem directly or SetSystemPowerState. Both functions eventually call the OEMPowerOff routine.