• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "lights"
18 
19 #include <cutils/log.h>
20 
21 #include <stdint.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <pthread.h>
27 
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
30 
31 #include <hardware/lights.h>
32 
33 #define LIGHT_ATTENTION	1
34 #define LIGHT_NOTIFY 	2
35 
36 /******************************************************************************/
37 static struct light_state_t *g_notify;
38 static struct light_state_t *g_attention;
39 static pthread_once_t g_init = PTHREAD_ONCE_INIT;
40 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
41 static int g_backlight = 255;
42 static int g_buttons = 0;
43 struct led_prop {
44     const char *filename;
45     int fd;
46 };
47 
48 struct led {
49     struct led_prop mode;
50     struct led_prop brightness;
51     struct led_prop blink;
52     struct led_prop color;
53     struct led_prop period;
54 };
55 
56 enum {
57     JOGBALL_LED,
58     BUTTONS_LED,
59     AMBER_LED,
60     GREEN_LED,
61     BLUE_LED,
62     RED_LED,
63     LCD_BACKLIGHT,
64     NUM_LEDS,
65 };
66 
67 struct led leds[NUM_LEDS] = {
68     [JOGBALL_LED] = {
69         .brightness = { "/sys/class/leds/jogball-backlight/brightness", 0},
70         .color = { "/sys/class/leds/jogball-backlight/color", 0},
71         .period = { "/sys/class/leds/jogball-backlight/period", 0},
72     },
73     [BUTTONS_LED] = {
74         .brightness = { "/sys/class/leds/button-backlight/brightness", 0},
75     },
76     [RED_LED] = {
77         .brightness = { "/sys/class/leds/red/brightness", 0},
78         .blink = { "/sys/class/leds/red/blink", 0},
79     },
80     [GREEN_LED] = {
81         .brightness = { "/sys/class/leds/green/brightness", 0},
82         .blink = { "/sys/class/leds/green/blink", 0},
83     },
84     [BLUE_LED] = {
85         .brightness = { "/sys/class/leds/blue/brightness", 0},
86         .blink = { "/sys/class/leds/blue/blink", 0},
87     },
88     [AMBER_LED] = {
89         .brightness = { "/sys/class/leds/amber/brightness", 0},
90         .blink = { "/sys/class/leds/amber/blink", 0},
91     },
92     [LCD_BACKLIGHT] = {
93         .brightness = { "/sys/class/leds/lcd-backlight/brightness", 0},
94     },
95 };
96 
97 enum {
98     RGB_BLACK = 0x000000,
99     RGB_RED = 0xFF0000,
100     RGB_AMBER = 0xFFFF00,  /* note this is actually RGB yellow */
101     RGB_GREEN = 0x00FF00,
102     RGB_BLUE = 0x0000FF,
103     RGB_WHITE = 0xFFFFFF,
104     RGB_PINK = 0xFFC0CB,
105     RGB_ORANGE = 0xFFA500,
106     RGB_YELLOW = 0xFFFF00,
107     RGB_PURPLE = 0x800080,
108     RGB_LT_BLUE = 0xADD8E6,
109 };
110 
111 /**
112  * device methods
113  */
114 
init_prop(struct led_prop * prop)115 static int init_prop(struct led_prop *prop)
116 {
117     int fd;
118 
119     prop->fd = -1;
120     if (!prop->filename)
121         return 0;
122     fd = open(prop->filename, O_RDWR);
123     if (fd < 0) {
124         LOGE("init_prop: %s cannot be opened (%s)\n", prop->filename,
125              strerror(errno));
126         return -errno;
127     }
128 
129     prop->fd = fd;
130     return 0;
131 }
132 
close_prop(struct led_prop * prop)133 static void close_prop(struct led_prop *prop)
134 {
135     int fd;
136 
137     if (prop->fd > 0)
138         close(prop->fd);
139     return;
140 }
141 
init_globals(void)142 void init_globals(void)
143 {
144     int i;
145     pthread_mutex_init(&g_lock, NULL);
146 
147     for (i = 0; i < NUM_LEDS; ++i) {
148         init_prop(&leds[i].brightness);
149         init_prop(&leds[i].blink);
150         init_prop(&leds[i].mode);
151         init_prop(&leds[i].color);
152         init_prop(&leds[i].period);
153     }
154     g_attention = malloc(sizeof(struct light_state_t));
155     memset(g_attention, 0, sizeof(*g_attention));
156     g_notify = malloc(sizeof(struct light_state_t));
157     memset(g_notify, 0, sizeof(*g_notify));
158 }
159 
160 static int
write_int(struct led_prop * prop,int value)161 write_int(struct led_prop *prop, int value)
162 {
163     char buffer[20];
164     int bytes;
165     int amt;
166 
167     if (prop->fd < 0)
168         return 0;
169 
170     LOGV("%s %s: 0x%x\n", __func__, prop->filename, value);
171 
172     bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
173     while (bytes > 0) {
174         amt = write(prop->fd, buffer, bytes);
175         if (amt < 0) {
176             if (errno == EINTR)
177                 continue;
178             return -errno;
179         }
180         bytes -= amt;
181     }
182 
183     return 0;
184 }
185 
186 static int
write_rgb(struct led_prop * prop,int red,int green,int blue)187 write_rgb(struct led_prop *prop, int red, int green, int blue)
188 {
189     char buffer[20];
190     int bytes;
191     int amt;
192 
193     if (prop->fd < 0)
194         return 0;
195 
196     LOGV("%s %s: red:%d green:%d blue:%d\n",
197           __func__, prop->filename, red, green, blue);
198 
199     bytes = snprintf(buffer, sizeof(buffer), "%d %d %d\n", red, green, blue);
200     while (bytes > 0) {
201         amt = write(prop->fd, buffer, bytes);
202         if (amt < 0) {
203             if (errno == EINTR)
204                 continue;
205             return -errno;
206         }
207         bytes -= amt;
208     }
209 
210     return 0;
211 }
212 
213 static unsigned int
set_rgb(int red,int green,int blue)214 set_rgb(int red, int green, int blue)
215 {
216     return(((red << 16) & 0x00ff0000) |
217            ((green << 8) & 0x0000ff00) |
218            (blue & 0x000000ff));
219 }
220 
221 static int
is_lit(struct light_state_t const * state)222 is_lit(struct light_state_t const* state)
223 {
224     return state->color & 0x00ffffff;
225 }
226 
227 static int
set_trackball_light(struct light_state_t const * state)228 set_trackball_light(struct light_state_t const* state)
229 {
230     static int trackball_mode = 0;
231     int rc = 0;
232     int mode = state->flashMode;
233     int red, blue, green;
234     int period = 0;
235 
236     if (state->flashMode == LIGHT_FLASH_HARDWARE) {
237         mode = state->flashOnMS;
238         period = state->flashOffMS;
239     }
240     LOGV("%s color=%08x mode=%d period %d\n", __func__,
241         state->color, mode, period);
242 
243 
244     if (mode != 0) {
245         red = (state->color >> 16) & 0xff;
246         green = (state->color >> 8) & 0xff;
247         blue = state->color & 0xff;
248 
249         rc = write_rgb(&leds[JOGBALL_LED].color, red, green, blue);
250         if (rc != 0)
251             LOGE("set color failed rc = %d\n", rc);
252         if (period) {
253             rc = write_int(&leds[JOGBALL_LED].period, period);
254             if (rc != 0)
255                LOGE("set period failed rc = %d\n", rc);
256         }
257     }
258     // If the value isn't changing, don't set it, because this
259     // can reset the timer on the breathing mode, which looks bad.
260     if (trackball_mode == mode) {
261         return 0;
262     }
263     trackball_mode = mode;
264 
265 return write_int(&leds[JOGBALL_LED].brightness, mode);
266 }
267 
268 static void
handle_trackball_light_locked(int type)269 handle_trackball_light_locked(int type)
270 {
271     struct light_state_t *new_state = 0;
272     int attn_mode = 0;
273 
274     if (g_attention->flashMode == LIGHT_FLASH_HARDWARE)
275         attn_mode = g_attention->flashOnMS;
276 
277     LOGV("%s type %d attention %p notify %p\n",
278         __func__, type, g_attention, g_notify);
279 
280     switch (type) {
281         case LIGHT_ATTENTION: {
282             if (attn_mode == 0) {
283                 /* go back to notify state */
284                 new_state = g_notify;
285             } else {
286                new_state = g_attention;
287             }
288         break;
289         }
290         case LIGHT_NOTIFY: {
291             if (attn_mode != 0) {
292                 /* attention takes priority over notify state */
293                 new_state = g_attention;
294             } else {
295                new_state = g_notify;
296             }
297         break;
298         }
299     }
300     if (new_state == 0) {
301         LOGE("%s: unknown type (%d)\n", __func__, type);
302         return;
303     }
304     LOGV("%s new state %p\n", __func__, new_state);
305     set_trackball_light(new_state);
306     return;
307 }
308 
309 static int
rgb_to_brightness(struct light_state_t const * state)310 rgb_to_brightness(struct light_state_t const* state)
311 {
312     int color = state->color & 0x00ffffff;
313     return ((77*((color>>16)&0x00ff))
314             + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
315 }
316 
317 static int
set_light_backlight(struct light_device_t * dev,struct light_state_t const * state)318 set_light_backlight(struct light_device_t* dev,
319         struct light_state_t const* state)
320 {
321     int err = 0;
322     int brightness = rgb_to_brightness(state);
323     LOGV("%s brightness=%d color=0x%08x",
324             __func__,brightness, state->color);
325     pthread_mutex_lock(&g_lock);
326     g_backlight = brightness;
327     err = write_int(&leds[LCD_BACKLIGHT].brightness, brightness);
328     pthread_mutex_unlock(&g_lock);
329     return err;
330 }
331 
332 static int
set_light_keyboard(struct light_device_t * dev,struct light_state_t const * state)333 set_light_keyboard(struct light_device_t* dev,
334         struct light_state_t const* state)
335 {
336     /* nothing to do on mahimahi*/
337     return 0;
338 }
339 
340 static int
set_light_buttons(struct light_device_t * dev,struct light_state_t const * state)341 set_light_buttons(struct light_device_t* dev,
342         struct light_state_t const* state)
343 {
344     int err = 0;
345     int on = is_lit(state);
346     pthread_mutex_lock(&g_lock);
347     g_buttons = on;
348     err = write_int(&leds[BUTTONS_LED].brightness, on?255:0);
349     pthread_mutex_unlock(&g_lock);
350     return err;
351 }
352 
353 static int
set_speaker_light_locked(struct light_device_t * dev,struct light_state_t const * state)354 set_speaker_light_locked(struct light_device_t* dev,
355         struct light_state_t const* state)
356 {
357     int len;
358     unsigned int colorRGB;
359 
360     /* Red = amber_led, blue or green = green_led */
361     colorRGB = state->color & 0xFFFFFF;
362 
363     switch (state->flashMode) {
364         case LIGHT_FLASH_TIMED:
365             LOGV("set_led_state colorRGB=%08X, flashing\n", colorRGB);
366             switch (colorRGB) {
367                 case RGB_RED:
368                     write_int(&leds[RED_LED].blink, 1);
369                     break;
370                 case RGB_AMBER:
371                     write_int(&leds[AMBER_LED].blink, 2);
372                     break;
373                 case RGB_GREEN:
374                     write_int(&leds[GREEN_LED].blink, 1);
375                     break;
376                 case RGB_BLUE:
377                     write_int(&leds[BLUE_LED].blink, 1);
378                     break;
379                 case RGB_BLACK:  /*off*/
380                     write_int(&leds[GREEN_LED].blink, 0);
381                     write_int(&leds[RED_LED].blink, 0);
382                     write_int(&leds[BLUE_LED].blink, 0);
383                     write_int(&leds[AMBER_LED].blink, 0);
384                     break;
385                     break;
386                 default:
387                     LOGE("set_led_state colorRGB=%08X, unknown color\n",
388                           colorRGB);
389                     break;
390             }
391             break;
392         case LIGHT_FLASH_NONE:
393             LOGV("set_led_state colorRGB=%08X, on\n", colorRGB);
394             switch (colorRGB) {
395                case RGB_RED:
396                     /*no support for red solid */
397                case RGB_AMBER:
398                     write_int(&leds[AMBER_LED].brightness, 1);
399                     write_int(&leds[GREEN_LED].brightness, 0);
400                     write_int(&leds[BLUE_LED].brightness, 0);
401                     break;
402                 case RGB_GREEN:
403                     write_int(&leds[GREEN_LED].brightness, 1);
404                     write_int(&leds[AMBER_LED].brightness, 0);
405                     write_int(&leds[BLUE_LED].brightness, 0);
406                    break;
407                 case RGB_BLUE:
408                     write_int(&leds[BLUE_LED].brightness, 1);
409                     write_int(&leds[GREEN_LED].brightness, 0);
410                     write_int(&leds[AMBER_LED].brightness, 0);
411                    break;
412                 case RGB_BLACK:  /*off*/
413                     write_int(&leds[GREEN_LED].brightness, 0);
414                     write_int(&leds[AMBER_LED].brightness, 0);
415                     write_int(&leds[BLUE_LED].brightness, 0);
416                     write_int(&leds[RED_LED].brightness, 0);
417                     break;
418                 default:
419                     LOGE("set_led_state colorRGB=%08X, unknown color\n",
420                           colorRGB);
421                     break;
422             }
423             break;
424         default:
425             LOGE("set_led_state colorRGB=%08X, unknown mode %d\n",
426                   colorRGB, state->flashMode);
427     }
428     return 0;
429 }
430 
431 static int
set_light_battery(struct light_device_t * dev,struct light_state_t const * state)432 set_light_battery(struct light_device_t* dev,
433         struct light_state_t const* state)
434 {
435     pthread_mutex_lock(&g_lock);
436     LOGV("%s mode=%d color=0x%08x",
437             __func__,state->flashMode, state->color);
438     set_speaker_light_locked(dev, state);
439     pthread_mutex_unlock(&g_lock);
440     return 0;
441 }
442 
443 static int
set_light_notifications(struct light_device_t * dev,struct light_state_t const * state)444 set_light_notifications(struct light_device_t* dev,
445         struct light_state_t const* state)
446 {
447     pthread_mutex_lock(&g_lock);
448 
449     LOGV("%s mode=%d color=0x%08x On=%d Off=%d\n",
450             __func__,state->flashMode, state->color,
451             state->flashOnMS, state->flashOffMS);
452     /*
453     ** TODO Allow for user settings of color and interval
454     ** Setting 60% brightness
455     */
456     switch (state->color & 0x00FFFFFF) {
457         case RGB_BLACK:
458             g_notify->color = set_rgb(0, 0, 0);
459             break;
460         case RGB_WHITE:
461             g_notify->color = set_rgb(50, 127, 48);
462             break;
463         case RGB_RED:
464             g_notify->color = set_rgb(141, 0, 0);
465             break;
466         case RGB_GREEN:
467             g_notify->color = set_rgb(0, 141, 0);
468             break;
469         case RGB_BLUE:
470             g_notify->color = set_rgb(0, 0, 141);
471             break;
472         case RGB_PINK:
473             g_notify->color = set_rgb(141, 52, 58);
474             break;
475         case RGB_PURPLE:
476             g_notify->color = set_rgb(70, 0, 70);
477             break;
478         case RGB_ORANGE:
479             g_notify->color = set_rgb(141, 99, 0);
480             break;
481         case RGB_YELLOW:
482             g_notify->color = set_rgb(100, 141, 0);
483             break;
484         case RGB_LT_BLUE:
485             g_notify->color = set_rgb(35, 55, 98);
486             break;
487         default:
488             g_notify->color = state->color;
489             break;
490     }
491 
492     if (state->flashMode != LIGHT_FLASH_NONE) {
493         g_notify->flashMode = LIGHT_FLASH_HARDWARE;
494         g_notify->flashOnMS = 7;
495         g_notify->flashOffMS = (state->flashOnMS + state->flashOffMS)/1000;
496     } else {
497         g_notify->flashOnMS = 0;
498         g_notify->flashOffMS = 0;
499     }
500     handle_trackball_light_locked(LIGHT_NOTIFY);
501 
502     pthread_mutex_unlock(&g_lock);
503     return 0;
504 }
505 
506 static int
set_light_attention(struct light_device_t * dev,struct light_state_t const * state)507 set_light_attention(struct light_device_t* dev,
508         struct light_state_t const* state)
509 {
510     unsigned int colorRGB;
511 
512     LOGV("%s color=0x%08x mode=0x%08x submode=0x%08x",
513             __func__, state->color, state->flashMode, state->flashOnMS);
514 
515     pthread_mutex_lock(&g_lock);
516     /* tune color for hardware*/
517     switch (state->color & 0x00FFFFFF) {
518         case RGB_WHITE:
519             colorRGB = set_rgb(101, 255, 96);
520             break;
521         case RGB_BLUE:
522             colorRGB = set_rgb(0, 0, 235);
523             break;
524         case RGB_BLACK:
525             colorRGB = set_rgb(0, 0, 0);
526             break;
527         default:
528             LOGE("%s colorRGB=%08X, unknown color\n",
529                           __func__, state->color);
530             colorRGB = set_rgb(101, 255, 96);
531             break;
532     }
533     g_attention->flashMode = state->flashMode;
534     g_attention->flashOnMS = state->flashOnMS;
535     g_attention->color = colorRGB;
536     g_attention->flashOffMS = 0;
537     handle_trackball_light_locked(LIGHT_ATTENTION);
538 
539     pthread_mutex_unlock(&g_lock);
540     return 0;
541 }
542 
543 
544 /** Close the lights device */
545 static int
close_lights(struct light_device_t * dev)546 close_lights(struct light_device_t *dev)
547 {
548     int i;
549 
550     for (i = 0; i < NUM_LEDS; ++i) {
551         close_prop(&leds[i].brightness);
552         close_prop(&leds[i].blink);
553         close_prop(&leds[i].mode);
554     }
555 
556     if (dev) {
557         free(dev);
558     }
559     return 0;
560 }
561 
562 
563 /******************************************************************************/
564 
565 /**
566  * module methods
567  */
568 
569 /** Open a new instance of a lights device using name */
open_lights(const struct hw_module_t * module,char const * name,struct hw_device_t ** device)570 static int open_lights(const struct hw_module_t* module, char const* name,
571         struct hw_device_t** device)
572 {
573     int (*set_light)(struct light_device_t* dev,
574             struct light_state_t const* state);
575 
576     if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
577         set_light = set_light_backlight;
578     }
579     else if (0 == strcmp(LIGHT_ID_KEYBOARD, name)) {
580         set_light = set_light_keyboard;
581     }
582     else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {
583         set_light = set_light_buttons;
584     }
585     else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {
586         set_light = set_light_battery;
587     }
588     else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
589         set_light = set_light_notifications;
590     }
591     else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) {
592         set_light = set_light_attention;
593     }
594     else {
595         return -EINVAL;
596     }
597 
598     pthread_once(&g_init, init_globals);
599 
600     struct light_device_t *dev = malloc(sizeof(struct light_device_t));
601     memset(dev, 0, sizeof(*dev));
602 
603     dev->common.tag = HARDWARE_DEVICE_TAG;
604     dev->common.version = 0;
605     dev->common.module = (struct hw_module_t*)module;
606     dev->common.close = (int (*)(struct hw_device_t*))close_lights;
607     dev->set_light = set_light;
608 
609     *device = (struct hw_device_t*)dev;
610     return 0;
611 }
612 
613 
614 static struct hw_module_methods_t lights_module_methods = {
615     .open =  open_lights,
616 };
617 
618 /*
619  * The lights Module
620  */
621 const struct hw_module_t HAL_MODULE_INFO_SYM = {
622     .tag = HARDWARE_MODULE_TAG,
623     .version_major = 1,
624     .version_minor = 0,
625     .id = LIGHTS_HARDWARE_MODULE_ID,
626     .name = "mahimahi lights Module",
627     .author = "Google, Inc.",
628     .methods = &lights_module_methods,
629 };
630