Mac OS X Essentials • 52:38
With the rapid growth of the notebook computer market, more customers than ever count on the power management features of Mac OS X to handle sleep/wake cycles and maximize battery life. Learn how to take advantage of the Leopard power management APIs to ensure your applications and device drivers handle power events gracefully.
Speakers: Ethan Bold, David Ferguson
Unlisted on Apple Developer site
Transcript
This transcript has potential transcription errors. We are working on an improved version.
So, hello everybody. I am really happy to see so many people showed up on Friday at 5 p.m. for Improving User Experience With Effective Power Management. My name is Ethan Bold, and I come from the Core OS team. I work on the I/O Kit Driver framework. And I am going to be speaking with Dave Ferguson from the USB team. He's going to come on stage after me in a little bit to talk about how the USB team has implemented a lot of power management technology in Leopard.
So today I want to talk to you about first off a couple of new things in Leopard. We have a new chapter on managing power and the I/O Kit Fundamentals book, which is available as a PDF today. We've got a new power management implementation in the kernel, and then we're going to discuss for a few slides how to implement a power managed device driver in the kernel. And then we'll finish up with a little bit of user space API for interacting with power management in your user space application.
So why should you as a device driver developer worry about managing power in your device? One thing -- one reason is battery life. When you save a milliwatt or a watt of power in your device you're saving minutes or dozens of minutes of battery life for your developers. These numbers up on screen are approximate, they're really just estimates, and obviously these numbers would vary by system and by your usage environment.
But for example, we do save 15 to 20 minutes of battery life just by turning off the audio hardware when your MacBook or PowerBook isn't actively playing any audio. The same goes for the battery. I am sure everyone who's used a MacBook or a PowerBook has seen the display dim after a few minutes of not using the keyboard or mouse.
And finally we save tons of battery life by powering down the CPU when it's not in use. That happens totally automatically on all of your computers out there. And we save, I mean, at least 30 or 40 minutes0, sometimes up into an hour or an hour-and-a-half of battery life by automatically consuming -- I'm sorry -- automatically preserving CPU power. Another thing to note is that when you save power for your users, you are not only saving battery life, you're generating less heat that means a cooler MacBook on their lap, and it means that the fans are going to stay quiet a lot longer.
Now I want to point out that this is the -- the interface that most of your users have with power management. You'll notice that I talked about the audio driver and the CPU driver on the previous slide. And neither of those drivers is here. There aren't user settings for that. It is that they're drivers and their software is smart enough to realize when their hardware isn't actively in use. And that's what -- what all of your device drivers and all of your software can do as well.
So the first thing I want to point out is we have a brand new rewrite of the Managing Power chapter in I/O Kit Fundamentals. I/O Kit Fundamentals is our I/O kit book. It's available as a PDF. And this new chapter we have is -- is very informative - it's got some great documentation about using power management APIs in the kernel and in device drivers. So it's available at the WWDC page for this session. And it's available today.
So we have made some pretty significant changes to power management in the OS X kernel, in Leopard. Some of the things that drove those changes leading up to Leopard were that it hasn't been a very convenient or easy environment for developers to write drivers to. There were a lot of issues with OS X's threading model and locking model that were difficult to interact with. And the APIs were vague. Sometimes a call was synchronous, sometimes a call was asynchronous, and it was very hard to -- to really account for all of that.
So in Leopard we fixed a lot of those things. First off, we eliminated the issue of the ambiguous behavior by defining and documenting all of those in-kernel power management calls. And we introduced a new chapter -- that new chapter I just talked about, the Managing Power chapter in I/O Kit Fundamentals. But we also improved our locking and threading model, and we made all calls into power management asynchronous, which provides a much more -- a much more consistent interface for anyone writing a driver with power management.
So -- so if you are beginning to implement power management in your own driver, the first thing you need to do is consider what level of support your I/O kit family provides for you automatically. For certain families like USB and networking and FireWire, and mass storage, those families provide quite a bit of built-in support for power management. And your driver as a sub class of those needs to know how to interact with the support built into the super class.
Other drivers don't provide as much or any built-in power management support. Those are drivers like PCI or audio. And when I say, does your family provide built-in power management support -- I mean that -- I/O service provides a base level of APIs that we're about to discuss and go through on the next few slides. But some of these other families provide other APIs that you would use instead of or in addition to those basic APIs.
So I want to go over the I/O power plan. This is the basic data structure that OS X uses to track the power dependencies of devices in the system. And it's this data structure that OS X uses to determine what order to put all of the hardware in your system to sleep when you close your laptop and put your machine to sleep, and what order to power those devices on in order to wake the machine from sleep. So the I/O power plan is a tree-like structure.
At the root we have the -- a note called IOP and root domain. And that's the parent of all the devices in the system. And throughout the rest of the tree we have -- so elsewhere in the tree a -- any node -- has its power dependencies as its parent. So if you were writing a driver for a USB audio device, you would declare an audio -- a power dependency on the USB bus above you.
So your USB audio devices -- devices, node's parent would be USB power. And this would let OS X know that when we're powering the machine off for sleep, we should always power off that USB audio node first before we power off its parent, because the USB audio device will probably need to communicate across that parent node's USB bus. And this -- this diagram shows a sleep transition in progress. You can see some of the leaf nodes are highlighted because we always -- when we're putting a machine to sleep we always turn off the leaf nodes first.
So what I want to talk about now is the API calls that your driver would use to interact with -- with kernel power management, and how your driver would insert itself into the I/O power plan here to be involved in system power management. So there are -- there are three calls that your driver would need to make in its I/O service start routine to be involved in system power management.
The first one is PM init. That initializes some basic power management data structures. The second is join PM tree. And depending on the arguments that you pass and how you call join PM tree, that is the call that's going to insert your driver into the I/O power plan.
And the third call is register power driver. Register power driver is the call that you make to let the kernel power management know what kind of power states you have. You can offer -- usually just an on state or an off state for a very simple driver. And your device would be in the on state when the system was awake and fully on. And then put your device in its off state when we put the machine to sleep.
So after you make those three set up calls, those PM init, join PM tree, and register power driver, there is a couple of other calls you need to implement to -- to be a part of power management in a very passive, simple way. Now when I say passive, I mean if you were a passively power managed driver then you are involved in system sleep and system wake.
But you're not necessarily going out of your way to actively power-manage your device, like the -- the audio chip I talked about before, or the CPU. You're just simply involved in system sleep and system wake. And able to power down your hardware and restore it safely away from sleep. So the next things your driver would have to do would be to implement the I/O service virtual method, Set Power State.
Set Power State is the -- it's the hook that OS X uses to communicate into a driver to say, all right, it's your turn to turn off. To let the system go to sleep. Or it's your turn to power back on when you're waking from sleep. And finally, you need to make one clean up call, PM stop, in your driver stop routine. So just to -- to obtain a bare minimum of interaction with system power management, you need to make those three initialization calls I just discussed, and implement that one virtual I/O service method. And call PM stop.
And again, if you'll remember that slide -- I showed it a couple of minutes ago -- about how certain families already implement some forms of power management for you, this is a perfect example of you might not need to make all these calls if you're, say, a USB driver or a FireWire driver, because your family may already make some of these calls on your behalf.
So next up I want to talk about how you can be more involved in managing your own power and how you can contribute to power savings over the course of a running system. So -- so if your driver is actively involved in power management it can turn off the -- its hardware where the machine is going to sleep, and it can turn that hardware back on when the system's waking up.
But it may also have a more -- a more sophisticated way to manage its power when the system is running, and the hardware isn't in use. So -- so I am going to go through some existing API that you can use to add this kind of support to device drivers today and let OS X automatically notice when your hardware isn't in use, and idle your devices into a lower power state.
So the first thing we need to talk about is -- is what power states your device offers. If you were writing a passive device driver that was only involved in system sleep wake and didn't have any more advanced power states, you might justify these two power states. On, and off. And when the machine was awake and useable, your device would be on. And when the machine was off and asleep, your device would be off.
Now you're -- now maybe your device is more sophisticated. Maybe you have a -- a state that's a lot, maybe, faster to transition into, and to transition out of than a full off state, and maybe you can transition into this state while the system is running, but while your device isn't actively in use.
This -- this power state array here pretty accurately mirrors what the -- the audio device's power state might look like in any of your MacBook pros. Because when you're playing music or you're playing sound, the device is fully on. But 20, 30 seconds later, when there's -- there's no sound being played, the device can automatically transition itself into its low power state and can remain there until -- until you play sound again, and then jump right back up to it's on state to service that sound request. And you don't have to stop there. If you have a sophisticated device with several degrees of power savings, you can always take advantage of as many of those as you want using this mechanism. This framework of power management.
So -- so earlier I talked about five API calls you would make to be involved in passive power management for your device, and there's really just two more that you would -- that you would need to use to be able to automatically power your device down into a lower power state and then automatically back up when your device needed to be used again.
So with the call set idle timer period and activity tickle, you can do just that. So by calling set idle timer period you can let power management know how -- how long you want your device to be idle before being put into a reduced power state, so you could pass in 15 seconds, or 30 seconds, or 2 minutes. And -- and then after 30 seconds of no device activity, OS X would -- would -- would call into your driver on that set power state routine we talked about before, and would power your device down.
So if your device had an on state, a low state and an off state, after 30 seconds of not having any activity on your device, OS X would put you into your low state. So like I just said, the idle timer once its elapsed will power your device down.
Now, now of course OS X needs to somehow know when your device isn't active. And that's what that activity tickle call was all about. The activity tickle call, you would have to call that somewhere on a data or on a hardware access path in your device driver. So any time your driver accessed its own hardware, or any time a user space application triggered a hardware request you'd want to call activity tickle.
And one thing I haven't mentioned is that you can use the call Change Power State to, to set a minimum of idle power state. So if you had those on low and off states and you wanted your device to idle down from on to low, but never to go lower than that, then you could use Change Power State to, to set a floor at that low state.
And again, that is documented, and you can read all about it in the Managing Power chapter in I/O Kit fundamentals. Very proud of that chapter. You guys should really take a look. Very excited. So I also wanted to talk about kind of switching gears a little bit. This is a new driver space API in Leopard for -- for I/O Kit, or I/O service sub classes.
This is a -- a shut down notification that your driver can register for simply by implementing the I/O service method, System Will Shut Down. And on system shut down or restart, at the very latest stages of shut down and restart, OS X, the kernel, will call into your device with -- via that System Will Shut Down method with either the System Will Shut Down, or System Will Restart argument.
Now, we are implementing this in the same order that we put -- that we put devices to sleep. So if you think back to that I/O power plan that I discussed earlier, a USB device would be the first one to get this -- this shut down notification even earlier than its USB parent.
And of course, I should mention that USB has its own implementation of shut down and restart notifications that -- that layer on top of this. So this is a perfect example of -- of a -- an I/O Kit family providing a different level of support for power management than the basic level. So if you were writing a USB driver, you can still get this shutdown message, just through a different format.
And I also want to mention that of the interesting thing about running code at shutdown time, and this shutdown time is it's after applications have all been killed, it's after all the file systems have been torn down. It's that any code you run here only -- only link -- only makes your user shutdown take longer. So you can -- unfortunately it's pretty easy to add to a bad user experience by running too much code at this time.
And this replaces an older call, called register priority sleep wake interest that had a few problems that made us replace it. The notifications were not ordered, so -- so for instance, if you were a FireWire disk that needed to -- to flush any unsafe buffers to a hard disk, then it's very possible that the FireWire bus that your device is loaded on was already turned off, or had already received it's shutdown notification and turned off. Thus making your disc completely inaccessible. So that's fixed by the new notification.
And the old notifications were also single-threaded. So in Leopard we were able to run all those shutdown notifications in parallel and make that important shutdown process even faster. So I want to switch gears. We've been talking about in kernel device driver API for I/O Kit devices. And I want to jump up to user space and run through a few really interesting user space power manager and APIs that can help your app more -- better interact with power management.
And we're going to talk about how to schedule a timed sleep wake shutdown power on or restart. How to listen for sleep wake notifications, and how to prevent idle sleep or prevent displaced sleep very easily with one line of code. Because before that's been a little complicated to do. So that's a fun new API.
So first, I want to talk about I/O PM schedule power event. This is a queued interface that let's you request a system wake up or sleep or shutdown. Say you could request a shutdown on Friday night at 8 p.m. and -- and then when that time came around the system would -- would shutdown. You could also request a wake up Monday morning at 7 a.m.. And the wake up Wednesday morning at 9 a.m. so it's a fairly simple API. But it's been available since 10.4 and it's pretty useful.
Next, I -- I want to talk about the I/O register for system power notification. This is the notification that you can use to -- to simply get a notification when the system goes to sleep, or when the system wakes up. I should point out that you do not get a system shutdown notification through this API. That's kind of outside of the scope of this API. And yeah, so this API is only for getting notified on system sleep, and on system wake.
So there are a couple of arguments to this -- to this function that you might be interested in Like KIO Message, Can System Sleep. KIO System Will Sleep, and KIO Message, System Has Powered on. Your application would get a System Will Sleep message before any of the hardware devices on the system have powered off.
So your app would get this message and it would handle it, and only when it was done, say, saving unsaved documents or saving drafts, if you're writing in a Text Editor, or closing out openly network connections. Only after you're done doing that does OS X tear down the driver stack below it and eventually put the machine to sleep. And then again, on Wake From Sleep after that, OS X builds up the entire power stack by powering all your devices on. And once all of the devices are on, it will send out the KIO message, system has powered on.
So if you are using these, this API with these notifications you might notice three to five seconds between the time the system appears to wake up and the time your application actually gets the wake up notification. And that's because that delay is powering on every device in the system.
So the big caveat about these APIs is that they're easy to misuse or to miss -- pretty important call to acknowledge the notification with the kernel. So when you receive one of these Can System Sleep or System Will Sleep notifications, it's imperative that you reply immediately -- or as soon as you're done with your sleep processing, with an IO Allow Power Change message. IO Allow Power Change, it let's the kernel know that you're done doing whatever you were going to do.
And finally, I want to talk about a really cool new API in Leopard called IO PM Insertion Create. There are two arguments that you can pass to it today. They are KIO PM Assertion Type No Displaced Sleep and assertion type No Idle Sleep so if you were writing a, say, an FCP client and you wanted to make sure that no matter what the Mac that you were downloading or up loading a file on stayed awake, then you could call IO PM Assertion Create, assertion type No Idle Sleep.
And that would completely disable idle sleep until you later called IO PM Assertion Release to release that assertion. And the same goes for No Displaced Sleep. If you were displaying a movie or a presentation like in key note, you would -- you would want to use this call to completely disable Displace Sleep and keep it as Play Awake the entire time.
So these calls are new in Leopard. One thing worth noting is that they only allow you to prevent idle sleep. They don't let you prevent sleep if the user selects sleep from the Apple menu, or chooses sleep or if there's software on the computer that it causes sleep programatically.
And of course there's a lot of things you can't prevent, like forces of nature. Like thermal emergencies, or batteries running out of juice, that's just -- how it goes. So that's it for me. And up next is Dave Ferguson who's going to talk to you about USB and how they've implemented some of these power management APIs in Leopard. Thank you.
( Applause )
Thanks, Ethan. To talk about USB power management we first start with the USB spec. Because the spec defines how USB devices specify their power, when USB devices can draw power from the USB bus at what levels and what times, USB devices have to draw a very small amount of power until they're configured. Once they're configured the host operating system can detect that that device declares it needs more power, if there is more power. For instance, you're plugged into the root hub on the back of the machine or into a self-powered hub.
If there's enough power then we can configure that device for high power. If the device doesn't need much power and it can work, say, in a keyboard hub, then we can configure it right away. USB devices have to support suspend mode. This means that when the USB bus becomes inactive, they have to go into a very low power mode where they draw milliamps, like 2.5 milliamps for a high power device.
Now the USB devices can wake up a sleeping computer. So once the USB bus is suspended, it's possible for a device to generate a Resume signal which says, wake up the port that I'm on. And if it's a running machine, it just wakes up to do communication. If it's a sleeping machine, it would wake the whole machine up. So you experience this every day when you put a machine to sleep and you wake it up with a keyboard press or clicking the mouse button.
So if a USB device defines itself as having remote wake up capability, then we automatically enable that. So that means that modems that have the ability to wake on ring automatically get that behavior. Any other USB device can easily with a device that wakes up the system. It just has to have its describers correctly configured. And all of that is specified in the USB spec. This suspending that I was talking about does come in a flavor known as Selective Suspend.
And that's where we suspend just a single port on a USB hub. And that suspends that device and all down stream devices. So a portion of the tree can easily be trimmed out, causing it to go into the lowest power states. So you can see that USB devices can control their power by having their port suspended whenever they're not actively transferring data or need to be polled for data.
I'm going use this picture today and so you're going to see it a lot. And I thought I would describe it here. This is the USB topology. So at the top I've got a USB controller. I've chosen to use rectangular boxes because these actually represent real hardware. So the USB controller in this case might have a Bluetooth connected over there on the left.
It has a keyboard and a mouse, you know, connected there in the center. And on the right-hand side you see a USB hub. And down stream of that hub is an audio device, both input and out put, and a USB mass storage. The green around that represents that these devices are turned on right here. The green represents the on state.
Now we also have the I/O power tree. And in Tiger and up until Leopard, the I/O power tree was very flat. The USB controller was a power parent, and all USB devices were power children of that power parent. So they were all singly connected. We'll talk a little bit about what's happening in Leopard and how that's new, but I wanted to introduce you to that in just a little bit. Now, in our old model, Power Management Tiger and before, we had no defined ordering among USB devices.
All of those power children were there. When notifications went out, the notifications went in whatever random order they happened to get distributed in. We know that hubs are actually involved in the power management. Because a hub is the thing that suspends the port. So it knows whether an individual device is in a low power state or not. But it wasn't involved in the power management. Not specifically.
So the USB controller basically operated on two states. It had an off state, or zero, and a 1 state when the controller was running. So really, all of USB was off or all of USB was on. It was possible for an individual device to turn its power off by suspending its port.
But that really didn't involve any of the other power management. We didn't know that there was a device with a suspended port, other than we did the work to suspend did port. So the last thing that was a little different with the -- that you need to be aware of with USB power management, PCI cards, because the PCI bus is generally powered off across sleep, the USB devices couldn't remain on.
So if a USB device is plugged into a PCI card you're not going to see the bus get suspended. You're not going to be able to wake up a sleeping machine. Some PCI cards actually use auxiliary power and are capable of doing that. And if a card is capable, we enable it. But the bulk of them, we can't tell from the card design. There's nothing that declares whether it has that or not.
And so if it doesn't look like it, then at sleep time we unload all of the drivers. And at wake up time we completely reenumerate and rediscover all of the devices in the bus. So that's why plugging in a mass storage device into a PCI card, you sleep a machine and you get that dialogue that says you removed this device unexpectedly. Well, because we powered it off and unloaded the driver for it.
So under the old model of when the system was powered on, here's all the hardware. Everything was just turned on. And when the system went to sleep, the sleep request came in. This was the same power management call. Set Power State came into the USB controller. And you would just issue a global suspend. Which suspends all the down stream ports at the same time, and causes all of the down stream hardware to suspend at exactly the same time.
From the I/O power tree what this looked like is we sent all of our children the message that said we're going to sleep. All at once, unordered. Just hoped it all worked out. Now hardware wake up worked like this. When the user presses a key, you see that we've got the bus all in the suspended state. When the user presses a key on the mouse that actually causes a resume signal to go up stream to the hub and the keyboard.
The hub comes alive and sends a resume signal up stream to the host. The host controller, when it gets the resume signal, actually, it's still in a suspended state. But it has the capability of generating a PCI power management event, or PME. So it generates this PME event, which goes over to the power manager. The power manager actually says, oh, we've got something that wants to wake up the system. Let's go ahead and turn the clocks on, get memory going, wake the CPU up.
All of those things start to happen. The power management code runs again, and now it sends the System Wake Up message to the USB controller. So you see two of our devices are already powered on, but now the system wake up message comes on and we did a global resume and all the rest of the devices came on.
Since -- since from a software driver model, the I/O power tree, you don't have a notion, you don't see the event that caused the wake up. All the devices are still in the suspended state. And when the message comes in to do System Wake Up, we do a global resume. We essentially send the message to all of the children to set their power state to running, and there they are.
Now with Leopard, we knew that we needed a hub-centric model. One reason for this is that sleep wake on USB actually according to an errata that came with the USB spec says for high speed hubs we need to actually sleep the ports before we sleep the parents. The result of not doing this is that there's a race condition where the device down stream transitions to full speed.
Which is what you do when you are suspending before the hub transitions. And it's possible for the hub to think a device disconnects. So you may have seen this message when you plug in some mass storage devices into a high speed hub and you go to sleep, and you occasionally get the system wakes back up right away.
The reason it wakes back up right away is that the hub thinks the device disconnected. And it starts to report that. But then it says, oh, the device is still here So sometimes you get a device was disconnected unexpectedly, and sometimes the system just wakes itself back up right away. And we notice the device fast enough to not notice that it disconnected. So this is going to solve that problem.
So now we're going to make hubs be the parent in the I/O parent tree. And we've defined our hubs, and we encourage other USB devices to use five power states when their USB device is participating in power management. The top one there is IO U S -- IO PM power on. That's the on and running state. The next two states both represent when the USB bus is suspended. The IO PM low power state, that's when the bus is suspended just for an individual device. IO PM sleep is when the whole system is asleep.
The reason we distinguish between that is that a device might go into the I'm not active, and I want to go into the low power state while the system operating. And we can still have the overall system go into sleep. And when we restore from sleep into running, we know not to mess with the devices that were already in low power state. I am going to show how that operates in a minute.
Finally, we created two different states for the off condition. Because the controller is receiving the messages that the system is shutting down or restarting. And we participated in using the new APIs that Ethan talked about. We, then, turn around and tell our children that we are putting them in one of two off states.
Either the IO PM restart state, or the off state. Which actually doesn't have a symbol. We just send a zero. So this is what we mean when we say that USB drivers don't need to participate in the new API. They're going to get through the Set Power State all the information that we're shutting down or restarting.
So low power state devices can use the idle timer. You know, the activity tickle. Or some other mechanism to determine when they might be able to drop into the low power state. For instance, a printer driver might say if I don't have a client currently attached to me and I'm not currently streaming data to that, I know that I can be in my low power state. I don't need to use the activity. I know that the open and closed call are sufficient for me to know that now I can enter the low power state.
So whenever it's in the low power state, the power driver for that device should suspend it. And we've always had the call suspend device, and that effectively tells the hub that that port is connected to into the suspend state. But now because the hub is participating in power management, it knows what that means. Because you've suspended a port, the hubs can say, oh, when all of my children are suspended I can go and put myself in a low power state and the hub driver itself can suspend its parent support.
So it just works its way right up the tree. And in fact when the entire USB controller finds that all of its devices, all of its ports are suspended, we can actually suspend the whole controller, and stop the controller from accessing memory, resulting in further power savings. So let's take a look how this works within the new system. So here's a running system. And you'll notice that Bluetooth, because it didn't have any devices currently pairs has already suspended its controller.
So the audio device determines that its not doing anything with its audio head set right now. So it goes ahead and suspends its device. And the hub says I don't have any children attached right now. They're all suspended. So I will go ahead and suspend myself. So at this point we have three of our USB devices that are drawing, that are in the lowest power state possible while the system's on.
Now at this point, what if you plug in a device? Well, the hub when you plug in a device like that supplies power to the device. The low amount of configuration power. But, it then generates a resume signal and says I need to wake myself -- I need to wake my parent up so that I can communicate with it. Now that that port resumed, the hub driver will notice that device is attached and the distal mount on the desktop and all that stuff.
So what happens when it comes time to transition the system to sleep? The sleep command Set Power State call into our USB controller comes in. And we start -- well, what actually happens is the power manager goes to all the children in the IO power tree and starts to suspend those by doing their Set Power State. In response to a Set Power State, a driver called suspend device -- here you go. It suspends the device. Then we go to the next parents and we suspend those. And finally, the controller gets its suspend.
Now at wake up time, the hardware wake up is the same. User presses a key, it generates the resumes up stream, the power management then happens over to the power manager chip, wakes up the CPU, the CPU power management software runs and System Wake Up is called. Now that System Wake Up is called, we wake up the controller first, the controller then goes down and wakes up just the hub.
But you notice we didn't wake up the Bluetooth device, because we knew that it was in a power state that wasn't system sleeping, we can avoid waking him up, doing any other communication there. And we would resume the other device that was down stream there, the mass storage. So the audio device and the Bluetooth still remain in the low powered state.
Now the IO power tree -- so now I've got my circles representing drivers here. The IO power tree shows that a couple of those drivers are in the low power state already when the system's running. And a system sleep comes in. And we follow exactly the same model. We start with turning off the leaf nodes, the children. By the way, you'll notice that in this model, I didn't mention it before but the keyboard, I split it off into two devices.
Because the keyboard actually is a keyboard device and a hub device. There's two USB devices inside of there. So it gets two circles in the driver. One circle in the physical hardware. So once we've done the leaf nodes, then the parents of those get suspended. And finally the controller. And that's what puts the whole system to sleep.
At system wake up time, at System Wake Up time we start by waking up the controller. After the controller, the next thing down is the children of the controller. And then finally, those -- the children of the hubs get woken up. And so the running system is back again with two of our devices still in the low power state and the rest of the devices on.
Now shutdown and restart, because we're turning the whole USB tree off for shutdown and restart, it means that we're going to do the Change Power State -- pardon me -- the Set Power State function, we're going to be calling you with either setting your state to zero or to the KIO PM restart. So you can use that instead of the new I/O Kit API for USB drivers. Now what do we need you to do? We need you to do your part to save power.
Start by changing your drivers to use the new USB power states. When transitioning your driver to -- when transitioning your driver to the low power state you need to make sure that you call suspend device. Because that's what actually notifies the hubs that something is actually happening to the children.
And finally, you need to transition to the low power state whenever the device is inactive. You can use open close calls from a user client, if you can do it when you don't have activity going to the device, every bit that you can suspend the device saves power. And it all adds minutes of time to a PowerBook, or MacBook Pro. Tools for debugging. This is actually something kind of new. New with Leopard is FireWire K Print F built into the kernel.
If you ever used FireWire K Print F it was distributed previously as part of the FireWire SDK, and it was a special version of FireWire that gave kernel Print F from drivers and read them from another machine connected via FireWire. You had a special version of FireWire, when you ran that special version of FireWire unfortunately all you could do was K Print F Logging. You couldn't connect your FireWire devices and use that. So it was kind of an either or.
Are you going to do debugging with FireWire or are you going to use FireWire. Now they've built it so that FireWire is active all the time. And until the -- until either debug flags are enabled, enabling K Print F in the first place, and a user client connects.
Until those thing happens FireWire works normally. You can use devices and all of that. But when you suddenly need to debug something, connect up with FireWire K Print F Viewer, and all of a sudden your FireWire devices are going to disconnect. But FireWire K Print F starts working exactly at that moment. You can then put a machine to sleep if you're turned on flags enabling power management logs you can look at those.
FireWire K Print F has turned out to be extremely useful for debugging power management because FireWire remains active up until the very last moment that the machine goes off. So even though the other things may be turned off, the display may be off, you know, it just may not be possible to do other communications. FireWire with its direct memory access keeps going all the time.
So to use this, you have to turn on the kernel K Print Fs. And right here I have an example of the command line you would do, where you do a pseudo N V ram, and you set the boot-args. The key is that that debug equals 8. It's that bit right there that says turn on kernel K Print F.
And then there's argument there that says IO equals 80 Hex. And the 80 Hex is the bit that turns on power management messages. I'm going to show a little example of decoding a couple of those power management messages. If you're starting to do your driver that participates in this power management, you want to know when your Set Power State is being called, you want to know what it's being changed to, you want to know what your parent is -- these are the logs that help you figure that stuff out.
Oh, the last thing is the FireWire K print Fs viewer which is the necessary piece for this is available in the FireWire SDK 24, which just became available, like, yesterday. So it's available for you now. You can download that thing and have its command line tool that you run in a Terminal window. And finds the machines connected via FireWire and starts getting their log messages right away. So take it for a spin on your Leopard machines.
Now the messages that you get out when you have the power management locking enabled, with the I/O equals 80, they're these cryptic things which look like this top line up here, which -- it's got a time stamp on it, it's got a few other fields. Finally, over there, you see Apple USB EHCI. Well, that happens to be one of the -- that happens to be a power driver. And that's the EHCI's power driver. And the first thing you do is you look for your class name right there.
The second thing is you look for the number just to the right of that. And we know that number 38 is the settle power state call. And the next number is the instance of Apple USB EHCI. And the number 2 is the actual state change. And that is the index into the table of power states that you have. So this is a case where EHCI is being asked to change the state to.
And then on the second line you see us decoding one where it says minus 38. Minus 38 indicates that the Set Power State call has returned. There's our incidence again. So it's the same EHCI driver. And the zero is the return value. So because it returns a zero, that says that the Set Power State was completed. If you return a non zero value, that says that this is an asynchronous call. And at that point you have to look for the completion call. And I'm going to show you what that message is right here.
So the -- where will you find a list of what those numbers mean? I went to actually answer that question so that I could hopefully just point to you and say here's the definition out of the header file. And what I found is we have a header file that defines these messages. It's available in the Darwin open source.
But the defines don't necessarily give you much of a clue as to what they are. So I went back to our engineers who sit down and do this stuff day in and day out and said, which ones do you use. And they said here are the magic numbers. This is what's written on their little notes next to the computer monitor. 38 and minus 38 are the Set Power State as I just covered. 39 is the power state will change to call.
40 is the power state did change call. So one is before it happens, an the other is after it has happened. And then finally, 16 is that asynchronous Set Power State completion. So in the previous example when you saw the minus 38, if that had returned a non zero number there on the right-hand side, then you would then see a call later with the EHCI driver and a 16, and you would see what the return value was at that time. Okay. So for more information Craig Keithley is our I/O Technology Evangelist. There's his e-mail address. And we've got things that are up on the attendee Web site so you can go there and download the latest power management chapter. Take a look.