Re: best way to handle LEDs

linux-os (Dick Johnson)
2005-11-03T16:38:56Z

On Thu, 3 Nov 2005, Russell King wrote:

> On Thu, Nov 03, 2005 at 04:34:45PM +0100, Vojtech Pavlik wrote:
>> On Thu, Nov 03, 2005 at 02:49:04PM +0000, Russell King wrote:
>>> On Thu, Nov 03, 2005 at 10:57:26AM +0100, Pavel Machek wrote:
>>>> Hi!
>>>>
>>>>>> Except the led code that is being proposed CAN sit on top of a generic
>>>>>> GPIO layer.
>>>>>
>>>>> I also have issues with a generic GPIO layer. As I mentioned in the
>>>>> past, there's serious locking issues with any generic abstraction of
>>>>> GPIOs.
>>>>>
>>>>> 1. You want to be able to change GPIO state from interrupts. This
>>>>> implies you can not sleep in GPIO state changing functions.
>>>>>
>>>>> 2. Some GPIOs are implemented on I2C devices. This means that to
>>>>> change state, you must sleep.
>>>>
>>>> Can't you just busywait? Yes, it is ugly in general, but perhaps it
>>>> is better than alternatives...
>>>
>>> Does the i2c layer support busy waiting or are you suggesting something
>>> else?
>>
>> It usually doesn't support anything else. At least on the controllers
>> I've seen the drivers for.
>
> I think you misunderstand me. Please read:
>
> http://dictionary.reference.com/search?q=busywait
>
> Since the i2c transfer functions allow drivers to sleep (and some do)
> you can't "just busywait" without modifying the i2c layer to tell
> drivers to busy wait instead of sleeping.
>
> --
> Russell King
> Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
> maintainer of: 2.6 Serial core

The whole thing is pretty easy. The interrupt code just signals
a task to do whatever...

For example:

Interrupt service routine or anything else, sets the
value in 'what' and 'which'. It then executes
(in demo code) wake_up_interruptible(info->twait);
... and coutinues whatever it was doing. The daemon wakes
up (whenever) and, in process-context does whatever was
you wanted it to do.

extern void turn_led_on(int led); // Can sleep
extern void turn_len_off(int len); // Can sleep

enum WHAT {
TURN_LED_ON,
TURN_LED_OFF,
FLASH_LED,
STOP_FLASH };

static WHAT what;
static int which;

static int local_kernel_thread(void *unused) {
daemonize(name);
for(;;) {
set_current_state(TASK_INTERRUPTIBLE);
if(signal_pending(current))
complete_and_exit(&info->quit, 0);
interruptible_sleep_on(&info->twait);
set_current_state(TASK_RUNNING);
preempt_disable(); // So we get this done soon
switch(what) {
case TURN_LED_ON:
turn_led_on(which);
break;
case TURN_LEN_OFF:
turn_led_off(which);
break;
case FLASH_LED:
start_timer_queue_for_flashing_led(which); // Can sleep
break;
case STOP_FLASH:
stop_timer_queue_for_flashing_led(which); // Can sleep
break;
default:
printk("Brain fart\n");
}
preempt_enable();
}
return 0;
}

You never want to busy-wait for some "bells and whistles". You
just make a bells-and-whistles kernel daemon that does whatever
you want.

Cheers,
Dick Johnson
Penguin : Linux version 2.6.13.4 on an i686 machine (5589.55 BogoMips).
Warning : 98.36% of all statistics are fiction.
.

****************************************************************
The information transmitted in this message is confidential and may be privileged. Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited. If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.