This document discusses theoretical issues and implementation details for "hot swappable" devices for both the Microsoft Windows 98 and Windows 2000 operating systems. Readers are assumed to have a thorough working knowledge of the Advanced Configuration and Power Interface (ACPI) specification, and should have the latest version of the specification. Hardware that is covered in this document may include expansion bay devices within laptops, docking stations, and hot swap servers. The latest version of the ACPI specification can be downloaded from http://www.acpi.info/
.
Important: This document is an early draft version, distributed primarily for review comment. Changes may be made to any part of the document, especially in the details of each section. Note that although docking is discussed, an explanation on how to handle docking in ACPI is not the primary purpose of this document. For more information about how to handle docking in ACPI, please see ACPI Docking for Windows.
An ACPI BIOS declares that a device is removable in one of three ways:
| • | The BIOS exposes one or more _EJx methods (where x is 0-4), which the operating system will call in order to eject the device. |
| • | The BIOS exposes an _LCK method, indicating that the device requires locking (and therefore is removable). |
| • | The BIOS exposes an _RMV token, indicating the device is not lockable or ejectable, but is removable. |
Docking stations are identified using the _DCK method. Docks must support at least one _EJx method.
An ACPI BIOS notifies the operating system of hot swap events by using the Notify(device, event) operation. The notification codes for docks and devices are different.
The following are notification codes for generic devices.
Notify(device, 0) - Enumerate device.
The operating system scans the device to see if any children devices have appeared or been removed. Each child device will also be examined, until all descendants of the parent device have had their presence or absence verified.
Notify(device, 1) - Check device.
The operating system will check to see if the device has appeared or disappeared. The BIOS should
not rely on the operating system to scan the device's descendants if there is no change in the device's presence. In general, Notify(device, 1) is more efficient than Notify(deviceParent, 0). This is because the device's siblings do not need to be examined; the device's children require examination only when the specified device has appeared or disappeared.
Note: Windows 98 will always translate Notify(device, 1) into Notify(deviceParent, 0).
Notify(device, 2) - Wake event.
(Not within the scope of this paper.)
Notify(device, 3) - Eject device.
When Notify(device,3) is invoked, the operating system will prepare the device for removal. If the device drivers can successfully be unloaded, the operating system will power the device down, then call
_LCK, if present, to unlock the device. After being unlocked, the operating system will choose among the available _EJx methods and call one, if available.
Note: This event is currently not supported in Windows 98.
Notify(device, 0) - Dock arrival.
When invoked, the operating system will run
_DCK(device, 1) to remove isolation from the devices in the dock. Note that the _STA should reflect the physical presence of the dock, and therefore should be unaffected by the _DCK method. It would, however, be affected by the _EJx method.
Notify(device, 1) - Undock request.
When Notify(device,1) is invoked, the operating system will attempt to undock. If all the appropriate devices can be stopped, the operating system will call
_DCK(device, 0) to re-isolate the dock from the rest of the system. As mentioned above, the _STA method should be unaffected by the invoking of _DCK.
Next, the operating system will call one of the _EJx methods. If warm ejection is selected, the operating system will put the system into the Sx state that corresponds with the _EJx method called.
ACPI devices described in the BIOS NameSpace fall into two categories:
| • | Devices described by _HID methods |
| • | Devices described only by _ADR methods |
A device described using a _HID method is enumerated exclusively by ACPI. The operating system relies only on the _STA method to determine whether the device is present. If the device is powered-down, bit 1 of the _STA method (device enabled and decoding) may change, but bit 0 (device present) should not change unless the device has been removed from the system.
The situation for devices described only by _ADR methods is more complicated. _ADR methods are used to describe devices enumerated by other buses. When the driver for such a bus discovers a new device, it assigns it an address number corresponding to its location. The ACPI driver then examines the namespace for objects whose _ADR method previously evaluated to that address number. Next, each matching object has its _STA method executed. If one of the object's _STA methods returns present, a match is made and the ACPI now augments functionality for that device.
Note that the presence of an _ADR object is not determined by the _STA. If the bus driver finds a device, that hardware will be reported to the operating system. The _STA method for an _ADR device only helps the operating system correlate the bus device with its ACPI NameSpace representation. For example, consider a system with an expansion bay that accepts either a DVD drive or an IDE drive. The two drives use different timings. This configuration might be represented in the NameSpace as follows:
Device(PCI0) // PCI root bus
_HID { ... }
Device(IDE0) // PCI IDE controller
_ADR 0x40001 // PCI device 4, function 1
Device(PRIM)
_ADR 0 // Primary channel
Device(SECD)
_ADR 1 // Secondary channel
Device(DVD)
_ADR 0 // Master drive
_STA { } // Returns present if DVD
_GTM ... // Get DVD drive timings
_STM ... // Set DVD drive timings
Device(IDE)
_ADR 0 // Also Master drive
_STA { } // Returns present if IDE
_GTM ... // Get IDE drive timings
_STM ... // Set IDE drive timings
If more than one NameSpace match is found, a BIOS bug is indicated. In the above example, if the _STAs for the DVD and IDE both returned as present, Windows 2000 would stop and display the bugcheck screen. If an _ADR device match is made, but then broken before the operating system learns about the device's disappearance via the parent bus driver (that is, the _STA method begins reporting that the device is missing), the operating system will initiate a surprise stop of the device and wait for its parent's bus driver to report that the device is missing.
Note that Windows 98 does not handle a multiple NameSpace match correctly.
Note: If a _STA method is not present, the operating system will assume the device is present and working. In the earlier example, the PCI root bus is assumed to be present. For the _ADR devices, the IDE controller and both of its channels are assumed to be present if they were found by their bus drivers.
ACPI-based power management of devices described by _HID methods is not difficult; the BIOS must ensure that devices without power are still reported as present.
ACPI-based power management of devices described only by _ADR methods is more constrained and requires discussion.
Problems will arise when an ACPI BIOS puts an _ADR device into a deeper sleep state than its bus is expecting. It is important to remember that any buses (including PCI) do not expect devices to disappear from the bus when they are powered down. If a subsequent enumeration of that bus takes place, the bus driver will believe that the powered-down devices have been removed from the system. In Windows 2000, this may result in an "Unsafe Surprise Removal" dialog box. For Windows 98, no dialog box will appear; the disappearance of an IDE device will result in an IDE error bluescreen.
In the case of PCI, it is safe to remove all power (including "enumeration" power) when the parent device is powered down. This can be accomplished in the PCI parent's _REG method, or in the appropriate power method.
An ideal place to cut enumeration power is in an _EJ0 method. When the _EJ0 method returns, the operating system expects the device to be missing. In such a system, the BIOS should re-enable enumeration power when it detects the reinsertion of the device.
To support a swappable device, the BIOS must be able to dynamically detect when the device has appeared, and when it has been removed. The hardware may or may not support some level of power during insertion or removal.
Design Scenario 1
The operating system presents the PCI device as removable. This design assumes the device can be safely removed while it is still visible on its parent bus. When the device is removed or inserted, a General Purpose Event (GPE) occurs, which requests a "device check" from the operating system.
Device(DEVI)
_ADR 0x40000 // PCI device 4, function 0
_RMV
_GPE
Method(_Lxx) { // Update device
Sleep(250) // Mechanical Delay
Notify(DEVI, 1)
}
Design Scenario 2
The operating system presents the PCI device as ejectable. This design ensures the device is fully powered-off prior to being removed. After the
_EJ0 method is run, the device cannot be detected on the bus. When the drive is removed or inserted, a GPE initiates a "device check" in the operating system.
Device(DEVI)
_ADR 0x40000 // PCI device 4, function 0
_EJ0 {
//
// Remove all power to device
//
}
_GPE
Method(_Lxx) { // Update device
Sleep(250) // Mechanical Delay
If (InsertionEvent) {
PWRN() // Reenable power if insertion event
}
Notify(DEVI, 1)
}
Special Note for Multifunction PCI devices:
Multifunction devices present special problems for ACPI. Although ACPI can describe all the functions of a PCI device using a
_PRT method (such as 0x4FFFF), this is not possible within the NameSpace. In the NameSpace hierarchy, each of the possible eight functions must be called out individually.
Another problem results because the _EJD method can call out only one device; it is impossible to construct a graph in the NameSpace where the ejection of any individual function will cause the ejection of the others. In Windows 2000, this is troublesome because Windows 2000 automatically assumes that the functions of a PCI device are ejected together.
The following code shows a generic hot-plug slot example based on Design Scenario 2:
Device(DV40)
_ADR 0x40000 // PCI device 4, function 0
_EJ0 {
//
// Remove all power to device, enable
// safe removal _LED.
//
}
Device(DV41)
_ADR 0x40001 // PCI device 4, function 1
_EJ0 { DV40._EJ0() }
Device(DV42)
_ADR 0x40002 // PCI device 4, function 2
_EJ0 { DV40._EJ0() }
Device(DV43)
_ADR 0x40003 // PCI device 4, function 3
_EJ0 { DV40._EJ0() }
Device(DV44)
_ADR 0x40004 // PCI device 4, function 4
_EJ0 { DV40._EJ0() }
Device(DV45)
_ADR 0x40005 // PCI device 4, function 5
_EJ0 { DV40._EJ0() }
Device(DV46)
_ADR 0x40006 // PCI device 4, function 6
_EJ0 { DV40._EJ0() }
Device(DV47)
_ADR 0x40007 // PCI device 4, function 7
_EJ0 { DV40._EJ0() }
_GPE
Method(_Lxx) { // Update device
Sleep(250) // Mechanical Delay
If (InsertionEvent) {
//
// Turn of safe removal _LED
// Reenable power
//
}
Notify(DV40, 1)
Notify(DV41, 1)
Notify(DV42, 1)
Notify(DV43, 1)
Notify(DV44, 1)
Notify(DV45, 1)
Notify(DV46, 1)
Notify(DV47, 1)
}
Design Scenario 1
The operating system presents the CD-ROM drive (for example, drive D) as removable, as opposed to the controller or channel itself. This design assumes the CD-ROM drive can be safely removed while it is still visible on its parent bus. When the drive is removed or inserted, a GPE initiates a request for a "device check" in the operating system. Upon insertion, power is reapplied.
Device(IDE0) // PCI IDE controller
_ADR 0x40001 // PCI device 4, function 1
Device(PRIM)
_ADR 0 // Primary channel
Device(SECD)
_ADR 1 // Secondary channel
Device(CDRM)
_ADR 0 // CDROM
_RMV
_GPE
Method(_Lxx) { // Update device
Sleep(250) // Mechanical Delay
Notify(CDRM, 1)
}
Design Scenario 2
In this design, the operating system presents the CD-ROM drive (for example, drive D) as ejectable, as opposed to the controller or channel itself. This design ensures that the CD-ROM drive is fully powered-off prior to being removed. Following the
_EJ0, the device cannot be detected on the bus. When the drive is removed or inserted, a GPE occurs that requests a "device check" from the operating system.
Device(IDE0) // PCI IDE controller
_ADR 0x40001 // PCI device 4, function 1
Device(PRIM)
_ADR 0 // Primary channel
Device(SECD)
_ADR 1 // Secondary channel
Device(CDRM)
_ADR 0 // CDROM
_EJ0 {
//
// Remove all power to device
//
}
_GPE
Method(_Lxx) { // Update device
Sleep(250) // Mechanical Delay
If (InsertionEvent) {
PWRN() // Reenable power if insertion event
}
Notify(CDRM, 1)
}
Note: Windows 98 does not currently handle notification on the IDE drive, but it does support notification on the IDE channel. Therefore an alternative implementation could eject the channels instead of the drives. It is worth noting that a significant percentage of users are not familiar with the "ESDI/IDE channel."
Note: The controller in this example is PIIX4.
In the normal operation of a Plug-and-Play operating system, each device is started when it is discovered. The operating system then enumerates the device, also looking for children devices to start.
However, compatibility-mode IDE controllers present problems. Many systems support configurations where two legacy PCI IDE controllers are present at the same time. This works because one IDE controller has only the primary channel enabled (1f0-1f7), and the other has only the secondary channel enabled (170-177).
The operating system risks a hardware crash whenever it enables a legacy IDE controller channel that was left powered-off by the BIOS. Furthermore, channels with no children cannot be disabled, since a drive could be inserted at any time. Therefore, Windows 95, Windows 98, and Windows 2000 never enable channels on legacy IDE controllers.
Furthermore, none of the three operating systems enumerates a channel device when the channel is disabled. This means turning off the channel may lead to a surprise removal dialog.
In the PIIX4 system, the primary channel is enabled and disabled by writing to the IDE controller's config space at offsets 40-41. Similarly, the secondary channel is enabled and disabled writing to the IDE controller's config space at offsets 42-43.
Device(IDE0) // PCI IDE controller
_ADR 0x40001 // PCI device 4, function 1
Device(PRIM)
_ADR 0 // Primary channel
Device(SECD)
_ADR 1 // Secondary channel
Device(CDRM)
_ADR 0 // CDROM
_EJ0 {
//
// Remove all power to device
//
}
_GPE
Method(_Lxx) { // Update device
Sleep(250) // Mechanical Delay
If (InsertionEvent) {
PWRN() // Reenable power if insertion event
}
Notify(CDRM, 1)
}
It may be desirable to "disable" the channel itself while drives can be removed or inserted. If the _EJ0 method in the above code were to disable the channel by writing to config space offsets 42-43, Windows operating systems will believe the channel itself has been removed. In Windows 2000, the operating system will display an "Unsafe Device Removal" dialog.
One possible solution is to eject the channel itself. However, there are two disadvantages with this potential solution. The user will be ejecting the "IDE/ESDI channel," as opposed to "CDROM (D:)." Secondly, the BIOS itself must turn on the channel. If a PCMCIA ATAPI card (for example, Sundisk) has been inserted, the operating system might place it at locations 170-177. When the BIOS enables the channel, the two devices will be configured at the same ports, possibly leading to data corruption.
The best solution requires that the laptop hardware be able to enable and disable the drive independently of the channel decodes.
If such hardware support is unavailable, a BIOS could disable the channel without visibly changing config space offset 42-43 by installing a SMI hook. Such BIOS code would in theory "fake-out" the values returned from config space offsets 42-43 when the channel resources should be reserved and the decodes left off. While this can be considered a possible solution, it is not recommended.
Note that, while legacy IDE controllers other than PIIX4 may use a different mechanism than config space offsets 40-43 to enable and disable channels, the problems discussed above are the same. Of course, an IHV building a custom IDE chipset--including separate states for "on/present" and "decoding,"--would solve the above problem. Nevertheless, supporting native mode is the most preferred solution.
Floppy controller enumeration has historically been accomplished by seeking the head inward towards the first track. The operating system detects a drive by monitoring the controller to see if a physical head signals it has reached track 0. Unfortunately, this method of enumeration is extremely slow, possibly being measured in seconds per drive. Windows 98 systems may be configured to not scan the floppy bus at boot, relying instead on the BIOS data. Similarly, Windows 2000 never scans the floppy bus with legacy enumeration techniques. To provide for hot swappable floppy support, ACPI systems can implement the _FDE method. Windows 2000 will use this method if it is present. Windows 98 does not currently support this method.