WWDC2001 Session 205

Transcript

Kind: captions Language: en good morning welcome to session 205 IO ket PCI drivers and open firmware my name is Mark tosser on desktop technology manager today we're gonna go over a couple areas here with IO kit specifically with the PCI driver development and assistance and also terminal determining how to get into open firmware what to look at open firmware we'll actually have some demos of looking at a couple of PCI cards and actually looking at the open firmware code there so today we'll start off the morning with Wayne flans burg who will give this presentation good morning let's begin we think the session audience should be people that are interested in generic PCIe cards and hardware developers and we think the audience also might include people that are writing drivers for that and hardware testers and just people that are generally interested in low-level PCI stuff and booting so what is a generic PCI device well it doesn't belong to a framework that's the biggest thing is you don't have a FireWire frame framework or a USB framework or any framework at all except IO service which is quite a lot your device is unique to your application nobody's going to try to install their driver or run their application on to your device your device could be a sonar device a radar device something that isn't something that's generic and your application needs to communicate with your device through the driver and has to go through the user space into the kernel space and we'll talk about that later on today also so this session gen agenda is basically we're gonna look in an open forum we're going to boot a device we're gonna boot one computer we're gonna stop in the open firmware user interface and we're gonna look at some devices and we're gonna look at some support nodes that are important to you and then we're going to go and look at the same stuff over again but this time using the IO registry and then we're going to talk about a generic PCI driver and finally we'll have a Q&A session now this URL that's on the bottom developer.apple.com slash event slash HTML excuse me /url s dot HTML was being universal in every session here and the object was to take the urls that we're using today so that you don't have to copy them all down all you have to do is get the one at the bottom of the page and go to them so i'll just mention quickly that the pci web page is basically points to everything so if you ever go there you're gonna find the rest of the world the hardware technical notes contains much stuff dealing with open firmware and the PCI bus some point is extremely important to you so that's the page that it's on and that explains that what you are required to put in your node or what we will put in your node for you and then the darwin open sources project page also so we're gonna start with the open firmware the device tree we're going to look at nodes in there we're going to look at configuration variables configuration variables have some very important and aspects for you that we'd like to talk to you about today and we're going to show you how to in from open firmware user interface using your reg properties how to actually read your configuration space and we're doing this because we want you to be able to get a new computer plug your device in there and make sure before you do anything that your device is recognized and built correctly into the open firm device tree and we're going to mention something about security so the device tree is a block diagram of the motherboard but it's more as I mentioned earlier it has the support nodes in it but it also opened firmware during its building of the device tree goes out and looks at all the PCI slots and if it finds a card in there bills the node for you or allows you to build it and in there you have your your properties your words and if you have children they'll also show up in there your words are only present they're optional if you have a device that is participating in the boot process such as an Ethernet device or display device it also has addresses for your configuration space and your memory and your i/o space and support nodes and in particular we're going to look at three support nodes and that's the alias chosen and the options node this is a block diagram of the target machine we have up here this is one of our latest desktop machines and we're not going to boot it up entirely but when you buy this machine you can get the developer note for that machine off of our web page and in that developer note you can look at this block diagram the reason this is important to you as though many people will come to DTS and say with this last machine my device stopped working what did you change well you don't really have to ask us we're going to try to teach you enough so you can get a reasonably quick look with knowing very little about open firmware and everything else so that you can see what it would have change what what may have changed and start from there so they're hoping to give you some leverage there and we're going to display your node we're using telnet to do that last year we use telnet this year we are last year we didn't use telnet this year we're using telnet and we're going to show you your your whole tree including your node from the Mac os10 host a system that is connected up to it and well like I said earlier will display your words properties and children if you have children and if you have words but you definitely have properties this is from the you are this is from the PCI bus binding to I Tripoli 1275 it's just one section that we took out but it's extremely important and I like to talk about that just for a moment this is difficult to read so I'm not going to go into it in great detail but what you see here is the bits from 0 0 to 31 and you see fizz hi fizz mid and fizz low fizz high is really very very important to you because it is how all the bridge controllers route messages from your virtual memory space and you know on the host bus down through the hierarchy of Asics on your on your bus forgetting these this NP and T thing that are there for a lot of legacy devices and everything else you have a space code which is either configuration space memory space or i/o space but you also have 8 bits for your bus so you can have 256 buses and you can have 32 devices on a bus and you can have 8 functions per device and you can have 256 registers per device so how do we get that message down to you we get it down to you and fizz high and we put that out onto the PCI bus and and the controllers know enough to recognize that this message that's coming down and they got one clock period to do this 30 nanoseconds today I guess so they got one clock period to say that this is not for me or this is for me or it's for my children and if it's for my children it changes the type of message and sends it down through the bridge to the next level so that's how we get there and then fizz mid and fizz low are the 64-bit addresses presently we only have a 32-bit bus but the standard allows for going to 36 of 64 bits and in the future so today you'll see that all the H's the fizz mid is always 0 and now I'm going to ask the Marten to come up and demo using telnet and a host computer what we've done here is we put a machine in open firmware already open from where we're at a pretty low level we don't really have the ability to cut and paste or scroll back up and we don't have much of a way to save any of our data what we've done with this machine is we've used the telnet app on 10 in the terminal program to link back in to the open firmware machine to give us an interface that allows us to save and capture our data so what I'm going to do here is what Wayne was showing on the slide above is I'm going to select the root node of the device that we're looking at and that's the dev is the word that Salette that used is used to select our device and I'll list that and what you can see here is that this is roughly a representation in text of the same hardware block diagram that Wayne was showing before we have children those are the indented text and we'll go down here to where is it right about here is our PCI bridge and we have two cards on this machine and they show up right here and right here we'll select that one the PCI 1000 and I'm going to use an alias a device alias to select this device I know that PCI is or first-time got it selected deb pci is the device is the is the pci bridge that's an alias for the bridge and i won't use the at thirteen as an alias for the device itself the card itself to show you what this really looks like and that it is really an alias this is the entire path so i have selected the path down to the card property are what we're going to show is if the card has any words attached to it anything that we can operate on and this card does not list any children of this card there are no children and the properties you note here that we have the vendor ID the device ID and the revision ID dude are we going to go to the slide that shows the okay well i want you to note those and we'll go use a word that is actually we've got a QA up on it it's QA 1036 called c regs that will put this in a format that you'd be used to seeing as in a register configuration register dump from your card and we'll use phys hi this is what's fizz high right here under the reg note that Wayne was talking about so I'll use that fizz hi to you to start this word as an input for this word that's one that's dot series there you go and you noticed here in the block diagram up above that the vendor ID and the device ID are the same as the first two entries here this is in a format that you should that comes right out of the PCI spec and Wayne wanna yeah let's go back to this machine which is two let's go to the next slide this is the PCI configuration space now that that demo we just showed you is it's difficult to show a demo like this to an audience for the first time but we do have the demo replicated esteems said on the site so you can stop on your own and look at it you as a PCI developer must supply a PCI configuration space 64 headers the blue ones are mandatory so the device ID and the let's say your three yeah the device ID and the vendor ID are as you saw in mine those two right there at the top vendor dice ID and vendor ID and there you see it being read you know write the firmware if I say to you and if he Scrolls up just a bit you'll see the properties then open firmware went in and looked at that configuration space and built the vendor ID and the device ID now there's something that's interesting here is that the Reg property which we also built built is a property encoded array remember the 64 bits are being the 96 bits what you're up there these are some other bits where 90 to talk about them right now they're not important for this demo but that reg property B got this assigned Andrus property you said that's what you want we gave you this they look pretty much the same if you start looking at the higher order bits you'll see now that they're absolute addresses but what's important there is that this property encoded array has one less member than this one and the member that's missing in this is the configuration space pointer and that's the phys hi we use so we use the phys hi with this dot C rigs firmware word that we supplied you to be an input parameter on the stack for dot C rigs and if you look at this before you go any further if you just get into the open firmware user interface and go down and do this kind of stuff and you find out that Jean this doesn't look like I thought it would look don't boot don't go any further the damage is already done and it's very important that you know how to see that your device tree was built correctly because OS 10 or any client of open firmer believes that the device tree is correct and if it isn't and the game's over so let's look at the some of the support nodes that are going to Oh wrong thing some of the support nodes we're gonna I'm going to have Steve we're bouncing back and forth because you've got to talk about this stuff and then show the example Steve in a moment is going to do print in v4 the UNIX people out there you probably noticed that dev and slash in the LS and now print env looks a lot like UNIX stuff and we're going to look at those words that word and we're going to look at three of the nodes that are of interest to you so print env what it's not what you wanted yes what got printed here was all the configuration variables these are the open firmware configuration variables and and they're mentioned in I Triple E 1275 and in that PCI binding and you'll see things that are that are probably important to you some of these are one of the devices what there's two columns here one column the far column is what's stored in boot ROM factory defaults the other column is current so if you are in OS 10 and you are in the terminal app and you started setting some configuration variables and you wanted to see that those were actually set you could shut the Machine off boot back into open firmware and type print ass print in print env and you could see what the current values are and in fact if you set it correctly we're going to be looking at boot device later with the boot picker because that's also very important device it's the only one that's off scale over there and the real important thing is that that comma separates one from the other and and we'll tell you more about that later one other one that's important to a lot of people want to know about what is and what isn't in NVRAM NVRAM is in here and because on this machine it doesn't show anything there isn't anything in NVRAM and even if we were to put something in nvram right now that script would not be used unless you set the use NVRAM r/c question mark variable to turn it on so let's look at the aliases known the importance here is that open firmware has to be able to move down the path in the path when it looks at a string that you give it it's either going to start with a slash or it isn't if it starts with a slash it's an absolute path but you can see some of these paths are terrible and if we stood up here and tried to type we'd die of old age before we maybe got the right one so these aliases are very important but there's a caveat with aliases and that is that the aliases on one machine might not be the same aliases on the other machine and although you can create your own and we expect you would if you were doing a lot of booting and stuff like that you need to check this so dev alias is another command and all of this stuff we're not giving you anything that we haven't put out on the internet already so there's two other nodes that are very important and that's the chosen and the options node but let's look at the options node first name of the properties one of the things you'll notice on your own spare time is what we did was we dev down to the options node and then we listed the properties but when we said print env we saw these properties so print a and V is a nice way to print the environmental variables but they're really configuration variables and they live in the options node and you need to know that because people don't and it's very important and you can very quickly see what what are your configuration variables the other node that's of importance is the chosen node you wanted us to do something when we're done we put stuff that we did for you in the chosen node the MAC address every Ethernet card has to have a MAC address so you stuff your machine with a whole three three Ethernet cards and you also have your own Ethernet connected up on the motherboard now which one of those MAC addresses are we using this one I don't know which one that points to but at least that's the that's the one this machine has never been set up entirely but your boot path and your boot arguments if you had them what would have been there so those three nodes the the alias is known the chosen node on the options node are all very important to you and we'll move on then open firmware security the biggest security we have right now is there's a lock on the box that's number one now I don't know when open firmware security is being implemented on what Mac but we're very close to doing it and the manager of that group is here for the Q&A and I don't know security very well so I'm just going to touch on it right now and during the Q&A session you can ask him of all the stuff but basically what it does is you can still get into open firmware but you can't change anything you can't do anything you can get in and get out that's about it and there's a way of doing it when open firmware boots up if you're holding down the command option PR key PR Keys for parameter RAM which would set those defaults back that I showed you for the configuration variables open firmware first checks to see if the amount of memory you have in the machine is different than when it's shut down ie you had three sticks when you shut down and now you only have two sticks it will unset the security for you the good news is that it comes benign if you don't know how to set it you you can use the machine forever and it'll never bite you it'll always just sit there and do nothing so that's a good feature of it and then we want to talk about the boot process just a bit once again this information comes out of Paul Russia's group the manager for the boot ROM and many people think that it takes forever to boot the Macintosh even with ten in there now and open firmware is doing some stuff that if you don't know about what it's doing you can make your time to boot being very very long for instance if you have a number of scuzzy devices out there and if there's scuzzy people here I have to ask you afterwards to come up and see me and I want to get your business card and give you my business card because Paul's group has a request of disguisey they want a new feature placed in him to the scuzzy drivers whenever open firmware goes out it doesn't know what's connected to scuzzy so if you have a bunch of scuzzy devices connected up it's gonna have to go are you there one two three four five six seven Oh nobody's there are you there and it's got to do it a number of times and that adds considerable to the amount of time to boot basically the firmware goes off and looks at the boot device configuration variable and it goes out there and tries to use it first and also since open firmware is not using interrupts although what command command period I think will tell the the boot picker to stop picking looking for boot devices command period won't be honored instantly because it might be out waiting for a scuzzy device but when it's done it comes back to see if there was some key presses so basically the boot picker displays the rescan and the boot buttons and searches the device tree for all the bootable while you very interesting address this is a hybrid syntax in this remember the slash said it was a absolute address that's the PCI that's the node name the app eight gazillion is the unit address that's in 1275 I think it's in section three point two point one point one this slash says now I'm going down to the Mac i/o chip which is the chip that goes out and and has all the ATA drives and everything else and it's at that unit address and then it goes down to this ati drive at that unit address and comes all the way down here and then this part of it here notice you have forward slashes and back slashes from here on out you're trying to find the boot device on the volume and we have three tech notes 3q a's out there right now on how to work with this how to read the hard disk or any disk from open firmware and how to load that and how to execute it that stuffs out there we're not going to talk about it now because i got two minutes left so we're gonna have Jason come up here real quick and he's going to basically show you the the i/o registry in its planes this is another very very important aspect the device tree in OS 9 mapped pretty close to the name registry but the i/o registry is much more and it has planes and there's only one plane in there that is the device tree and you are not going to see all of these you may not see all of these planes every Macintosh because if you don't have USB on your Macintosh you you don't have firewire you wouldn't see one so Jason show them the IO registry Explorer please - four please okay fine io registry explorer is in developer applications and we'll crank it up right here and is there any particular plane you'd like me to show them the service plane first that's a default plane so we'll go to tools and switch plane make sure we're on service and we can start it root and you can see the Power Mac now we're traversing down yeah that's important right there right there all of a sudden for the very knowledgeable people on from the audience you're gonna say what happened to my support notes where are they how do I know where I booted from well you're in the wrong plane for that now if Jason could go into the device tree planes really and we can go down to the chosen no there's your chosen no there's all your planes very important aspect there's the blue path that's for this machine booted from this is one of the very first things I did when I started learning about the IO registry was saying hey you've you've got my device tree I wanna I want to go find it so this very nice feature I compliment the IO team on this can we look at the same thing using the terminal app please sure there's a command line tool called IO reg which will essentially do the same thing that's gonna come away all right which officers did you want to highlight one of the things I needed to learn yes one of the things I needed to learn was objects and classes who supported whom and where did you get your providers from so let me switch back over to my machine for a second and you want to determine who your provider is and you want to determine your class and you want it to read some variables and you provide your inheriting because you don't have a framework of particulars importance like fire wires of you you're inheriting from IO service but you can be provided by IO PCI device a GP device PCI bridge and card bus device and for all the PCI knowledgeable people in the audience those are all PCI devices so so show them that oh so so shown the IO wrench with a minus B so we can see the bold properties and a minus P so we see the IO device tree plane no need no need to worry if you're not a C++ expert I'm not I was immediately able to find the objects in the tree because they supplied me with the bonus B option and I'm also saying who's providing for me that's a big big help and we also we want to do is get you started because we know that most of the questions that you're asking right now is how do I get started once you got all the information we get talented PCI devices all the time Jason's show them IO PCI device dot H and then that'll be it we'll go into the next part of the session and the headers you'll be interested the IO PCI device that h io PCI bridge I a GP device and the card bus headers are in the kernel framework so show um the shown that header file IO PCI device PCI device dot H the bottom halves right there go down to the phys hi strut there there it is right there get that struck right there remember how I showed you phys hi look at it I never had this ten has it there it is and it's in little-endian and big-endian you may even have to get out of bed anymore I [Laughter] was told not to be talking like that but I guess I won that one well that's it I'm not going to talk anymore and Jason and I are going to get off the stage and we're going to turn the podium and the podium over to Josh [Applause] good morning everyone my name is Josh de Caesar I work in the Mac os10 chorus group on various things but primarily I've been working on platform architecture and various aspects of how IO kid interfaces with the rest of the kernel and today I'm going to talk to you about how you can write a lot of the things that you would use to write generic PCI drivers so in writing a generic PCI driver you're going to have to pay attention to several things including how your driver gets matched in the system both active and passive matching how you initialize your driver how your driver would process events also how you would create a user client so that you can handle requests from various sources now also since you're not part of a one of the built-in frameworks that we provide you're going to have to design the interface between your application and your driver so we need to talk a little bit about how that's done additionally we also want to tell you a little bit about how to deliver your driver so that it'll be there when you need it first off we're going to talk about passive matching so in your driver there's going to be an info dot plist file that contains all the properties that derive that describe your driver to the rest of the system one of those properties in there is the i/o kit personalities you'll have one personality for sort of each way your driver works and all the personalities have some similar properties for matching the important properties are things like the i/o provider class which tells the system what kind of device you're interested in being attached to in the case of most of your drivers you're going to be interested in having your eye provider class be IO PCI device tell the system that you're only interested in PCI devices you're not interested in getting attached to USB devices or block devices just the PCI devices I own a match will help you or will allow you to have your driver matched against the name compatible or modeled properties that the F code that open firmware or the F code for your device left in the device tree so if you know that your drive device isn't in the device tree is going to be called my device or my company , my device you can use the I own a match to do that additionally the different provider types can also provide their own kinds of matching and IO PCI family does that as well it has several kinds of matching there's IO PCI match which lets you match on some combination of configure of the configure device and vendor IDs there's also a primary and secondary match it allows you to match exclusively against either the sub vendor I sub vendor and sub device IDs or the regular vendor in device IDs there's also an IO PCI class matching key which allow you to match against certain classes of device so if you were writing a USB something-or-other or USB host controller it would have a class code and you could use that to do that but mostly what you guys are going to be using is some either the IO PCI match to use the vendor and device ID or name match if you have F code that puts a particular name on your part on your device there are also other possible matching keys and you can find those in IO kit io kit Keys dot H the other major property you're going to be interested in is IO probe score probe score allows several phases of matching to be adjusted in which order the various drivers are going to get attempted to attach to various devices you can use the probe score to say that your driver should be given preference over another in case that your company has two devices that are very similar maybe same device and vendor IDs you might have other variances they might have other properties or various things going on you could use IO provider score to help make sure that one driver wins against the other both would potentially still have the chance to run which is what we're going to look at next in active matching so one thing to keep in mind about the passive as its passive meaning that your driver didn't get to run any code active matching is different you will get your driver will be loaded it'll be linked into the system and it will be given the opportunity to run your probe method now the thing you note at the bottom there is it's not normally needed most devices your most drivers just don't need a probe method you can do what you need to get your driver loaded using the passive matching so what does probe allow you to do allows you to access your device's hardware but that also means that when you're done you have to make sure that you leave your Hardware in a safe state you don't want to leave it such that it's going to be trying to interrupt the system or holding other holding the bus locked or any other strange stuff you have to make sure that you left it in a safe state when you're done because somebody some other driver may also get the opportunity to probe you must free any resources you've used if you allocate any large chunk of memory or attach to various other providers in the system or hold locks you need to make sure you release all of those because some other driver could get probed after you get probed and it turns out they might win so you want to make sure that you've left everything else okay another thing you can do with probe this is one of the more important things that probe does for you is you can allow it can allow you to bind multiple devices to a single driver instance most people don't need to do this but there are certain multifunction PCI devices that the two functions serve different purpose say the first functions of video device the second functions an audio device but you want them handled by the same driver so by returning one driver instance for both of the two probes you can get that bound and I've got an example of that that's in Darwin I'll talk a little bit more about where to find that later I just want to reiterate again these are probe is not normally needed you can do almost everything you need to do just using property matching from the passive schemes so now that your driver has been matched in the system besides that you're the one that wants to try you're going to get started one thing to remember is that start can also be used as an even later version of probe since every dry almost every driver will have a start routine you also have the opportunity of returning false from your start routine to say that you're not actually interested again sort of the same rules apply with probe if you did allocate any resources you need to make sure to let them go and make sure your hardware is in a safe State so we're gonna focus here on a device whose provider on a driver whose provider is IO PCI device now this PCI device the num you get provides you access to your hardware it provides it in several forms it provides a way to get mappings for memory space and i/o space and these are done through a couple of these methods that get device memory with index or with register also IO device memory now I've got a lot of these class names property names or method calls coming up and we're gonna try to make sure that these slides are available for you later so you don't have to copy them down and these will just serve as sort of crib notes for later when you're trying to go through and figure out how to put it all together so for configuration cycles as you saw there's the C regs demo earlier that lets you look at what your configuration registers are you can read and write your configuration registers by using the config read 32 write 32 and various other methods on your nub similarly if you want to turn on the memory space for your device or you need to set bus master enabled i/o space or any of the other or many of the other various bits in the command register there are some word or some methods will help you do this set memory enabled takes a fault it takes a boolean for whether you should turn it on or off so once you've figured out how you can want to map your device you need to figure out how it's going to be used by the rest of the system and we have several classes that will help you do this particular these are the the i/o work loop and the various IO event source sub classes and subclasses that are like to be most useful for URI Oh interrupt event source and I have a filter in her event source for event processing timer event source for timers and IO command gate is sort of a catch-all that lets you sync stuff up there's also the IO command pool sort of helps you manage resources for within your driver and Iowa's register service helps you to make your driver available for the rest of the system so a little more on register service so when you call register service on your driver instance your driver will get it added to the matching system and the matching system will come through and try to find all the devices that might be interested in attaching to you now most the time you're not actually going to have other drivers attaching to your driver because you're sort of the your what we call a leaf node and the service plane but what it also does is it allows user space to find the user space matching functions to find you and this will allow you to create user clients it also can be used to let other drivers in the system know that your driver is ready you might have two different devices in your draw in your your product and you want to make sure that one driver references the other or will wait for the other so you can have the second driver do wait for service and that will come back or stop blocking as soon as the other driver that's called register service so after your drivers been initialized you need to start processing you want to be able to process events so here's a little bit more about some of these classes that we provide for event processing so the i/o work loop allows you to serialize access to all of your drivers resources it's meant to simplify everything keeps you from having to have tons of little locks to lock this lock that it also makes it easier to access your hardware you don't have to worry that two threads one and maybe a client thread maybe your thread or accessing your hardware at the same time as long as you use the bare various access or methods through the various events sources or work glue you will not have to worry about having to driver or two to two threads trying to talk to your hardware at the same time the work loop also provides a thread for various IO event source actions talk about that a little bit more later and then the work loop also soar supplies itself as a choke point when your clients need to tell you to stop they're not ready to receive callbacks or other things in the stack need to tell you to stop for a moment so each of the event sources can be added to the work loop and any time an event source fires and says that it's got something to do the work loop will serialize any other outstanding events to make sure only one of these is happening at any given time and they each of these and event sources will execute an action this action can be will normally be executed on whatever client thread generated the trigger but they can also happen on the work loops thread but only one at a time so in a little bit more detail on the types of interative ends you're going to be using primarily if your device is PCI device has got likely to have an interrupt you'll want to have some way of getting at it easily in your driver we do provide lower level interrupts services that will let you control the Nabal and disable on your interrupts register interrupt handlers but we do suggest that you use these higher-level constructs because they will simplify many things for you and the two types of interrupts event sources we have are the basic interrupts event source it's a proxy for the device interrupts it makes it so you don't actually have to talk to the device interrupts you'll get notified when things happen it also handles behind the scenes enabling and disabling your interrupts as required and the action will get so when an interrupt occurs this action will happen on a thread you don't have to worry about running an interrupt context so when this thing does happen you can block if you have to you can allocate memory if you have to you can take locks don't have to worry about running in a very restrictive restricted environment the one thing to keep in mind with the interrupted IO interrupts event source is that if you've got a level insensitive interrupt like a PCI device would when your interrupt happens in the hardware there the low-level interrupts controller stuff will process this interrupt and cause a thread to get scheduled in the meantime your interrupts will be disabled so if other interrupts come in for your device they won't be able to do anything you won't get notified of them happening until your interrupts action it finishes so if you want to have the ability to take multiple interrupts at once from your device or potentially if you're sharing and interrupt with several devices if you've got a single PCI card that is a bridge on it and then several your devices behind it they'd be sharing the one physical interrupt so to make sure that one device can get it interrupt while the other ones processing and interrupted thread level we provide this i/o filter interrupt event source has the same basic features as a regular i/o interrupted event source but it also allows you to supply a filter function that runs at interrupts level now in that this is a real interrupt handler you cannot allocate memory you cannot take locks you cannot do anything that would otherwise block the system otherwise the system will deadlock now what this filter function does allow you to do is quickly interrogate your hardware to determine whether or not the interrupt is for you also it allows you to say process the interrupt if you can process the interpreter very quickly you can do that and you may not even have to send this interrupt cause the interrupts action to cause your work loop thread to go you can in a lot of cases where you might want to do that is that you're implementing some sort of software DMA where you have a lot of high frequency interrupts coming in you just want to quickly take a bite off of a FIFO and put it into a buffer somewhere and maybe when you're fuffeling to approach full then you might want to decide that you should cause your interrupts action to fire and let the higher-level parts of your driver process the rest of the interrupts so there's also the IO timer event source you can use it in two ways the first way is a lot easier just basically to schedule a time out suppose a client issues a transaction your driver and you want to make sure that after some number of milliseconds to seconds that a notification is sent back up to say that it just didn't complete you can at the same time that you issue the transaction to your hardware you can also set up one of these timer event sources when the timer event source fires it gives your OP gives you an opportunity to see if the thing if the transaction is done or if it isn't done you can set an error up now one thing to keep track of is that these timer event sources are one-shots it won't get rearmed unless you explicitly rearm it so if you're going to attempt to use one of these for a periodic timer you need to after every time it fires you need to rearm it another one is the IO command gate this isn't really like a lot of the others it doesn't have an explicit action attached with it it doesn't really have a trigger but it does have a way for you to execute any function as if it were being executed by your work loop now it's not going to get shuttled over to the work loop thread it'll execute on whatever thread you've called the function on so it's efficient but it will block if necessary in case the work loop is in the middle of doing something this allows you in many cases to take an i/o request coming in to your driver that could be happening on multiple processors or in many different ways and schedule the function that actually causes the IO to be put into your driver by saying run action command on your command gate and it will get serialized appropriately the command pool is mostly a helper it's not likely to be used by most of your drivers but it's there if you need it basically it lets you allocate some number of commands each one of these commands would hopefully have the total amount of memory needed to process completely one of your commands same time you don't want to pre-allocate too much memory since every met every piece of memory you have pre-allocate isn't going to be available for the rest of the system this is important notion if your drivers somehow related to the paging path because if the paging system is trying to come up free up memory or put stuff on disk there's no memory to be allocated you can't be allocating memory in your driver while it's doing that these the i/o command pool can be told to block when there isn't anything available also it can be set up to just return you an error to say that there is no memory available at this time and you can if you wanted to return an error or you could block on some other hile or higher-level construct in your driver it's also synchronized with the work loop to make sure that things don't get out of sequence so now that you've got a basic notion of the classes that are used to process events in your driver you need to figure out what sort of event or how you aren't start getting these events to your driver so there's a couple ways to do that there's one of them is basically generic sort of generically through property access the other is through user clients now the property access stuff is done through basically gets or sets on properties in your drivers dictionary and this is a very easy thing to do it's connection lists there's no clients to think about it's kind of high overhead because as you come from the youth from outside the kernel has to get wrapped through a serialized it's actually a chunk of text comes into the kernel that gets parsed again and created into a dictionary and consequently it's also rather low bandwidth but it's easy to make your driver participate in this the two methods that you need to override our serialized properties this allows you to find out when somebody's trying to get properties from you and potentially return different properties also set properties allows you to take or accept a dictionary from user space and then add it and dynamically into whatever dictionary now if you're doing a more complicated system you're probably going to have to use and I a user client there's somewhat more complicated so we're gonna be trying to provide some examples for you give you a baseline of what to do it's a connection based so you'll always know who all of your clients are you'll know if clients go away and you'll also have everything you need to serialize clients to make sure that they're not trying to talk to you all at once it's very low overhead and it can be very high bandwidth it allows you to map memory from a user process into the kernels address space if necessary you could DMA into the buffers you could copy memory around you can do pretty much whatever you need you can also export new API through to user space and the the major property that you need to be interested in for doing this is the G i/o user client class key basically you add a new property to your drivers dictionary that says the name of the class it should be instantiated when a user client request comes in so how do you access your application from or your driver from an application and this is done pretty similarly for cocoa or carbon applications ultimately they would have to link against the i/o kit framework and how this linking is done is a little bit complicated depending on whether your cocoa or carbon if you saw the i/o kit overview on Monday there was some stuff where you had to have a CF plug-in and various other things in between to get back and forth between the mokou context and CFM context but it boils down to you get you attached or you linked with the i/o kit framework it provides you all the api's that you need to shuttle back and forth across the user kernel boundary it also probably provides a set of matching functions that you can use to find your device after register service has been called in your driver these user space commands will be able to find your device now if you're trying to use the get and set property interfaces to your driver the two functions that you're going to be interested in using from user space our ir registry entry creates the F properties and I registry entry set cioth properties these allow you to pass a dictionary from user space into the kernel and get it and have it end up going to the driver in the set properties or if you're getting allows you to ask the kernel to provide you a dictionary from serialized properties in your driver that you can then use now if you're going to be creating a user client after you have found the device you'll want to use i/o service open which will cause the in the kernel the user cyan't the user client class to be created and you can then go from there there's other there's also once you have the user client you can then use the api's that you've provided say to cause a transaction to be initiated with your hardware to memory to do various things as you decide also you can provide a library or see if plug-in as you desire desired also you can just simply have a piece of C code that you can link into your application that simplifies the calls back and forth so the other topic we need to talk about is driver delivery so now that you've got a driver you need to figure out how to get it into the system this can be done in a couple of ways standard driver format that you're going to be using is a dot text as the standard CF bundle has the usual properties in it the two that are very interesting for us of course are the info dot plist file that gives the properties including the iokit personalities and there's also the binary for the driver so this whole thing is directory based it's not a flat file which makes it rather difficult to put in the ROM on a PCI card so we've also provided another method for storing drivers this is a dot MKX it's um we called a multi text it can contain multiple texts normally for your device you're only going to be putting one kext inside your n text it turns into a flat file it's compressed it's also check summed and is very easy for use in a rom it only in the and it only contains an info dot P list and a drivers behind arey so how do you create this dot M text first thing you need to do is you need to strip the debugging simple symbols and local symbols from your driver this will reduce the size of your binary by about 90% it'll also simplify things you don't worry about other people looking at your debugging symbols or gaining other information about the internals of your driver to do this you use the strip command with dash lowercase X and point it to your driver it then goes through Andrews everything it isn't needed it's very important to do this because obviously the ROM space in your card is limited and this will greatly extend the size of the driver that you get the actual working size of driver that you can put in the ROM in your card so how do you create the EM text well first you have to run after you strip the driver then you can run this em text cache utility and this utility will take a a text or potentially a list of texts and put them inside your driver and create an EM text out of them it will compress them and checksum them to further reduce this driver the size of your mtext now that you've got an M text you need to know what to do with it so this involves the F code that you've written for your driver now Mac OS 10 uses basically the same F coat as Makela Stein really there's only optionally two properties to add that are needed and these are the driver comma APL comma Mac OS X comma PowerPC property that's very similar to the Mac OS 9 version of the driver from that you're used to it's in that it's a property in the device tree you use encode file to put it there and there's an example there of what a sample string for how you'd create this causes the entire contents of the MKX to be created as a property inside your driver they're inside the drivers properties now this can take up a lot of space in the registry so one way you can get around this is by using the driver - reg a yell mac os/x property this just puts this would just be a reference in the property list for where to find the driver in your expansion Rob now obviously you have to have an expansion ROM to do this and unfortunately there aren't any good tools to do that right now but it is possible to do and future we hope to have better tools another topic I just wanted to briefly mention is firmware updates so if you are if later after you've already released your card you want to be able to update the firmware this is a sample of one way you can do it there are many different ways you could do this and I don't want to talk about this a little bit because it is different than nine obviously in Mac OS 10 you can't actually access your hardware from an application you have to go through a driver so this means that the hardware access done to say flash the ROM on your card has to be done by the driver firmware update application just turns into a pretty front end you one way or another have to pass the firmware image from user space to the driver this could be done in chunks it could be done all at once by having a driver by creating a dummy driver that just contains a property that is the image that somehow attaches to your driver or you could use set property interface to put the chunks across one at a time you could also even use a user client to have the chunk of address space in your user in your address user at client sorry you could have you could use a user client to have your you have your user application have the entire firmware image in its memory space then you could have your user client map that address space into the kernel that your driver could then take advantage of once you're in the driver it will write these chunks into the flash on your card you could also have it update properties so that your application could have a barbershop whole giving you a little bit of progress and that's pretty much the basic idea that so where to find some examples the one thing that we really want to stress is the first thing you need to do if you're going to be writing Hyeok at drivers is you need to sign up as a darwin developer you need to go to the public source toppled on come website to find out how to do that and in there you can find out how to get access to everything inside Darwin three things of interest inside Darwin that's topical to today's discussion are X and you this is the curls so the actual kernels source you can find inside here all the headers and source to various pieces of bio kit this will be in a valuable resource also serves as many examples for how to do certain things I've also been working on an example generic PCI driver unfortunately it's not quite done but it's got a pretty good going so far you can find this in i/o kit examples Colonel IO kit generic and generic PCI I will be posting updates or references were how to find it and status reports to the Darwin mail devourer darwin developer mailing list so you should all sign up for that additionally a couple years ago i wrote a simple driver for a Brooktree 878 device it's one of these devices that has both a video and an audio function and the driver is available inside darwin server is somewhat more complicated example of how to do that you