QNX approch

I’m curently designing some low level drivers in a QNX Neutrino
environment. While designing a low-level driver (such
as /dev/ser1, /dev/spi or /dev/i2c drivers), it is clear that the best
approch is the POSIX approch (open(), close(), read(), write(), etc.)
It seems to be the way to do it with QNX…

Now, what if I’m designing a EEPROM driver which connect to
the /dev/i2c driver? I wonder what is the most standard way to do it in
QNX Neutrino. I wonder if I should :

  • Create a /dev/i2c/eeprom driver using the “open(), read(), write
    () ,etc” approch. The problem I see with this approch is that if I want
    to write a specific byte in the EEPROM, the write() parameters doesn’t
    include an offset. So, I will have to first call lseek(), to move my
    pointer to the specific byte and then call write().

OR

  • Create my own API. For example, I could create a function called
    EEPROMWrite(), with a prototype including the offset for writing. This
    EEPROMWrite() will not be registered in the ressource manager. It will
    simply be a library that the user may call if he wants to.

Now, maybe you can tell me what is the standard QNX way to do it?

Thanks,
Sylvain G.



Sent via Deja.com http://www.deja.com/
Before you buy.

sylvain.gagnon@mindready.com wrote:

Now, what if I’m designing a EEPROM driver which connect to
the /dev/i2c driver? I wonder what is the most standard way to do it in
QNX Neutrino. I wonder if I should :

  • Create a /dev/i2c/eeprom driver using the “open(), read(), write
    () ,etc” approch. The problem I see with this approch is that if I want
    to write a specific byte in the EEPROM, the write() parameters doesn’t
    include an offset. So, I will have to first call lseek(), to move my
    pointer to the specific byte and then call write().

What is the problem with having to call lseek() prior to issuing a write/read ?

The big advantage of this approach is that you can use already written
standard utilities for your driver (this is the highest form of code
re-use); for example:

cp /home/joe/src/foo/images/bar.bin /dev/i2c/eeprom

to program the whole eeprom.

or

hd /dev/i2c/eeprom | less

to view the eeproms content

or

disasm /dev/i2c/eeprom | less

to view the eeprom as assembly

or

khexedit /dev/i2c/flash

to change the flash dynamically.

Anyway, I am sure you get the idea.

OR

  • Create my own API. For example, I could create a function called
    EEPROMWrite(), with a prototype including the offset for writing. This
    EEPROMWrite() will not be registered in the ressource manager. It will
    simply be a library that the user may call if he wants to.

The problem with this approach is that now you have to write your own
(from the above example)

  1. cp
  2. hd
  3. disasm
  4. hex editor
  5. ?

Now, maybe you can tell me what is the standard QNX way to do it?

The open/read/write/devctl (i.e. Posix) approach is definately encouraged.


To succeed in this world it is not enough to be stupid; you must also be
well-mannered. - Voltaire

The Neutrino way is DEFINITELY the /dev/ic2/eeprom approach.

To add to Rennie’s comment. You will also get

data synchronisations. What if your EEPROMWrite function
is call twice at the same time (worse on a SMP ) you
would have to have some sort of data synchronisation.

Via resmgr you also get transparent networking.


<sylvain.gagnon@mindready.com> wrote in message
news:8l7504$o92$1@nnrp1.deja.com

I’m curently designing some low level drivers in a QNX Neutrino
environment. While designing a low-level driver (such
as /dev/ser1, /dev/spi or /dev/i2c drivers), it is clear that the best
approch is the POSIX approch (open(), close(), read(), write(), etc.)
It seems to be the way to do it with QNX…

Now, what if I’m designing a EEPROM driver which connect to
the /dev/i2c driver? I wonder what is the most standard way to do it in
QNX Neutrino. I wonder if I should :

  • Create a /dev/i2c/eeprom driver using the “open(), read(), write
    () ,etc” approch. The problem I see with this approch is that if I want
    to write a specific byte in the EEPROM, the write() parameters doesn’t
    include an offset. So, I will have to first call lseek(), to move my
    pointer to the specific byte and then call write().

OR

  • Create my own API. For example, I could create a function called
    EEPROMWrite(), with a prototype including the offset for writing. This
    EEPROMWrite() will not be registered in the ressource manager. It will
    simply be a library that the user may call if he wants to.

Now, maybe you can tell me what is the standard QNX way to do it?

Thanks,
Sylvain G.



Sent via Deja.com > http://www.deja.com/
Before you buy.

Just to stick my 2 cents in here, I think that
either way is appropriate. In the cut over from
QNX 4 to Neutrino, there seems to be a much
greater emphasis on writing I/O managers.
This is clearly an excelent approach when
there are issues of portability or if you
want to use the device with standard utilities.

In your case, I think it is merely one of taste.
There is nothing wrong nor un-QNX like to write
your own message passing interfaces.

Mitchell Schoenbrun --------- maschoen@pobox.com

Mitchell Schoenbrun wrote:

In your case, I think it is merely one of taste.
There is nothing wrong nor un-QNX like to write
your own message passing interfaces.

It is not simply a matter of taste. There are definite productivity advantages
(over the long-term) in developing a driver with an interface that is based on
the Posix model. I agree that it is not wrong to develop a driver on QNX
without a Posix interface, just as it is not wrong to write non reusable code
(at least no one will throw you in jail for such a transgression :slight_smile:

Having said that. I can certainly envision cases where the driver is so trivial,
or inherently non reusable, that creating a Posix interface is overkill. I do
not have enough information to judge whether that is the case here.


To succeed in this world it is not enough to be stupid; you must also be
well-mannered. - Voltaire

why not do both ?

start off with the resmgr way, so standard utils
will work with the device.

then add devctl()s or an XTYPE for read/write to
specify offset + read/write operation

the utils/apps you want optimized to work with
your manager could use the non-standard interface

but, otoh, implementing a non-standard interface
just to save 1 msg pass (lseek()) – and that’s
only when not using sequential access – may not
be worth the effort, especially, if using a slow
device.

Mike Taillon <miket@qnx.com> wrote:

but, otoh, implementing a non-standard interface
just to save 1 msg pass (lseek()) – and that’s
only when not using sequential access – may not
be worth the effort, especially, if using a slow
device.

Or use combo messages to get the benefit of both…

Rennie Allen <rallen@computermotion.com> wrote:

It is not simply a matter of taste. There are definite productivity advantages
(over the long-term) in developing a driver with an interface that is based on
the Posix model. I agree that it is not wrong to develop a driver on QNX
without a Posix interface, just as it is not wrong to write non reusable code
(at least no one will throw you in jail for such a transgression > :slight_smile:

Well if it is not wrong, and my opinion differs from yours, how
is it not a mater of taste? BTW, I write Posix resource managers
all the time, and in some circumstances I find them indispensible,
they are just not always for me, the structure of choice.

Mitchell Schoenbrun --------- maschoen@pobox.com

Mitchell Schoenbrun wrote:

Rennie Allen <> rallen@computermotion.com> > wrote:

It is not simply a matter of taste. There are definite productivity advantages
(over the long-term) in developing a driver with an interface that is based on
the Posix model. I agree that it is not wrong to develop a driver on QNX
without a Posix interface, just as it is not wrong to write non reusable code
(at least no one will throw you in jail for such a transgression > :slight_smile:

Well if it is not wrong, and my opinion differs from yours, how
is it not a mater of taste? BTW, I write Posix resource managers

It is not simply a matter of taste, since there are real, tangible benefits
associated with one approach over the other. In cases where there are no
tangible benefits over one approach or the other, I agree, it is simply a matter
of taste.

all the time, and in some circumstances I find them indispensible,
they are just not always for me, the structure of choice.

Perhaps the times when you choose not to use a resource manager architecture,
are those times, when the benefits of the resource manager architecture are not
so compelling (in cases where the code is obviously disposable, perhaps ?). I
believe I acknowledged that this may be the case on occasion.


To succeed in this world it is not enough to be stupid; you must also be
well-mannered. - Voltaire

I agree that it is not wrong to develop a driver on QNX

without a Posix interface, just as it is not wrong to write non
reusable code
(at least no one will throw you in jail for such a transgression > :slight_smile:

But it doesn,t make my code non reusable! Lets take the example of an
EEPROM device connected to an I2C bus. So, I have a /dev/i2c device and
a /dev/i2c/eeprom device. My I2C device is already implemented with the
open(), close() approch. Since my EEPROM device uses my I2C device, I
wonder if it is not an overkill to use one more time the open() close()
approch while designing my EEPROM driver. With this approch, I will
have a write()(the EEPROM one) calling another write() (the I2C one).
The portability of my driver is already insured by the I2C POSIX
functions, so why bother with the resource manager?

Sylvain G.


Sent via Deja.com http://www.deja.com/
Before you buy.

Mitchell Schoenbrun <maschoen@tsoft.com> writes:

Rennie Allen <> rallen@computermotion.com> > wrote:
It is not simply a matter of taste. There are definite
productivity advantages (over the long-term) in developing a
driver with an interface that is based on the Posix model. I
agree that it is not wrong to develop a driver on QNX without a
Posix interface, just as it is not wrong to write non reusable
code (at least no one will throw you in jail for such a
transgression > :slight_smile:

Well if it is not wrong, and my opinion differs from yours, how
is it not a mater of taste? BTW, I write Posix resource managers
all the time, and in some circumstances I find them indispensible,
they are just not always for me, the structure of choice.

The problem I have, whether real or imagined (I’m still learning),
is that not all devices offer meaningful interpretations of open,
close, read, write, poll, etc. For example, I want to write a driver
to an Allen-Bradley KT card for Data Highway Plus. Look at the calls:

open - makes sense
close - makes sense

write - useless for synchronous messaging
read - similarly useless
poll - similarly useless

flush - meaningless
etc.

and, now I have a pile of devctl()s to implement…

read block
write block
read/mask/write bits
open processor
change processor mode
query processor mode

etc (there are many).

What have I gained from using the POSIX model? I get told when the
client exits, even if it crashes. I get to publish a name in the file
system name space. I can use standard utilities to perform some
opeations. I’m just not sure if it’s worth the complexity of the
POSIX wrapper for these benefits.

For example, using the POSIX mechanism (assuming you don’t have a
/proc filesystem), people tend to limit the information available.
Look at mqueue. You can use ls -l to look at the queue sizes, but
what about information like number of readers, wait states of readers,
number of writers, wait states of writers, maximum messages in queue,
total bytes queued, queue owner? ls -l won’t give me these, so in
order to get this info, I need another devctl() and a custom tool to
call it. If the original author of mqueue had been working with a
custom interface, he (or she) might have thought to offer this
information. I know that the POSIX mechanism offers endless
flexibility through devctl(), which is really just a way to create a
custom API, but programmers who already give us some information
through standard tools tend not to go to the trouble of making the
custom tools to do the rest of the job.

I’m not trying to slag the POSIX model. I think it’s a Good Thing.
But I do agree with Mitchell that it may not always fit.

Cheers,
Andrew


Andrew Thomas, President, Cogent Real-Time Systems Inc.
2430 Meadowpine Boulevard, Suite 105, Mississauga, Ontario, Canada L5N 6S2
Email: andrew@cogent.ca WWW: http://www.cogent.ca

Rennie Allen <rallen@computermotion.com> wrote:

It is not simply a matter of taste, since there are real, tangible benefits
associated with one approach over the other. In cases where there are no
tangible benefits over one approach or the other, I agree, it is simply a matter
of taste.

Well I would agree except that there are real tangible benefits to
both approaches. In some cases added portability is of no value,
but faster coding is.


Mitchell Schoenbrun --------- maschoen@pobox.com

Andrew Thomas wrote:

The problem I have, whether real or imagined (I’m still learning),
is that not all devices offer meaningful interpretations of open,
close, read, write, poll, etc. For example, I want to write a driver
to an Allen-Bradley KT card for Data Highway Plus. Look at the calls:

open - makes sense
close - makes sense

OK so far.

write - useless for synchronous messaging
read - similarly useless

Reasonable statement.

poll - similarly useless

Select/Poll, is generally useful for things like control networks (which I
assume AB Data Highway is).

flush - meaningless
etc.

OK.

and, now I have a pile of devctl()s to implement…

read block
write block
read/mask/write bits
open processor
change processor mode
query processor mode

etc (there are many).

These don’t need to be devctls. MsgSend()/Sendfd() will do nicely for
these, if portability is not an issue.

You know, I wrote a resmgr for a control network once. In prefix namespace it
looked like this.

/dev/ctrlnet/processor1/mem
/proc
/task1
/task2
/processor2/mem
/proc
/task1

Where ctrlnet is a particular network (there could be multiple)
processorX is a particular node (PLC what have you)
taskX is a particular task on a particular controller.

You could:

“spatch /dev/ctrlnet/processor1/mem” to view the controllers physical memory.
“ls /dev/ctrlnet/processor2/proc” to view the tasks running on processor2.
“rm /dev/ctrlnet/processor1/proc/task2” to terminate task2 on processor1.
“cp /src/foo.hex /dev/ctrlnet/processor1/proc” to download, and begin execution
of a task on processor1.

I could use Photon filemanager to download and begin execution of a task on
processors on the network.
I could use Photon filemanager to terminate tasks on processors on the network.
I could write a 5 line shell script to shutdown/startup every task on the
network.

A programmer could open("/dev/ctrlnet/processor1/proc/task1", O_RDWR), and then
(using the returned fd) “Sendfd(fd, …)” to send messages to a task (exactly
the same way one would do the same thing for a QNX process). Of course, the
messages to a task would be proprietary, but look at all the infrastructure that
was provided by the standard API. Also select(fd,…) would work, and a client
program could wait on a message from multiple tasks on multiple controllers in
the network; while simultaneously waiting for keyboard input or Photon events,
or; yada, yada, yada.

Anyway, for me it certainly seemed like I could successfully overload a whole
whack of standard operations for a control network.

What have I gained from using the POSIX model? I get told when the
client exits,

This is good, I think; 1 point.

even if it crashes. I get to publish a name in the file
system name space.

This is also good; 2 points (btw: I prefer the term prefix name space).

I can use standard utilities to perform some
opeations.

Again this is good; 3 points.

I’m just not sure if it’s worth the complexity of the
POSIX wrapper for these benefits.

Hmmm, have you played with neutrino much ? It really isn’t very complex to do a
resmgr.

Now to apply the same criteria to creating a completely non-standard interface.

OK, I have created a proprietary interface; what have I gained ? I saved
perhaps 50 lines of code, over doing a resmgr. I have to do my own name
location mechanism (which no other program/utility will understand), I have to
handle resource reclamation when a client dies (I’m not sure if it is even
possible to reliably do this without handling a close in Neutrino; in QNX 4 it
is doable but ugly). If my driver is going to be multi-threaded I will also have
to do my own thread pool management.

For example, using the POSIX mechanism (assuming you don’t have a
/proc filesystem), people tend to limit the information available.
Look at mqueue. You can use ls -l to look at the queue sizes, but
what about information like number of readers, wait states of readers,
number of writers, wait states of writers, maximum messages in queue,
total bytes queued, queue owner? ls -l won’t give me these, so in
order to get this info, I need another devctl() and a custom tool to
call it.

If the original author of mqueue had been working with a
custom interface, he (or she) might have thought to offer this
information.

I don’t buy the argument that because a developer is using a standard interface,
that they subconsciously limit themselves to the functionality that the
interface can provide. Is this what you are saying ?

I know that the POSIX mechanism offers endless
flexibility through devctl(), which is really just a way to create a
custom API, but programmers who already give us some information
through standard tools tend not to go to the trouble of making the
custom tools to do the rest of the job.

You don’t need to create devctls under QNX (for custom API’s); however, if you
want portability it isn’t a bad idea to do so. Consider that if you build all
of your custom API over devctl’s then it will be no more difficult to port your
driver to another Posix system; and all of your clients will compile and link
first time (assuming that all other aspects are Posix).

I’m not trying to slag the POSIX model. I think it’s a Good Thing.
But I do agree with Mitchell that it may not always fit.

I don’t remember disagreeing with Mitchell. I simply made the point that when a
device driver can reasonably be placed in the Posix interface model, it is more
than just a matter of taste whether you do so or not (there are real
quantifiable differences in the utility of the end result).


Andrew Thomas, President, Cogent Real-Time Systems Inc.
2430 Meadowpine Boulevard, Suite 105, Mississauga, Ontario, Canada L5N 6S2
Email: > andrew@cogent.ca > WWW: > http://www.cogent.ca


To succeed in this world it is not enough to be stupid; you must also be
well-mannered. - Voltaire

In article <x7k8ebusq8.fsf@cogent.ca>, Andrew Thomas <andrew@cogent.ca> wrote:

Mitchell Schoenbrun <> maschoen@tsoft.com> > writes:
Rennie Allen <> rallen@computermotion.com> > wrote:
It is not simply a matter of taste. There are definite
productivity advantages (over the long-term) in developing a
driver with an interface that is based on the Posix model. I
agree that it is not wrong to develop a driver on QNX without a
Posix interface, just as it is not wrong to write non reusable
code (at least no one will throw you in jail for such a
transgression > :slight_smile:

Well if it is not wrong, and my opinion differs from yours, how
is it not a mater of taste? BTW, I write Posix resource managers
all the time, and in some circumstances I find them indispensible,
they are just not always for me, the structure of choice.

The problem I have, whether real or imagined (I’m still learning),
is that not all devices offer meaningful interpretations of open,
close, read, write, poll, etc. For example, I want to write a driver
to an Allen-Bradley KT card for Data Highway Plus. Look at the calls:

open - makes sense
close - makes sense

write - useless for synchronous messaging
read - similarly useless
poll - similarly useless

Hmm. Not sure I buy this. If we assume that a synchronous message is no
different from a delimited element of a continuous stream, then read & write
both make sense. Compare it to UDP sockets. recv() is really superfluous
and recvfrom() is only necessary to obtain the IP address and port of the
sender on an unconnected UDP socket. This could be placed in the body of
the message as well.

Consider a message as:

header: destination address, delivery options
body
delimiter

The delimiter could be explicit, implied by a flush, or always appended to
a message – writev is a good choice when doing this. The choice here depends
on the format. Some formats are amenable to explicit delimiters because they
specify some bit patterns that aren’t possible in the message format.
Other times, for simple messages, you want to be able to do a single write, and
for complex messages, it may be better to perform multiple writes to marshal
the message, followed by a flush.

Now we can write a synchronous message with:

write(fd,header,sizeof header);
write(fd,elementA, sizeof elementA);
write(fd,elementB, sizeof elementB);
tcflush(fd);

or

iov[0].iov_base = header;
iov[0].iov_len = sizeof *header;
iov[1].iov_base = elementA;
iov[1].iov_len = sizeof *elementA;
iov[2].iov_base = elementB;
iov[2].iov_len = sizeof *elementB;
iov[3].iov_base = trailer;
iov[3].iov_len = sizeof *trailer;
writev(fd, &iov[0], 4);


This makes it much simpler to marshal synchronous messages and allows
more flexibility in dealing with variable length data elements within
the message format.

If you use read() to receive synchronous messages from the device in
the same format, you can now use poll to do multiplexing of your
synchronous communications along with other file descriptors in
a unified model, without dedicating separate input threads (that’s
a design choice – dependent on how many threads you want to limit
yourself to, or to the time allotments and schedule for the input
threads).

flush - meaningless
etc.

and, now I have a pile of devctl()s to implement…

read block
write block
read/mask/write bits
open processor
change processor mode
query processor mode

etc (there are many).

What have I gained from using the POSIX model? I get told when the
client exits, even if it crashes. I get to publish a name in the file
system name space. I can use standard utilities to perform some
opeations. I’m just not sure if it’s worth the complexity of the
POSIX wrapper for these benefits.

For example, using the POSIX mechanism (assuming you don’t have a
/proc filesystem), people tend to limit the information available.
Look at mqueue. You can use ls -l to look at the queue sizes, but
what about information like number of readers, wait states of readers,
number of writers, wait states of writers, maximum messages in queue,
total bytes queued, queue owner? ls -l won’t give me these, so in
order to get this info, I need another devctl() and a custom tool to
call it. If the original author of mqueue had been working with a
custom interface, he (or she) might have thought to offer this
information. I know that the POSIX mechanism offers endless
flexibility through devctl(), which is really just a way to create a
custom API, but programmers who already give us some information
through standard tools tend not to go to the trouble of making the
custom tools to do the rest of the job.

I’m not trying to slag the POSIX model. I think it’s a Good Thing.
But I do agree with Mitchell that it may not always fit.

Cheers,
Andrew


Andrew Thomas, President, Cogent Real-Time Systems Inc.
2430 Meadowpine Boulevard, Suite 105, Mississauga, Ontario, Canada L5N 6S2
Email: > andrew@cogent.ca > WWW: > http://www.cogent.ca

Steve Furr email: furr@qnx.com
QNX Software Systems, Ltd.

Rennie Allen <rallen@computermotion.com> writes:

These don’t need to be devctls. MsgSend()/Sendfd() will do nicely for
these, if portability is not an issue.

I figure that I might as well write portable code if I am faced with
two otherwise equivalent options.

Hmmm, have you played with neutrino much ? It really isn’t very
complex to do a resmgr.

I’m just getting into writing res managers. I like it so far.

Now to apply the same criteria to creating a completely non-standard
interface. OK, I have created a proprietary interface; what have I
gained ? I saved perhaps 50 lines of code, over doing a resmgr. I
have to do my own name location mechanism (which no other
program/utility will understand), I have to handle resource
reclamation when a client dies (I’m not sure if it is even possible
to reliably do this without handling a close in Neutrino; in QNX 4
it is doable but ugly). If my driver is going to be multi-threaded I
will also have to do my own thread pool management.

Most of this applies to Neutrino, but not QNX4. The name location
mechanism was clear in QNX4. The message interface required almost no
coding. The message type differentiation was by message number in the
first 2 bytes of the message. The client death came in by the same
mechanism. Under QNX4, a custom driver is easy. Under Neutrino,
it’s hard.

I don’t buy the argument that because a developer is using a
standard interface, that they subconsciously limit themselves to the
functionality that the interface can provide. Is this what you are
saying ?

Yes, it is. I used mqueue as an example. The only information
available from mqueue that I have seen is what can be reported by ls.
There is much more information that I would like to see.

You don’t need to create devctls under QNX (for custom API’s);
however, if you want portability it isn’t a bad idea to do so.
Consider that if you build all of your custom API over devctl’s then
it will be no more difficult to port your driver to another Posix
system; and all of your clients will compile and link first time
(assuming that all other aspects are Posix).

Whether I write devctls or custom messages, I will still wrap them in
an API library, and the interface will be the same. It isn’t, in my
opinion, good practise to give the end user a message specification
and let him fill in structures and make raw Send() calls. The POSIX
model has not let me off the hook for writing a custom interface and
API, it has just reduced some of it. The worse the fit between the
actual device driver and the POSIX model, the less use the POSIX model
will be.

I don’t remember disagreeing with Mitchell. I simply made the point
that when a device driver can reasonably be placed in the Posix
interface model, it is more than just a matter of taste whether you
do so or not (there are real quantifiable differences in the utility
of the end result).

Ok. I agree with you here. If the device driver can be reasonably
expressed in terms of the POSIX model, then there is a big advantage
to using the POSIX model. Not all devices fit the POSIX model very
well. Sometimes the effort to fit the sqare peg in the round hole is
just not worth it.

I really like your posting. I think it should go into a FAQ or
technote or something. I’m certainly keeping it. Is anybody out
there collecting particularly useful tidbits of information?

Regards,
Andrew


Andrew Thomas, President, Cogent Real-Time Systems Inc.
2430 Meadowpine Boulevard, Suite 105, Mississauga, Ontario, Canada L5N 6S2
Email: andrew@cogent.ca WWW: http://www.cogent.ca

Andrew Thomas wrote:

I don’t buy the argument that because a developer is using a
standard interface, that they subconsciously limit themselves to the
functionality that the interface can provide. Is this what you are
saying ?

Yes, it is. I used mqueue as an example. The only information
available from mqueue that I have seen is what can be reported by ls.
There is much more information that I would like to see.

Perhaps; however, knowing some of the background of mqueue, I don’t
think the programmer was subconsiously limiting themselves (I believe
it was quite conscious :slight_smile:

You don’t need to create devctls under QNX (for custom API’s);
however, if you want portability it isn’t a bad idea to do so.
Consider that if you build all of your custom API over devctl’s then
it will be no more difficult to port your driver to another Posix
system; and all of your clients will compile and link first time
(assuming that all other aspects are Posix).

Whether I write devctls or custom messages, I will still wrap them in
an API library, and the interface will be the same. It isn’t, in my
opinion, good practise to give the end user a message specification
and let him fill in structures and make raw Send() calls. The POSIX
model has not let me off the hook for writing a custom interface and
API, it has just reduced some of it. The worse the fit between the
actual device driver and the POSIX model, the less use the POSIX model
will be.

Whether you wrap the devctls in your own API or not, the port is just
as easy (since your custom API will compile into a lib, and the client
will successfully link against the unresolved reference to devctl from
your library) on a Posix system.

I don’t remember disagreeing with Mitchell. I simply made the point
that when a device driver can reasonably be placed in the Posix
interface model, it is more than just a matter of taste whether you
do so or not (there are real quantifiable differences in the utility
of the end result).

Ok. I agree with you here. If the device driver can be reasonably
expressed in terms of the POSIX model, then there is a big advantage
to using the POSIX model. Not all devices fit the POSIX model very
well. Sometimes the effort to fit the sqare peg in the round hole is
just not worth it.

I agree. There are cases where it is not worth it; however, typically
if it is worth using any sort of driver model (i.e. rather than building
in the driver through in-line code), it is usually justifiable to make it
a Posix driver.


To succeed in this world it is not enough to be stupid; you must also be
well-mannered. - Voltaire