]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/openslug-init/openslug-init-0.10/leds.c
OE tree imported from monotone branch org.openembedded.oz354fam083 at revision 8b12e3...
[familiar-h63xx-build.git] / org.handhelds.familiar / packages / openslug-init / openslug-init-0.10 / leds.c
1  #include <stdio.h>
2  #include <stdlib.h>
3  #include <math.h>
4  #include <errno.h>
5  #include <string.h>
6  #include <endian.h>
7  #include <unistd.h>
8  #include <fcntl.h>
9  #include <sys/ioctl.h>
10  #include "leds.h"
11
12  static int leds;
13  static int reset;
14  static int verbose = 0;
15  enum {
16    off=0, on=1, blink, unknown, transition=unknown
17  };
18
19
20  void init_leds(void)
21  {
22    int i;
23    if ((leds = open("/dev/leds", O_RDWR)) < 0) {
24      int e1 = errno;
25      if (e1 != ENOENT) {
26
27        fprintf(stderr,"Error: Could not open LEDS device file '/dev/leds' : %s\n",
28                strerror(e1));
29        if(e1 == EACCES)
30          fprintf(stderr,"Run as root\n");
31        exit(1);
32      }
33    }
34
35    if (verbose)
36      printf("leds: initialized.\n");
37  }
38
39  void led_ioctl( int cmd, int num )
40  {
41    int i, st;
42
43    if (ioctl(leds, cmd, num) < 0) {
44      int e1 = errno;
45      fprintf(stderr, "leds: ioctl(%d,%d): failed to set leds: %s\n",
46          cmd, num, strerror(e1));
47      exit(1);
48    }
49  }
50
51  void led_set( int led, int state )
52  {
53    switch (state) {
54    case off:   if (!reset) led_ioctl(N2_LM_OFF, led); break;
55    case on:    led_ioctl(N2_LM_ON, led); break;
56    case blink: /* Ensure any previous timer gets deleted first and that
57                 * the LED is in a well known state.
58                 */
59                if (!reset) led_ioctl(N2_LM_OFF, led);
60                led_ioctl(N2_LM_BLINK, led); break;
61    }
62  }
63
64  int led( int ch ) {
65    switch (ch) {
66    case 'r': return LED_RS_RED;
67    case 'g': return LED_RS_GRN;
68    case '1': return LED_DISK1;
69    case '2': return LED_DISK2;
70    case 'A': reset = 1; return LED_ALL;
71    default:  fprintf(stderr, "leds: %c: unknown LED (use r,g,0,1 or A)\n", ch);
72              exit(1);
73    }
74  }
75
76  int main( int argc, char **argv ) 
77  {
78         /* Default: switch green on, red off (-A +g). */
79         if (argc == 1) {
80           verbose = 1;
81           init_leds();
82           led_ioctl(N2_LM_ALL_OFF, 0);
83           led_ioctl(N2_LM_ON, LED_RS_GRN);
84         } else {
85           int i, alt=0, state[PHYS_LEDS];
86           for(i=0; i<PHYS_LEDS; ++i)
87             state[i] = unknown;
88           reset = 0;
89
90           while (--argc > 0) {
91             char *arg = *++argv;
92             int st;
93             if (strcmp(arg, "-v") == 0) {
94               ++verbose;
95               continue;
96             }
97
98             switch (*arg) {
99             case '+': st = on; break;
100             case '-': st = off; break;
101             case '!': st = blink; break;
102             case '/': st = transition; break;
103             default:  fprintf(stderr, "leds: %c: unknown option\n", *arg);
104                       exit(1);
105             }
106
107             if (st != transition) {
108               while (*++arg) {
109                 i = led(*arg);
110                 if (i == LED_ALL)
111                   for (i=0; i<PHYS_LEDS; ++i) state[i] = st;
112                 else
113                   state[i] = st;
114               }
115             } else {
116               int done, newstate[PHYS_LEDS];
117               for(i=0; i<PHYS_LEDS; ++i)
118                 newstate[i] = off;
119               while (*++arg) {
120                 i = led(*arg);
121                 if (i == LED_ALL)
122                   for (i=0; i<PHYS_LEDS; ++i) newstate[i] = on;
123                 else
124                   newstate[i] = on;
125               }
126
127               /* Merge the newstate back in.  This sets 'alt' if going
128                * from an old state of just red to a new of just green
129                * or vice versa (and this is the only way of getting
130                * 'alt')
131                */
132               /* Blink anything which changes from off to on or from
133                * on to off (this ignores anything already blinking).
134                */
135               for (done=i=0; i<PHYS_LEDS; ++i) {
136                 if (state[i] == !newstate[i]) {
137                   done = 1;
138                   state[i] = blink;
139                 }
140               }
141
142               /* Is anything (new) blinking?  If it is then deal
143                * with the red/green case - blinking red,green is
144                * amber, is that what we want?  This could be
145                * improved by a better kernel interface - it would
146                * be nice just to specify on/off times and a start
147                * time for each LED.
148                */
149               if (done) {
150                 if (state[LED_RS_RED] == blink && state[LED_RS_GRN] == blink &&
151                     newstate[LED_RS_RED] == !newstate[LED_RS_GRN]) {
152                   /* Kernel bug: must switch off r and g first. */
153                   alt = 1;
154                 }
155               } else {
156                 for (i=0; i<PHYS_LEDS; ++i) {
157                   if (newstate[i] == on) {
158                     state[i] = blink;
159                   }
160                 }
161               }
162             }
163           }
164
165           /* Go through the list making the required settings.  'alt' is
166            * special.  'reset' means A was given and all the settings are
167            * known.
168            */
169           init_leds();
170           if (reset)
171             led_ioctl(N2_LM_ALL_OFF, 0);
172           if (alt) {
173             /* Turn the leds off first to get to a known state. */
174             led_set(LED_RS_GRN, off);
175             led_set(LED_RS_RED, off);
176             led_ioctl(N2_LM_ALT, LED_RS_RED);
177           } else {
178             /* KERNEL BUG: setting the green timer zaps the red behaviour
179              * to toggle the green, therefore if red blink is set before
180              * green blink no blink will happen!
181              */
182             led_set(LED_RS_GRN, state[LED_RS_GRN]);
183             led_set(LED_RS_RED, state[LED_RS_RED]);
184           }
185           led_set(LED_DISK1, state[LED_DISK1]);
186           led_set(LED_DISK2, state[LED_DISK2]);
187         }
188
189         return 0;
190  }