1c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare/*
2c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * Copyright (C) 2008 The Android Open Source Project
3c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare *
4c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * Licensed under the Apache License, Version 2.0 (the "License");
5c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * you may not use this file except in compliance with the License.
6c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * You may obtain a copy of the License at
7c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare *
8c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare *      http://www.apache.org/licenses/LICENSE-2.0
9c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare *
10c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * Unless required by applicable law or agreed to in writing, software
11c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * distributed under the License is distributed on an "AS IS" BASIS,
12c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * See the License for the specific language governing permissions and
14c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * limitations under the License.
15c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare */
16c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
17c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare/*
18c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare * Based on htc/flounder/lights/lights.h
19c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare */
20c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
21c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare#define LOG_TAG "lights"
22c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
23c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare#include <malloc.h>
24c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare#include <string.h>
25c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare#include <unistd.h>
26c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare#include <errno.h>
27748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca#include <cutils/log.h>
28c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare#include <hardware/lights.h>
29c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare#include <hardware/hardware.h>
30748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca#include <gpio.h>
31748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
32748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/* List of supported lights */
33748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscatypedef enum {
343dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    NOTIFICATIONS_TYPE,
353dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    LIGHTS_TYPE_NUM
36748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca} light_type_t;
37748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
38748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/* Light device data structure */
39748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastruct light_device_ext_t {
403dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    /* Base device */
413dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct light_device_t base_dev;
423dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    /* Physical pin */
433dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int pin;
443dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    /* Current state of the light device */
453dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct light_state_t state;
463dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    /* Number of device references */
473dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int refs;
483dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    /* Synchronization attributes */
493dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_t flash_thread;
503dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_cond_t flash_cond;
513dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_t flash_signal_mutex;
523dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_t write_mutex;
53f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca    /* Transform function to apply on value */
54f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca    int (*transform)(int);
55748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca};
56748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
57748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int64_t const ONE_MS_IN_NS = 1000000LL;
58748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int64_t const ONE_S_IN_NS = 1000000000LL;
59748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
60748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
61f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca * Platform version strings used to identify board versions
62748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
63f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Muscastatic char * const EDISON_ARDUINO_PLATFORM_VERSION = "arduino";
64f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Muscastatic char * const MINNOWBOARD_TURBOT_PLATFORM_VERSION = "Turbot";
65748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
66748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
67748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Pin constants
6839bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca * Please add a pin to EDISON_ARDUINO_PINS, EDISON_MINIBOARD_PINS &
6939bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca * MINNOWBOARD_MAX_PINS when you add a new light type
70748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
7139bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Muscastatic int const EDISON_ARDUINO_PINS[LIGHTS_TYPE_NUM] = {13};
7239bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Muscastatic int const EDISON_MINIBOARD_PINS[LIGHTS_TYPE_NUM] = {31};
7339bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Muscastatic int const MINNOWBOARD_MAX_PINS[LIGHTS_TYPE_NUM] = {21};
74f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Muscastatic int const MINNOWBOARD_TURBOT_PINS[LIGHTS_TYPE_NUM] = {27};
75748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
76748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
77748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Array of light devices with write_mutex statically initialized
78748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * to be able to synchronize the open_lights & close_lights functions
79748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
80748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastruct light_device_ext_t light_devices[] = {
813dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    [ 0 ... (LIGHTS_TYPE_NUM - 1) ] = { .write_mutex = PTHREAD_MUTEX_INITIALIZER }
82748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca};
83c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
84748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
85748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Set the GPIO value
86748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param pin physical pin of the GPIO
87748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param value what value to set
88748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
89748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
90748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int set_gpio_value(int pin, int value)
91748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
923dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    mraa_gpio_context gpio = NULL;
933dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int rc = 0;
94748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
953dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if ((value != 0) && (value != 1)) {
963dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
973dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
98c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
993dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    gpio = mraa_gpio_init(pin);
1003dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (gpio == NULL) {
1013dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EPERM;
1023dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
103748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
1043dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (mraa_gpio_dir(gpio, MRAA_GPIO_OUT) != MRAA_SUCCESS) {
1053dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        rc = EPERM;
1063dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto close_gpio;
1073dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
108748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
1093dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (mraa_gpio_write(gpio, value) != MRAA_SUCCESS) {
1103dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        rc = EPERM;
1113dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
112c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
113748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscaclose_gpio:
1143dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (mraa_gpio_close(gpio) != MRAA_SUCCESS) {
1153dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        rc = EPERM;
1163dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
117748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
1183dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return rc;
119748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
120748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
121748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
122f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca * Invert value
123f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca * @param value what value to invert
124f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca * @return value inverted
125f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca */
126f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Muscastatic int invert_value(int value) {
127f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca    return value ? 0 : 1;
128f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca}
129f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca
130f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca/*
131748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Get current timestamp in nanoseconds
132748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return time in nanoseconds
133748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
134748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscaint64_t get_timestamp_monotonic()
135c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
1365b95432c01a78c364aa029b05eeddb570d1828f2Constantin Musca    struct timespec ts = {0, 0};
137748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
1383dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
1393dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return ONE_S_IN_NS * ts.tv_sec + ts.tv_nsec;
1403dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
141748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
1423dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return -1;
143748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
144748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
145748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
146748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Populates a timespec data structure from a int64_t timestamp
147748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param out what timespec to populate
148748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param target_ns timestamp in nanoseconds
149748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
150748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscavoid set_timestamp(struct timespec *out, int64_t target_ns)
151748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
1523dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    out->tv_sec  = target_ns / ONE_S_IN_NS;
1533dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    out->tv_nsec = target_ns % ONE_S_IN_NS;
154748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
155748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
156748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
157748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * pthread routine which flashes an LED
158748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param flash_param light device pointer
159748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
160748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic void * flash_routine (void *flash_param)
161748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
1623dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct light_device_ext_t *dev = (struct light_device_ext_t *)flash_param;
1633dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct light_state_t *flash_state;
1643dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int color = 0, rc = 0;
1653dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct timespec target_time;
1663dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int64_t timestamp, period;
1673dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
1683dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (dev == NULL) {
1693dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: Cannot flash a NULL light device", __func__);
1703dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return NULL;
1713dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
1723dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
1733dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    flash_state = &dev->state;
1743dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
1753dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_lock(&dev->flash_signal_mutex);
1763dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
1773dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    color = flash_state->color;
1783dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
1793dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    /* Light flashing loop */
1803dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    while (flash_state->flashMode) {
1813dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        rc = set_gpio_value(dev->pin, color);
1823dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        if (rc != 0) {
1833dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            ALOGE("%s: Cannot set light color", __func__);
1843dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            goto mutex_unlock;
1853dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        }
1863dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
1873dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        timestamp = get_timestamp_monotonic();
1883dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        if (timestamp < 0) {
1893dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            ALOGE("%s: Cannot get time from monotonic clock", __func__);
1903dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            goto mutex_unlock;
1913dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        }
1923dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
1933dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        if (color) {
1943dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            color = 0;
1953dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            period = flash_state->flashOnMS * ONE_MS_IN_NS;
1963dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        } else {
1973dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            color = 1;
1983dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            period = flash_state->flashOffMS * ONE_MS_IN_NS;
1993dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        }
2003dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2013dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        /* check for overflow */
2023dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        if (timestamp > LLONG_MAX - period) {
2033dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            ALOGE("%s: Timestamp overflow", __func__);
2043dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            goto mutex_unlock;
2053dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        }
2063dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2073dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        timestamp += period;
2083dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2093dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        /* sleep until target_time or the cond var is signaled */
2103dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        set_timestamp(&target_time, timestamp);
2113dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        rc = pthread_cond_timedwait(&dev->flash_cond, &dev->flash_signal_mutex, &target_time);
2123dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        if ((rc != 0) && (rc != ETIMEDOUT)) {
2133dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            ALOGE("%s: pthread_cond_timedwait returned an error", __func__);
2143dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            goto mutex_unlock;
2153dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        }
2163dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
217748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
218748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscamutex_unlock:
2193dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_unlock(&dev->flash_signal_mutex);
220748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
2213dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return NULL;
222c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare}
223c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
224748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
225748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Check lights flash state
226748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param state pointer to the state to check
227748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
228748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
229748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int check_flash_state(struct light_state_t const *state)
230748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
2313dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int64_t ns = 0;
2323dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2333dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if ((state->flashOffMS < 0) || (state->flashOnMS < 0)) {
2343dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
2353dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
2363dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2373dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if ((state->flashOffMS == 0) && (state->flashOnMS) == 0) {
2383dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
2393dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
2403dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2413dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    /* check for overflow in ns */
2423dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    ns = state->flashOffMS * ONE_MS_IN_NS;
2433dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (ns / ONE_MS_IN_NS != state->flashOffMS) {
2443dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
2453dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
2463dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    ns = state->flashOnMS * ONE_MS_IN_NS;
2473dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (ns / ONE_MS_IN_NS != state->flashOnMS) {
2483dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
2493dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
2503dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2513dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return 0;
252748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
253c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
254748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
255748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Generic function for setting the state of the light
256748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param base_dev light device data structure
257748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param state what state to set
258748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
259748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
260748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int set_light_generic(struct light_device_t *base_dev,
2613dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        struct light_state_t const *state)
262c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
2633dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct light_device_ext_t *dev = (struct light_device_ext_t *)base_dev;
2643dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct light_state_t *current_state;
2653dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int rc = 0;
2663dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2673dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (dev == NULL) {
2683dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: Cannot set state for NULL device", __func__);
2693dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
2703dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
2713dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2723dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    current_state = &dev->state;
2733dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2743dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_lock(&dev->write_mutex);
2753dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2763dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (dev->refs == 0) {
2773dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: The light device is not opened", __func__);
2783dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_mutex_unlock(&dev->write_mutex);
2793dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
2803dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
2813dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2823dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    ALOGV("%s: flashMode:%x, color:%x", __func__, state->flashMode, state->color);
2833dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2843dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (current_state->flashMode) {
2853dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        /* destroy flashing thread */
2863dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_mutex_lock(&dev->flash_signal_mutex);
2873dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        current_state->flashMode = LIGHT_FLASH_NONE;
2883dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_cond_signal(&dev->flash_cond);
2893dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_mutex_unlock(&dev->flash_signal_mutex);
2903dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_join(dev->flash_thread, NULL);
2913dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
2923dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
2933dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    *current_state = *state;
294f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca    if (dev->transform != NULL) {
295f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca        current_state->color = dev->transform(current_state->color);
296f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca    }
2973dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
298f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca    if (current_state->flashMode) {
2993dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        /* start flashing thread */
3003dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        if (check_flash_state(current_state) == 0) {
3013dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            rc = pthread_create(&dev->flash_thread, NULL,
3023dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca                    flash_routine, (void *)dev);
3033dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            if (rc != 0) {
3043dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca                ALOGE("%s: Cannot create flashing thread", __func__);
3053dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca                current_state->flashMode = LIGHT_FLASH_NONE;
3063dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            }
3073dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        } else {
3083dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            ALOGE("%s: Flash state is invalid", __func__);
3093dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            current_state->flashMode = LIGHT_FLASH_NONE;
3103dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        }
3113dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    } else {
312f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca        rc = set_gpio_value(dev->pin, current_state->color);
3133dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        if (rc != 0) {
3143dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            ALOGE("%s: Cannot set light color.", __func__);
3153dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        }
3163dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
3173dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3183dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_unlock(&dev->write_mutex);
3193dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3203dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return rc;
321748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
322748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
323748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
324748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Initialize light synchronization resources
325748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param cond what condition variable to initialize
326748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param signal_mutex what mutex (associated with the condvar) to initialize
327748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
328748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
329748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int init_light_sync_resources(pthread_cond_t *cond,
3303dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_mutex_t *signal_mutex)
331748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
3323dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int rc = 0;
3333dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_condattr_t condattr;
3343dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3353dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    rc = pthread_condattr_init(&condattr);
3363dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (rc != 0) {
3373dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: Cannot initialize the pthread condattr", __func__);
3383dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return rc;
3393dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
3403dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3413dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    rc = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
3423dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (rc != 0) {
3433dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: Cannot set the clock of condattr to monotonic", __func__);
3443dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto destroy_condattr;
3453dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
3463dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3473dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    rc = pthread_cond_init(cond, &condattr);
3483dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (rc != 0) {
3493dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: Cannot intialize the pthread structure", __func__);
3503dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto destroy_condattr;
3513dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
3523dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3533dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    rc = pthread_mutex_init(signal_mutex, NULL);
3543dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (rc != 0) {
3553dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: Cannot initialize the mutex associated with the pthread cond", __func__);
3563dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto destroy_cond;
3573dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
3583dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3593dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_condattr_destroy(&condattr);
3603dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return rc;
361748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
362748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscadestroy_cond:
3633dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_cond_destroy(cond);
364748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscadestroy_condattr:
3653dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_condattr_destroy(&condattr);
3663dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return rc;
367748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
368748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
369748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
370748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Free light synchronization resources
371748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param cond what condition variable to free
372748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param signal_mutex what mutex (associated with the condvar) to free
373748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
374748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic void free_light_sync_resources(pthread_cond_t *cond,
3753dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_mutex_t *signal_mutex)
376748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
3773dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_destroy(signal_mutex);
3783dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_cond_destroy(cond);
379748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
380748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
381748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
382748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Close the lights module
383748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param base_dev light device data structure
384748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
385748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
386748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int close_lights(struct light_device_t *base_dev)
387748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
3883dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct light_device_ext_t *dev = (struct light_device_ext_t *)base_dev;
3893dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int rc = 0;
3903dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3913dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (dev == NULL) {
3923dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: Cannot deallocate a NULL light device", __func__);
3933dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
3943dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
3953dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3963dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_lock(&dev->write_mutex);
3973dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
3983dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (dev->refs == 0) {
3993dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        /* the light device is not open */
4003dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        rc = EINVAL;
4013dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto mutex_unlock;
4023dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    } else if (dev->refs > 1) {
4033dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto dec_refs;
4043dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
4053dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
4063dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (dev->state.flashMode) {
4073dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        /* destroy flashing thread */
4083dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_mutex_lock(&dev->flash_signal_mutex);
4093dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        dev->state.flashMode = LIGHT_FLASH_NONE;
4103dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_cond_signal(&dev->flash_cond);
4113dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_mutex_unlock(&dev->flash_signal_mutex);
4123dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        pthread_join(dev->flash_thread, NULL);
4133dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
4143dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
4153dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    free_light_sync_resources(&dev->flash_cond,
4163dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca            &dev->flash_signal_mutex);
417748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
418748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscadec_refs:
4193dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    dev->refs--;
420748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
421748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscamutex_unlock:
4223dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_unlock(&dev->write_mutex);
423748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
4243dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return rc;
425c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare}
426c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
427748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
428748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Module initialization routine which detects the LEDs' GPIOs
429748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param type light device type
430748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
431748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
432748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int init_module(int type)
433c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
434f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca    const char *platform_version = NULL;
4353dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
4363dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (type < 0 || type >= LIGHTS_TYPE_NUM) {
4373dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
4383dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
4393dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
440f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca    light_devices[type].transform = NULL;
441f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca
44239bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca    switch(mraa_get_platform_type()) {
44339bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca        case MRAA_INTEL_EDISON_FAB_C:
444f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca            platform_version = mraa_get_platform_version(MRAA_MAIN_PLATFORM_OFFSET);
445f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca            if ((platform_version != NULL) && (strncmp(platform_version,
446f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca                    EDISON_ARDUINO_PLATFORM_VERSION,
447f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca                    strlen(EDISON_ARDUINO_PLATFORM_VERSION)) == 0)) {
44839bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca                light_devices[type].pin = EDISON_ARDUINO_PINS[type];
44939bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca            } else {
45039bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca                light_devices[type].pin = EDISON_MINIBOARD_PINS[type];
45139bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca            }
45239bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca            break;
45339bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca        case MRAA_INTEL_MINNOWBOARD_MAX:
454f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca            platform_version = mraa_get_platform_version(MRAA_MAIN_PLATFORM_OFFSET);
455f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca            if ((platform_version != NULL) && (strncmp(platform_version,
456f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca                    MINNOWBOARD_TURBOT_PLATFORM_VERSION,
457f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca                    strlen(MINNOWBOARD_TURBOT_PLATFORM_VERSION)) == 0)) {
458f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca                light_devices[type].pin = MINNOWBOARD_TURBOT_PINS[type];
459f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca                light_devices[type].transform = invert_value;
460f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca            } else {
461f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca                light_devices[type].pin = MINNOWBOARD_MAX_PINS[type];
462f39cee21fe73ee76b8d5f5ef5bc9746ac1d992f3Constantin Musca            }
46339bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca            break;
46439bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca        default:
46539bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca            ALOGE("%s: Hardware platform not supported", __func__);
46639bbf3e39686a35fbc19b1b9b3d2f1e03a8f72c6Constantin Musca            return EINVAL;
4673dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
4683dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca
4693dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return 0;
470c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare}
471c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
472748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
473748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Open a new lights device instance by name
474748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param module associated hw module data structure
475748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param name lights device name
476748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param device where to store the pointer of the allocated device
477748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
478748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
479c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Bearestatic int open_lights(const struct hw_module_t *module, char const *name,
4803dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        struct hw_device_t **device)
481c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
4823dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    struct light_device_ext_t *dev;
4833dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    int rc = 0, type = -1;
484c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
4853dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    ALOGV("%s: Opening %s lights module", __func__, name);
486748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
4873dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
4883dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        type = NOTIFICATIONS_TYPE;
4893dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    } else {
4903dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        return EINVAL;
4913dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
492c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
4933dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    dev = (struct light_device_ext_t *)(light_devices + type);
494c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
4953dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_lock(&dev->write_mutex);
496c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
4973dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (dev->refs != 0) {
4983dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        /* already opened; nothing to do */
4993dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto inc_refs;
5003dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
501748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
5023dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    rc = init_module(type);
5033dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (rc != 0) {
5043dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        ALOGE("%s: Failed to initialize lights module", __func__);
5053dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto mutex_unlock;
5063dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
507c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
5083dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    rc = init_light_sync_resources(&dev->flash_cond,
5093dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca                &dev->flash_signal_mutex);
5103dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    if (rc != 0) {
5113dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca        goto mutex_unlock;
5123dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    }
513748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
5143dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    dev->base_dev.common.tag = HARDWARE_DEVICE_TAG;
5153dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    dev->base_dev.common.version = 0;
5163dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    dev->base_dev.common.module = (struct hw_module_t *)module;
5173dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    dev->base_dev.common.close = (int (*)(struct hw_device_t *))close_lights;
5183dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    dev->base_dev.set_light = set_light_generic;
519748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
520748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscainc_refs:
5213dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    dev->refs++;
5223dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    *device = (struct hw_device_t *)dev;
523c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
524748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscamutex_unlock:
5253dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    pthread_mutex_unlock(&dev->write_mutex);
5263dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    return rc;
527c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare}
528c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
529c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Bearestatic struct hw_module_methods_t lights_methods =
530c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
5313dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    .open =  open_lights,
532c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare};
533c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
534c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Bearestruct hw_module_t HAL_MODULE_INFO_SYM =
535c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
5363dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    .tag = HARDWARE_MODULE_TAG,
5373dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    .version_major = 1,
5383dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    .version_minor = 0,
5393dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    .id = LIGHTS_HARDWARE_MODULE_ID,
5403dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    .name = "Edison lights module",
5413dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    .author = "Intel",
5423dc1f7b573db70eb1d2d37a59080117997ed60b4Constantin Musca    .methods = &lights_methods,
543c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare};
544