Subject: Re: RFC: General purpose "general purpose i/o pin" framework
To: None <cgd@broadcom.com>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-kern
Date: 08/13/2002 08:32:35
On Mon, Aug 12, 2002 at 10:26:27PM -0700, cgd@broadcom.com wrote:

Ok, first of all, do you see value in being able to set multiple pins
in a single operation?  That's the point of having the "pins" passed
in as an array.  I think if this *IS* allowed, then it needs to be
qualified with "if you set multiple pins in one operation, the pins
must all belong to the same underlying device" so that the operation
can be atomic.

 > > 	  int gpio_get_val(struct gpio_pin *pins, int npins);
 > > 	  int gpio_set_val(struct gpio_pin *pins, int npins);
 > > 	  int gpio_toggle_val(struct gpio_pin *pins, int npins);
 > 
 > Err, what do these do?  Get and set, OK, I understand, ... but
 > "toggle"?!

Toggle might be used for blinking an LED, for example:

	led_pin.val = 1;
	gpio_set_val(&led_pin, 1);
	for (/* some condition */) {
		/* do something */
		gpio_toggle_val(&led_pin, 1);
		/* do something */
	}
	led_pin.val = 0;
	gpio_set_val(&led_pin, 1);

Yes, I know that this could be done like:

		led_pin.val ^= 1;
		gpio_set_val(&led_pin, 1);

...but I want to expose "toggle" to userland for scripts, and I wanted
to have some sense of consistency.

 > pulse?  "how wide?"  These things, and more, are important to people
 > who fiddle with GPIOs!  8-)

A pulse could be open-coded, right?  Although, as Dan points out, this
can often be quite sensitive to timing...

Ok, so, how about:

	int gpio_pulse(struct gpio_pin *pins, int npins, u_int usec);

used like:

	reset_pin.val = 0;
	gpio_pulse(&reset_pin, 1, 25);

...which would do:

	* Set pin to val (0).
	* Wait 25 microseconds.
	* Set pin to !val (1).
	* Return.

 > > 	  int gpio_get_dir(struct gpio_pin *pins, int npins);
 > > 	  int gpio_set_dir(struct gpio_pin *pins, int npins);
 > 
 > people have e.g. selectable debounce circuits on gpios, it would be
 > good to support that kind of thing.  (hehe.)

Can you give me an idea of what the interface to this should look like?

 > > 	* There will also be some kind of API for saying "interrupt
 > > 	  when this GPIO input pin does something" (configurable
 > > 	  for level or edge), but I haven't really thought too much
 > > 	  about how to handle that yet.  In particular, what IPL
 > > 	  do folks think GPIO pins should be registered at?  Should
 > > 	  they get a new IPL_GPIO (and splgpio())?
 > 
 > hmm.
 > 
 > (1) is this meant to be an internal API which people can use to
 >     control GPIOs used by other drivers?
 > 
 >     "Psst!  hey, buddy, lemme show you my generic bus IDE interface!"
 >     8-)

No.  This would be the kind of scenario where you have a "generic bus
IDE driver", which marks the pins it uses as "off limits" to the GPIO
framework :-)

 >     If so, well, those should use the appropriate (& minimum) levels.
 > 
 >     For others, i dunno...  new, or ... tty?  Looks like a serial line
 >     to me.  8-)

Yah, IPL_SERIAL (probably too high, but ideal for timing-sensitive
applications, and you can always schedule a software interrupt from
here) popped to mind ... it's not really a TTY, but IPL_TTY might
also work.

 > (2) fun things with resource conflicts: sometimes, GPIOs can only be
 >     set in pairs to interrupt!
 > 
 >     need to be sure to document that, really, you definitely sohuld
 >     check those return values!

Yah.

 > (3) edge / level setup.  input sense (high, low) too.

Ah, yah.  Noted :-)

 > > 	* There'll also be a userland API, which takes two forms:
 > > 
 > > 		- An ioctl-based API that looks a lot like the
 > > 		  kernel API.
 > > 
 > > 		- A /dev/gpioN, where N == pin number, which is meant
 > > 		  for easy frobbing by scripts.  The idea is to do:
 > > 
 > > 			echo '1' > /dev/gpio0	# turn pin on
 > > 			echo '0' > /dev/gpio0	# turn pin off
 > > 			echo 't' > /dev/gpio0	# toggle pin
 > > 
 > > 		  Similarly, reading will return a '1' or '0', indicating
 > > 		  the current state.
 > > 
 > > 		  This would allow e.g. easy frobbing of an LED on
 > > 		  an embedded system, setting an error LED if booting
 > > 		  failed, etc.
 > > 		
 > > 		  This idea from Jasper Wallace.
 > 
 > hmm.
 > 
 > things come to mind:
 > 
 > * what if you've got multiple (call 'em a flock!) which control the
 >   same things, and you'd like them to transition at "about" the same
 >   time?
 > 
 >   I don't think this API will allow you to do "at exactly the same
 >   time (modulo RC delay 8-)" even if the HW supports it...  That's
 >   probably OK.  But e.g. multiple syscalls and being context switched
 >   away may make it a long long time.
 > 
 >   Dunno if it's that important.

For the script-control-of-single-pin, yah, it's designed to be a simple
interface for doing simple things from scripts.

The ioctl interface would be able to do multiple pins in a single call,
much like the kernel API.  I.e. the ioctl interface would open /dev/gpio
("the who GPIO block"), whereas scripts would peek/poke values from
/dev/gpioN (individual pins).

I probably didn't make that clear enough in my original mail :-)

 > * similarly, if you've got multiple, it may be annoying to have to
 >   break a single request into N different writes.  (e.g. imagine a
 >   7-segment LCD driver done with GPIOs...  timing not critical, but,
 >   boy, having do split that character into N bits...  it's annoying.)

Yah, it would be nice to be able to manipulate this from a script.  Maybe
I need gpioctl(1) (I was hoping to avoid that, but...)

 > * Re: interrupts: dunno that it's sensible to try to expose them to
 >   userland (or to allow userland to configure GPIOs to raise
 >   interrupts).
 > 
 >   Disregarding the "how do you get the interrupt to the user program,"
 >   what do you do, mask them until the user program does ... something?
 > 
 >   don't think it needs to be done up front.

Yah, the "punt" option :-)

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>