Thane: So I'm Thane Norton.
I'm with the I/O Kit Team.
And I want to talk to you a little bit about designing and debugging device drivers on OS X.
What I'm going to talk about today is how you can drive hardware from user space or kernel space, the kinds of drivers that have to be in the kernel.
And some ways you can debug kernel level code, and some of the special challenges that are involved in doing your own I/O Kit user client.
So what is I/O Kit?
I/O Kit is the set of frameworks that Apple uses for driving hardware.
There's a piece in the kernel and it percolates up into user space.
Not only is it the device driver model, but it's also a framework that applications can use to drive hardware.
Now I/O Kit is only available on OS X.
It is not available for the iPhone.
If you want to know how to drive devices on the iPhone, you want to go watch the Developing Apps That Work with iPhone Accessories session that happened earlier today.
So the best possible place for you to support hardware is in your application in user space.
If you just need to drive hardware from your particular application, you can just link against the I/O Kit libraries, the I/O Kit framework and build the support straight into your application.
This gives you the benefit of being able to do a drag-and-drop install and not having to have a special installer.
And even if you have multiple applications that share the hardware, I/O Kit can arbitrate that sharing for you, and you don't have to worry about all the nitty details.
Now, if you have multiple applications that need to share the same device support code, then you're probably going to want to create some kind of framework.
You can still build that into your application, letting you have the drag-and-drop install by putting it in the resource folder of your application, otherwise you're going to need some kind of installer to put it in the right place, so all of the applications can use it.
The last way to support hardware from user space is when you need to do some kind of services, moving the cursor, generating keyboard events, or other services to the system, you need to have some kind of background application.
Launchd is your friend.
It is a utility that can be used to create launch-on-demand applications that anybody can connect to.
It's very well documented in the man pages, such as launchd.plist, and you want to go to the Launch-on-Demand session, which I'm pretty sure hasn't happened yet.
Now what being in user space buys you is your device support will be a lot easier to debug.
Not only will it be easier to debug, when you have bugs your application will be more robust.
If your application exits suddenly, the user can relaunch it or the background service can be relaunched.
If your kernel driver exits unexpectedly, the user's going to reboot and they're going to lose whatever they were working on.
You also have a lot more access to system services.
You can choose to use Objective-C, which you cannot do in the kernel.
You have access to better logging facilities, such as the ASL log system.
You can create your own log file and log your messages out to that.
And you should not be able to cause panics.
This is not to say that you won't, but if you do you're going to want to log a bug against it and then try and work around it.
Now from user space,- you can get nearly full access to any I/O Kit driven hardware.
Almost any USB device can be supported.
You get much better memory management.
You can actually page memory in and out.
You don't have to worry about your memory all being wired down.
And one common misconception is that kernel threads get special treatment when it comes to thread scheduling.
That is untrue.
At a given priority, kernel threads and user space threads get the same scheduling.
So that doesn't; being user space versus kernel space does not buy you anything in terms of priority of access.
And you end up with a testing matrix that is very similar to any other application.
You do some testing on both processors on all the versions of the OS that you support.
When I say all the versions of the OS you support, I would highly recommend only supporting the most recent revision.
Have your users update to whatever the latest revision is.
It collapses your testing matrix significantly.
Now you can't drive hardware from user space if the hardware is supplying services to someone in the kernel; for example, if you are writing a file system driver.
If you require access to other kernel resources that are not published through I/O Kit, you're going to have to be in the kernel to get those.
And if you need to respond directly to primary interrupts, that is to say, if you are a PCI driver you're going to have to be in the kernel.
There's just no other way to handle it.
If you have to be in the kernel, you're going to need to write a kext.
Even if you're just thinking about writing a kext, if you've already written a kext and you haven't done this already, go read the Kernel Extension Programming Topics.
It has a lot of very good walkthroughs.
Going through that over the course of a day, you can get a very good workflow for building your kext, installing it on your test machine, testing it, debugging it.
It's an excellent set of tutorials.
All memory that you allocate in a kext is, by default, wired.
What that means is if you had a memory leak in your driver in the kernel, you're going to take the user system down just by depriving other applications of memory.
Memory from user space is not wired.
As I was saying, user space applications can page.
But, since the driver, since kexts, expect memory to be wired, you have to, before you do any direct I/O on memory passed in from user space, you have to make sure that it's wired down and then unwire it after the operation completes.
When you're in the kernel, logging is very limited.
Most of the system logs use some kind of ring buffer.
Which means to you, that if you try and log a lot of messages, you're going to overflow the buffer, the messages are going to get garbled, things will be dropped, you're not going to see what you expect to see.
You can't use ASL, which is a very nice logging system.
Now you can use kprintf to do FireWire logging.
This is not a solution that you can deploy.
This is something that is very handy to use in a test setup, so that you get all of the message coming, the messages coming out of your driver.
If you want to learn how to do that, the place to look is the man page for fwkpfv, which is the FireWire kprintf something.
Your test cycle's going to be longer.
Often it will require a reboot, especially when you encounter a bug, because you'll have to be rebooting your system.
It requires advance preparation.
You need to have two machines.
That's going to be your best debug solution.
You're going to connect them either through Ethernet or through FireWire.
Ethernet tends to be more convenient, because all your machines are hooked up all ready.
FireWire is available earlier in the boot time, so it just depends on what kind of environment you need.
Additionally, you can download the kernel debug kit for the specific kernel that you're running on.
And that will give you the ability to step through Apple code as your driver uses it.
So you can see what's going on and who is expecting that pointer to be not null.
Again, read the Kernel Extension Programming Topics.
This will show you how to set up a two-machine environment.
If you wanted to use FireWire, another FireWire utility, fwkdp, very handy for getting FireWire up and running.
You must test your kext on every supported kernel, every release.
I tell you from experience, it is very easy to build a kext that will not run because you linked against something that isn't there.
Your kext also must match the kernel architecture that you're running on.
You don't get to choose if you're going to run 64-bit or 32-bit.
If it's a 32-bit kernel, you run 32-bit.
If it's 64-bit, you run 64-bit.
So this expands your testing matrix slightly.
Each of these tests is going to be a little more involved as you're testing to make sure that your kexts runs on the various kernels proper.
One of the problems you can run into is that various functions have changed, for example, memory descriptors.
They had to change in 10.5 to support x86 user processes, or 64-bit user processes.
The kernel was still 32-bit, and so we had to deal with the memory address translations.
To do that, you have to use conditional compilations and availability macros.
Weak linking doesn't really exist in the kernel for all intents and purposes.
Now when you're deploying a kext, one way you can support multiple platforms is by having multiple kexts nested inside of one package.
Dean will talk about this a little more later, but it can make things very easy for the system to find the proper kext.
You can fairly easily support all Leopard or better kernels with one kext.
You can support earlier kernels.
And if you want to do that, you're going to want to go back and look at last years Creating I/O Kit Drivers for Multiple Architectures and OS Versions.
They have a very detailed overview of how you have to link them all together and munge them so that they work.
When you're working in the kernel you have to deal with panics.
Panics are even harder to debug than your regular kernel environment.
You've got a static slice of the operating system.
You can poke around, you can look around, but it's sort of like CSI, you're trying to figure out who killed you.
Again, two machine works well if you already have it set up.
Once the panics happen, too late.
One thing that can be very handy is having your system dump core.
What this means is, it, you can set it up so that it will write out the kernel memory to a core file that you can then look at later, or at a different location.
So, anyhow, if you have a panic that happens infrequently, you can set up a bunch of test machines and when they crash, they can dump core and you can take a look at them.
If you want to know how to set up a kernel system for dumping core, you want to see Tech Note 2118`.
That will show you how to set up an Ethernet core dump.
And again, fwkdp is how you can dump core over FireWire.
All of the panic debugging is covered in Tech Note 2063.
It's a very good place to look to figure out what went wrong.
And it is another one of those things I would highly recommend that anybody working in the kernel reads.
So why do you work in the kernel?
For whatever reason you need to have closer access to hardware.
You need kernel resources.
The kernel, being in the kernel gets you that special access.
It's more challenging than user space.
I'm sure that's not a surprise to anybody here.
It opens up, you up to a whole new class of defects, panics, which can deprive your user of the use of their system.
And you get much more limited access to system resources.
You can't hit the hard drive, for example, and access config files.
If you need a custom interface for crossing the user kernel boundary, you may need to write your own custom user client.
This is even harder to debug than a kext, because you've got two separate processes in two separate memory spaces with two separate debuggers attached to them, and figuring out who's calling whom can be very confusing.
There is almost always a better choice.
I would highly recommend that you not do this.
Code running in the kernel is inherently trusted.
So if you create, the reason you create an I/O User Client is to cross that trust boundary.
If you make your own user client, you become the gatekeeper.
What that means is, you have to validate everything.
Any data that comes in from user space, you have to check to make sure that it makes sense.
Any pointers that you pass out, you cannot trust them to be the same pointer that comes back in.
Even if just a connect, an application connecting to your user client, if that could elevate privileges or affect another user task, you need to verify that the connecting application has the right to access your user client.
If you want to know how to do any of this, the SimpleUserClient and the AppleSamplePCI driver are both very good examples.
And this is another big reason you don't want to do it; your test matrix explodes.
You have to test all the various architectures of user clients on all the various architectures of kernels, and it just becomes a testing nightmare.
You can remove Rosetta support, but this only helps a little bit.
It's not a big win.
And now for something completely different.
I've been asked by members of the team to give a couple of public service announcements.
If you're doing a PCI driver, you want to try and use Message-Signaled Interrupts.
They are preferred, because there is less interrupt sharing and it allows us to demux the interrupts, so that only one driver gets called.
The way you enable MSI is by supplying an index that is greater than 1 to your I/O interrupt event source.
When you do that, you don't need to supply a filter.
So you can use the root class I/O interrupt event source, interrupt event source.
If you enable MSI, you disable the standard interrupts.
If you've set them up, don't expect them to be called.
This is supported on all Intel hardware.
So as long, if you're still supporting Power PC, you're going to have to still do some filtered interrupt support.
Power Management: If you're in user space, better performance equals better battery life.
Periodic activity is worse than batching your activity.
If you're constantly pinging the hard drive, it's going to keep it from spinning down; it's going to use more power.
If you can do all of your access and then let it go to sleep, this is going to be better for your users.
Another tool you have available to you is the System Load Advisory API.
Now this is as it might sound, an advisory API to let you know what kind of power save is the user in?
Is this a good time to do background tasks?
Is this a bad time?
Is it kind of OK?
Some users, the way they use their system, it never is a good time to do background tasks.
So you want to use this to guide your behavior, but you're going to want to have some kind of time out, so that, you know, OK, I've waited long enough, I've got to just go ahead and do it.
If you need to know about wake and sleep, the IO Kit.framework lets you subscribe to the system power messages.
If you need to prevent the system from going to sleep, you want to use the IOPMAssertion APIs.
They can set it so that your screen won't go to sleep, for example, if your users watching a movie.
Or that the system won't go to sleep, if the users listening to music, the screen will still darken, the music will still play.
And for those of you who know about SafeSleep, this is what happens when the system runs out of battery when it's already asleep.
You should not have to do anything different.
It should look just the same to you: the system went to sleep, it woke back up, the hardware was turned off, it got turned back on.
There shouldn't be anything special that happens.
If it looks like there's something special, there's probably something wrong.
Now Power Management's slightly different in the kext.
Since any sleep can become SafeSleep, in the kernel, you again, should not have to do anything different.
It should look just the same to you.
You can use IOService APIs to join the power tree so that you can be notified of Power Management state changes.
Most kexts don't need to know that, so they're not part of that tree.
It's important that your kext, anything in your kext, only implements the mechanism.
You do not want to hard code policy into your kext.
Have a user space daemon that pushes information to the kext and lets it know what the policy should be.
You'll have some default policy in your kext, but you definitely want to be pushing policy from user space.
You also may have noticed that in Snow Leopard we introduced something called maintenance wake.
This was added for Bonjour sleep proxy.
So your system could go to sleep and still maintain system resources, or network resources, available on the web.
Sleep Proxy, the Maintenance Wake is a brief wake with the screen and audio off.
It will not last more than 30 seconds.
If you try and do something that takes longer than that, you're just not going to get to.
And it's only, again, it's only triggered by Bonjour sleep proxy being active.
And with that, I will hand it off to Dean.
I'm going to talk to you a little bit about taking your driver sort of the next step.
You've got it written.
It's working in your lab.
But how do you take it from your prototype all the way to being a product?
What do you need to do to harden it and prepare it?
And also, what resources Apple has to help you if you get stuck along the way.
So how to qualify a driver is an interesting question.
And most engineers have a pretty good intuitive sense of things that they need to test, because they know what the challenges were when they were with the driver.
But there's a lot of basic correctness tests that often get overlooked, because they seem very basic.
But I work with a lot of developers and I see a lot of kernel extensions that have been shipped with some pretty silly common mistakes.
And as soon as we point them out to the developer, it's like, oh yeah, of course, I need to fix that.
But I'm going to go through kind of a laundry list of things that you might want to look at before you even consider putting a driver into full QA.
And also I recommend keeping records of a lot of these results between releases, because we've found it's actually valuable to compare from release to release how we're doing, particularly with Power Management and with general performance.
It can be very instructive, and you can start to notice trends, and particularly if something steps out of line.
So first on the sort of easy checks is, look at the Info.plist.
This is an XML file inside your kext bundle that is sort of used by the kext management system to know under what conditions to load your kernel extension, how to load it, what it depends on, and so on.
But there's a few particular properties I want to call your attention to.
This is a property you can add to your personalities in your plist, to turn on some additional logging messages in the IOKit system.
And its value is the decimal number; I believe it's from zero to 65535.
Well you need to either make sure that it's been absent or set to zero when you ship your kext, because you don't want these additional messages clogging up your users logs.
And it's slowing down their system, because it has to write these out to the disk at some point.
Did you advance your version number?
This is important, because it's one of two properties that the kext system uses to uniquely identify your kernel extension.
If you have two different versions of your kext on the system, this is how the computer can differentiate between them and load the newest one.
It's also handy for support, when somebody calls in with an issue you'll know exactly what they're running.
In the CFBundleIdentifier is the other property used to uniquely identify your kernel extension to the system.
Make sure it's correctly formed.
Make sure that you're using a reverse DNS style identifier, com.yourcompanynamehere.driver.whatever.
We don't want to see a bunch of kexts out there with their CFBundleIdentifier being com.mydriver, or something like that from one of the examples.
Because, again, if these collide, the kext management system doesn't know that they're different kexts, it assumes that they're the same.
Two additional properties that have been misused over the years, OSBundleCompatibleVersion.
This is perhaps confusingly named.
This is what tells the kext management system that the kext is a library kext.
It is describing the lower bound of a version range that that text is binary compatible with.
If it's presenting and interface vessel or lower bound to the range.
The actual CFBundleVersion being the upper bound.
But if your kext is not a libary kext, and most of you probably are not making library kext, then you do not need this property.
Having it in there means the system will keep around additional information assuming it's going to need the link.
Use that information for linking later.
So make sure that property is absent unless you know you need it, because you're a library.
And then also the OSBundleRequired property.
This is used to determine if the booter has to load your driver, or if it can be left later for the kernel.
The only reason that the booter has to load the driver is if it's necessary in order to go about mounting the root file system, so that other drivers can be found.
So most of your drivers probably don't need to have the OSBundleRequired property, either.
But if you've kind of developed your driver by cutting and pasting from some other drivers you might have kind of absorbed these properties along the way and you want to review their use.
Run Find on your kext and look at every file that's in there.
There's really only two files that have to be there: there's the Info.plist and then the binary that actually gets loaded into the kernels.
You should be able to account for every file that's in the bundle.
I've seen kernel extensions ship with header files in them.
That their build process somehow copied in there.
I've seen lots of stuff in there, a GDB debug sessions files left in there.
Yeah, go through and do some hygiene there and make sure those files are all removed if they don't need to be there.
And of course, ownership and permissions, you kext won't even load if these are wrong.
But this is a good opportunity to make sure they're owned by root, group is wheel, and they're set up so they can't be modified by any other user.
Kextutil-tn is a great tool to help you find, sort of structural problems with your kext.
Any kind of an issue that, you know, maybe would be fatal, maybe even not fatal, maybe it's just a warning.
But it does; the t means test the kext, perform the strictest test that it can.
And n means don't actually load it.
So this is just doing all the proofing that it would do before it loads the kext.
So that's kextutil on Snow Leopard and later.
Prior to Snow Leopard, that's kextload.
In Snow Leopard we split out the developer tool into kextutil.
We also have a tool called kextlibs.
And this is a great way to find out what your dependencies ought to be.
If you don't know exactly what other library kext you should be linking on, the kextlibs tool will actually even give you the little XML blurb that you can copy and past right into your plist to make sure you got your dependencies right.
So we would hope you'd use that to make sure your dependencies are as tight as they can be.
Now the binary inside the bundle is the PC gets loaded into the kernel.
And, but it also contains a lot of symbolic information.
Obviously we have to link that into the kernel, so you got to have all your undefined symbols defined there.
And if you're a library you have to have your exported symbols there as well.
But you want to make sure that that was built with the release configuration of Xcode.
Because if you have it set to debug, you're going to get a lot of debug symbols.
You're going to get like ten times as large a symbol table as you would actually need.
So the binary gets very large.
And you're actually leaking a lot of information about the structure of your code.
You're also going to want to verify that your architectures are correct.
Make sure that every architecture you need is present, and that none that you don't need are present.
So there's three that you would encounter in this development space: i386 for 32-bit Intel, x86_64 for 64-bit Intel, and ppc for 32-bit par PC.
You should also run nm on the kernel.
Nm is the, on the kext, nm is the utility that dumps all the symbols in the symbol table.
And there's a variety of options and other things you can do.
I've given you a line here that runs it through a filter to convert the C++ mangled names into human readable names.
And then removes all of the undefined symbols.
So what you're going to be left with here is a list of symbols that your kext defines.
Make sure that they're named correctly.
You really want all your global symbols to have a prefix that uniquely identifies them to your kext.
Ideally the reverse DNS that matches your CFBundleIdentifier, but with the periods replaced with under bars.
And the reason for this is the kernel uses a single, flat name space.
All the kexts, when they link, link against all their libraries, and those all link against the kernel.
If you have any symbol collision along the way, it won't load your kernel extension.
So if you have a function called qsort and then a version of our kernel Apps qsort, which I think we actually view now, your kext will not load, because you have duplicate symbols.
So you want to make sure that your global names are all well qualified.
OK, so far we've just been looking at the kext passively.
Now we actually want to try loading it, and here's some things you can do.
Watch the system log and kernel logs while you're loading your kernel extension.
Look for any warnings, or errors, or any other kind of messages that come out that seem scary, and go chase those down.
Figure out why they're there.
The messages that we spit out are usually meaningful.
They usually are important.
And if you're having trouble understanding what they mean, the various mail lists that our own lists can usually help shine a light.
Also, unload your kext.
I recommend getting this working very early in your development cycle, and here's why.
When you're developing the kernel, you want to be able to load your kext, try something out, unload your kext, make a few changes, reload.
You know, hopefully you won't panic every time and have to reboot the computer.
So some of the time unload can save you, can actually make your development cycle much more rapid.
But it's also important to make unload work, because it really helps ensure that you've got a lot of your references right.
You're not leaking references to your objects.
You're not leaving dangling objects around.
So if unload won't work, that probably means that either somebody is holding a reference to one of your objects or you've leaked a instance of an object and we won't unload you.
Also, you know, while you're doing this, make sure that the system sleeps and wakes correctly while your kext is loaded.
And make sure your driver will unload after the device has gone away.
If you unplug your device after about a minute, your driver should automatically unload.
And also try Safe Boot, that's where you boot holding down the Shift key.
This bypasses the kernel caches, the kext caches, and actually tells the system to rebuild them.
But that has the booter load the drivers individually as opposed to a cache.
And this gives you a way of testing a few more configurations that your users will encounter under some circumstances.
Now cycling is a really powerful tool.
This is something we use pretty extensively at Apple and we find a lot of things.
This helps us harden the code quite a bit.
But it's not just about repeating a task over and over again, it's about watching the impact of that task on the system.
If you load and unload your kext one time, it's unlikely that you're going to notice any leaked memory, because it's probably not a lot of memory.
But if you load it and unload it 1,000 times, you can see a pattern.
So we have some tools like ioclasscount, ioalloccount, zprint, and top that all monitor various things around the system.
And if you can cycle some of these activities, then you can watch for trends.
You can look for, you know, some particular zone of memory blowing up, and realize, OK, maybe I am leaking some resource here.
These are important things to fix.
As Thane pointed out, kernel memory allocated by kext is, by default, wired.
And so that's memory that if it gets leaked, the only way to recover that memory is to reboot the computer.
It's gone as far as the kernel is considered, as concerned.
So take leaks like that very seriously please.
And of course, you know, I've listed a few things you can cycle here: sleep, wake, attach, detach.
But your product, obviously, is going to have some very common operations.
Cycle those as well.
We give you a tool in the developer's tools called SleepX that will allow you to do sleep cycling.
So that is actually a very powerful tool for checking that transition.
And set a goal.
I mean this is pretty basic test methodology, right?
We usually try to start at 1,000.
Sometimes some of our goals are up over 10,000 cycles.
It really just depends on how long it takes to get through a cycle of something.
But this is another area to keep records.
You know, how many thousands of cycles can this go, and let it go over the weekend, and helps you see if your quality is improving.
Okay, so you've hammered out your kext.
You've tested it.
You've got it hardened by cycling, and now you're ready to put it into your users hands.
What do you need to do to do that?
Well we have a tool called Package Maker that will create a .pkg file that the Apple Installer knows about.
And it automatically does all the right things to install a kext, right?
So if you don't want to have to worry about setting owners and permissions correctly, you know, you don't want to deal with touching the extensions folder, all of those other things that you might have seen on Apple Tech Notes.
The Package Maker will generate a package that does all the right things for you.
And as it turns out there's a nice walkthrough that describes exactly how to go about doing this in the Packaging a Kernel Extension for Distribution and Installation.
It's a very straightforward title.
It says exactly what it's about.
But it walks you through packaging up an example kext.
Now, what's actually going on behind the scenes here is that your kext is being copied into system library extensions, which is the folder for auto loaded kernel extensions.
Please do not install kext in library extensions.
There have been a few discussions on the mail lists about, you know, why doesn't Apple use library extensions, because it should, because other file system domains include libraries as opposed to just system library.
And this is a decision that was made early on.
We've revisited it a few times.
But we want to keep library extensions for future use.
We think we might want to use it in the future.
But if you're installing kernel extensions there now, that limits how we could use it in the future.
Plus, there's no reason to install them there now, because it doesn't actually mean anything.
It's just a folder.
So put them in system library extensions if you want them to auto load.
If they're tied to an application, if you have a kernel extension that really is only there in support of a specific application, then you can put the kext inside the app.
It can be inside its resources, or plug-ins folder, and the app can load it programmatically by running kext load.
Thane had mentioned earlier that you can nest kernel extensions, and the reason you might want to do that is to have one top-level kext with a family of supporting kexts.
We will support up to one level of nesting for kernel extensions.
So inside the plug-ins folder of a kext you can have as many kexts as you need for your suite of drivers, and deliver them as if they were one kext.
It's actually pretty handy if you, say, have an older version of the kernel extension that's supported PPC hardware, and you don't want to re-QA it and redevelop it.
You can just shift that as a subkext of your main kext or new shiny Intel 64-bit kernel extension.
And that, the subkext will be used on the 64-bit, or excuse me, on PAR PC systems, and the main one will be used on Intel 64 systems.
The talk, last years talk that Thane referenced earlier will describe exactly the ins and outs of how to make all that work.
After you've installed a kernel extension, or modified one, or removed one, you need to touch the extensions folder.
This changes its modification date and allows the caching system to know that it's time to regenerate the caches.
You shouldn't directly manage the caches.
The caches for every release of MAC OS X have changed.
We've constantly been refining them and it's difficult for you to try to manage them, because you have to do something different on every release.
You should not need to.
If you encounter a situation where you really do need to manage the caches to get your product to work correctly, please file a bug that would be a bug on us.
Because the caches should always reflect what's in the extensions folder.
Assuming you've honored the contract of touching system library extensions.
Now if you want to have a kext immediately available for use without requiring a reboot, there's a tech note for that, a Technical Q&A 1319.
What it boils down to is you want to send the SIGHUP to kext D.
And the tech note, or the Technical Q&A describes exactly under what OS releases you can do that, and how you go about finding its process ID, and, and, it's pretty straightforward though.
Now if you can't use Package Maker, if you need to install your kext through some other installation utility for whatever reason, you can certainly do that.
But there's a few things you need to make sure of.
First off, make sure that the installed version of your kext exactly matches what you built.
I've seen installers that modify kernel, or modify files that get installed they send them, because they think they need, don't need all the binaries, or they change the permissions in odd ways.
You should go and make sure that not only the data, but the meta data, the, the ownership and permissions and ACLs, [phonetic] and extended attributes, and anything else on those files are correct.
And also make sure that it does touch the extensions folder to update the mod date.
And there's a common trap here that I'll warn you about.
The first time you install a kext, that effectively creates a new subdirectory in the extensions folder that guarantees the mod date of the extensions folder gets updated.
But when you reinstall that kext, it's just overlaying the same files.
The folder, the .kext folder that was created during the first install doesn't get reinstalled, right?
It's already there.
So the extensions folder mod date doesn't change in that case.
So that's why you want to make sure that the installer works after an upgrade as well.
The second time after the kext is already present, you want to make sure it's still touching the extensions folder, so the caching can take over.
And you also want to make sure that if you are doing an upgrade install that if you have any old resources or old files from your previous kext, until they get removed, obviously you don't want anything bleeding through from a previous version, because that can lead to who knows what.
OK, if you get stuck along the way, if you need some help, there's a large variety of resources available in the Apple Developer Community.
And I'm going to start you off at the Hardware and Drivers page off of developer.apple.com.
This is probably going to be your hub for doing driver development.
Pretty much all the resources that Thane and I have talked about today are referenced through there.
There are, there are developer forums, developer.apple.com/devforums, and they haven't been used extensively for device support to date.
We do have a forum on there for 64-bit migration, and it is suitable and appropriate to talk about 64-bit kernel issues there.
There's certainly the mail lists that are pretty common, the darwin mail lists: darwin-kernel, darwin-drivers, and development that'll be suitable for any of these topics.
And then there's application or domain specific ones like USB, FireWire, ata-scsi-dev, where you can ask questions about those specific areas.
And of course, at any point along the way, if you think that something is not behaving correctly, or not behaving as documented, please file a bug report.
This is how we know what we need to do.
This is important communication.
I know it feels sometimes like a one-way street where you file a bug and you never hear back about it.
But understand that that's a voice that comes in and gets added to a lot of other voices.
And it helps us understand maybe collectively where we should be putting our resources.
So it does help us understand how to focus on, or what to focus on, I should say.
So please don't be shy about filing bug reports if you think you've encountered a defect.
You probably shouldn't be filing bug reports just to get answers, right?
If something isn't working, because you don't quite understand it, that's not the same as something isn't working, you understand it, you're following the directions, and it's just not working.
If you're not sure and you want some one-on-one help, you can always request a DTS Incident.
These are paid support sessions where an Apple engineer will work with you to try to resolve the problem that you're having.
All of these methods have been used to great effect by many of the developers I've worked with.
So please use your community.