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