Subject: Re: device driver questions
To: None <nathanw@MIT.EDU>
From: Brook Milligan <brook@biology.nmsu.edu>
List: current-users
Date: 10/05/2001 12:23:52
Thanks for the response.  This is very helpful and has gotten me
thinking along the right direction (I hope).

   The first thing that comes to mind is that the flag/idle loop
   communication might be better handled with the tsleep()/wakeup()
   interface, so as not to unnecessairly block other processing. Whether
   this is a good idea is somewhat timing-related; how long does the
   device take to respond? 

tsleep()/wakeup() sounds like just the right thing.  I note that the
dev/if_wi.c driver uses an idle loop instead, though.  Is this because
the response will come so soon that tsleep() is not worth it?  How
long must the expected wait be before tsleep() is preferable?

In this case, I'm not sure how quickly the device will respond.  It
is, however, directly on the isa bus so there should be reasonably
quick response.  I'm looking for the information, though.

   Yes, this is trickier. One thing to be careful about is avoiding a
   race condition between the host-initiated and device-initiated
   communication; what happens if the device decides to send a byte
   between when the host has set the "data wanted" flag and actually
   sends the byte? Is there really no other way of determining whether a
   byte from the device is a response or a new request?

I think I have the race condition figured out.  The identity of the
first byte back from the device should always differentiate between
whether the device thinks it is initiating the exchange or whether it
thinks the host is.

   What is "significant action"? Again, it's a question of timing. If you
   really need to do a lot of work (digging through files or something),
   or can't do it at interrupt context, or can't afford the delay of
   deferring to userland, you might consider setting up a kernel process
   to handle such requests (see kthread(9)). It would help to know what
   this device is, as well as its expected usage model.

This device is an intelligent power supply.  Most commands will be
initiated rarely by the host to query its state.  Even more rarely the
supply will notify the host of a change in state.  Given the frequency
of these events, I doubt race conditions will be a problem in
practice, though I appreciate that good design is always best.  The
"significant action" that might be required upon device notification
of a state change will involve further queries to the device to figure
out the details of the state change and what to do about it.

Based on the tsleep()/wakeup() suggestions, here is my current design
idea.  Additional comments welcome and encouraged.

- driver interrupt handler:
  o reads a character from the device
  o differentiates between different cases based on flags and nature
    of byte read
  o uses wakeup() to restart one of several different processes to
    handle the character

- driver function writing commands to device:
  o sets some flags to help interrrupt handler figure out what is
    happening
  o writes a byte
  o calls tsleep()
  o on wakeup(), writes next character, ...

- driver function receiving asynchronous commands from device:
  o calls sleep()
  o on wakeup(), reads command from device

- userland daemon:
  o designed to handle all the decisions for the "significant action"
  o issues an ioctl to the driver
  o ioctl() calls the function to read a command from device, and
    hence is stopped by sleep() in the driver for a long time
  o on wakeup() to the driver, the command is read by the driver and
    returned to the daemon
  o the daemon figures out what to do and does it

Does this seem like the proper design?  Again, please help me refine
this so I can become more proficient at writing drivers.

Thanks for your help.

Cheers,
Brook