Hi Phil,
Thanks for replying, it's always good to hear from someone who has
done this sort of thing before.
To clarify my understanding of your situation: these
interrupt presumably correspond to independent subdevices or ports
on the device itself. You currently have up to 2 user client
instances, one for input and one for output, each of which are
hardcoded to one of the two interrupt sources. Correct?
Yup the Card itself has several sub-devices, Currently the driver
stack only really interacts with 1 sub-device at a time,
and I am trying to add functionality so that i can interact with
each of the sub-devices concurrently.
Are these 4 independent ports (interfaces, units,
devices, whatever) which happen to be one or the other direction,
or would one of the inputs always be paired with one of the
outputs? It sounds like the former, but I'd like to clear this up
100%.
No, whilst there is a very high likely-hood that an input port would
be paired with an output port, this is not guaranteed, and not
enforced by any of the hardware.
(The card has multiple HD-SDI video channels (ie. 2-in, 2-out), and
interrupts for each channel. So whilst most of the time an input
port would also be driving an output port this is not always true)
Hence why i have separate user clients for input vs output, instead
of a single user client that handles it all.
TL:DR - No an input is NOT ALWAYS paired with an output.
Can I pick "none of the above"? ;-)
There is an established pattern/convention in the IOKit of
creating child IOService instances to identify multiple
ports/subdevices/interfaces/etc. on a larger physical device. If
you look at the output from
ioreg -i
you should spot a few IOUSBDevice (subclass) instances, which
typically have multiple IOUSBInterface child objects. These child
objects can then be matched by clients independently.
Bearing that in mind, I would suggest a provider/client hierarchy
that looks something like this:
+-o IOPCIDevice
+-o MyWholeCardDevice
+-o MyInputInterface
| +-o
MyInputInterfaceUserClient
+-o
MyOutputInterface
| +-o
MyOutputInterfaceUserClient
+-o
MyInputInterface
| +-o
MyInputInterfaceUserClient
+-o
MyOutputInterface
+-o
MyOutputInterfaceUserClient
(assuming a PCI device and assuming your 4 ports are
independent, see above)
OK thanks,
That is pretty much the implementation i am going for.
Perhaps i did not explain it very clearly previously.
The only change would be that All the MyInterfaceUserClients are
exactly the same class, just matched against slightly different
IORegistryEntry properties.
You mention that the input and output code is very similar, so
you could use a common superclass for them, the class hierarchy
would look like this:
(Subclass : Superclass)
MyWholeCardDevice
: IOService
MyInterface
: IOService
MyInputInterface
: MyInterface
MyOutputInterface
: MyInterface
MyInterfaceUserClient
: IOUserClient
MyInputInterfaceUserClient
: MyInterfaceUserClient
MyOutputInterfaceUserClient
: MyInterfaceUserClient
The Input and Output specialisations for interfaces and
user client would (by your description) contain very little
code, but having them as different classes can help with
matching.
As for going about implementing this, MyWholeCardDevice's start() method
presumably initialises the device and enumerates the ports,
and possibly sets up the event sources. When each port is
ready, you would then create a corresponding MyInputInterface
or MyOutputInterface instance that knows
which port on MyWholeCardDevice it represents. Each such interface
object would have the "IOUserClientClass" property set to
the corresponding class name, along with something to
identify the port (I assume the user space app will need to
know which port it's using). When ready, you call
registerService() on the interface object to make it
available for matching.
The user space
framework can then open the service, creating the user
client. The user client doesn't talk directly to MyWholeCardDevice but rather through the MyInputInterface or MyOutputInterface object. Each interface
object can restrict itself to one user client to enforce
exclusive use, but the individual interfaces can be used
independently. Identifying ports (and direction) can be done
entirely via IORegistryEntry properties, which
reduces/simplifies your user methods.
If there literally is no input or output specific code, you
can also make the direction a property on a single interface
class, and avoid having separate input and output interfaces
and user clients.
This is how it works at the moment, ie. the direction is an
IORegistryEntry property, and a single interface class is used for
both user clients.
I'm hoping to expand on this structure to add the additional user
clients
Yeah, I think everyone has this problem. The Halvorsen book
(discosure: I was one of the reviewers) is a little more
practical for driver development than Singh's (and somewhat more
up to date) but still leaves a lot to the imagination when you
actually try to implement a driver yourself.
I have looked up that book and will probably buy a copy soon.
Even if one of the reviews on amazon highlights the lack of any info
regarding video based devices, although perhaps the author of that
comment mean video as in display devices, and not I/O.
It's nice to know I was at least sort of on the right track, I think
the hardest part will be modifying the my root "MyWholeCardDevice" class to support
multiple concurrent user clients,
But at least I have the correct architecture now.
Thanks again, your feedback and advice has been really helpful,
James
|