lights.c revision 748d6cd3dec472369f0de2eab0fff7a1e80d77ab
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 {
34748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	NOTIFICATIONS_TYPE,
35748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	LIGHTS_TYPE_NUM
36748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca} light_type_t;
37748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
38748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/* Light device data structure */
39748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastruct light_device_ext_t {
40748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	/* Base device */
41748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct light_device_t base_dev;
42748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	/* Physical pin */
43748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int pin;
44748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	/* Current state of the light device */
45748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct light_state_t state;
46748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	/* Number of device references */
47748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int refs;
48748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	/* Synchronization attributes */
49748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_t flash_thread;
50748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_cond_t flash_cond;
51748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_t flash_signal_mutex;
52748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_t write_mutex;
53748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca};
54748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
55748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int64_t const ONE_MS_IN_NS = 1000000LL;
56748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int64_t const ONE_S_IN_NS = 1000000000LL;
57748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
58748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
59748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Raw pin number for identifying the TRI_STATE_ALL GPIO
60748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * used to determine if we're on an Arduino board
61748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
62748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int const TRI_STATE_ALL_GPIO_RAW_PIN = 214;
63748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
64748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
65748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Pin constants
66748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Please add a pin to ARDUINO_PINS & NON_ARDUINO_PINS
67748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * when you add a new light type
68748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
69748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int const ARDUINO_PINS[LIGHTS_TYPE_NUM] = {13};
70748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int const NON_ARDUINO_PINS[LIGHTS_TYPE_NUM] = {31};
71748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
72748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
73748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Array of light devices with write_mutex statically initialized
74748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * to be able to synchronize the open_lights & close_lights functions
75748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
76748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastruct light_device_ext_t light_devices[] = {
77748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	[ 0 ... (LIGHTS_TYPE_NUM - 1) ] = { .write_mutex = PTHREAD_MUTEX_INITIALIZER }
78748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca};
79c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
80748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
81748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Set the GPIO value
82748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param pin physical pin of the GPIO
83748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param value what value to set
84748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
85748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
86748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int set_gpio_value(int pin, int value)
87748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
88748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	mraa_gpio_context gpio = NULL;
89748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int rc = 0;
90748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
91748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if ((value != 0) && (value != 1)) {
92748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
93748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
94c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
95748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	gpio = mraa_gpio_init(pin);
96748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (gpio == NULL) {
97748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EPERM;
98748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
99748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
100748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (mraa_gpio_dir(gpio, MRAA_GPIO_OUT) != MRAA_SUCCESS) {
101748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		rc = EPERM;
102748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto close_gpio;
103748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
104748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
105748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (mraa_gpio_write(gpio, value) != MRAA_SUCCESS) {
106748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		rc = EPERM;
107748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
108c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
109748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscaclose_gpio:
110748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (mraa_gpio_close(gpio) != MRAA_SUCCESS) {
111748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		rc = EPERM;
112748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
113748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
114748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return rc;
115748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
116748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
117748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
118748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Get current timestamp in nanoseconds
119748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return time in nanoseconds
120748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
121748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscaint64_t get_timestamp_monotonic()
122c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
123748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct timespec ts = {0};
124748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
125748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
126748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return ONE_S_IN_NS * ts.tv_sec + ts.tv_nsec;
127748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
128748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
129748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return -1;
130748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
131748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
132748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
133748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Populates a timespec data structure from a int64_t timestamp
134748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param out what timespec to populate
135748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param target_ns timestamp in nanoseconds
136748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
137748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscavoid set_timestamp(struct timespec *out, int64_t target_ns)
138748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
139748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	out->tv_sec  = target_ns / ONE_S_IN_NS;
140748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	out->tv_nsec = target_ns % ONE_S_IN_NS;
141748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
142748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
143748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
144748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * pthread routine which flashes an LED
145748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param flash_param light device pointer
146748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
147748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic void * flash_routine (void *flash_param)
148748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
149748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct light_device_ext_t *dev = (struct light_device_ext_t *)flash_param;
150748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct light_state_t *flash_state;
151748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int color = 0, rc = 0;
152748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct timespec target_time;
153748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int64_t timestamp, period;
154748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
155748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (dev == NULL) {
156748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		ALOGE("%s: Cannot flash a NULL light device", __func__);
157748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return NULL;
158748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
159748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
160748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	flash_state = &dev->state;
161748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
162748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_lock(&dev->flash_signal_mutex);
163748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
164748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	color = flash_state->color;
165748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
166748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	/* Light flashing loop */
167748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	while (flash_state->flashMode) {
168748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		rc = set_gpio_value(dev->pin, color);
169748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		if (rc != 0) {
170748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			ALOGE("%s: Cannot set light color", __func__);
171748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			goto mutex_unlock;
172748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		}
173748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
174748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		timestamp = get_timestamp_monotonic();
175748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		if (timestamp < 0) {
176748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			ALOGE("%s: Cannot get time from monotonic clock", __func__);
177748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			goto mutex_unlock;
178748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		}
179748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
180748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		if (color) {
181748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			color = 0;
182748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			period = flash_state->flashOnMS * ONE_MS_IN_NS;
183748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		} else {
184748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			color = 1;
185748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			period = flash_state->flashOffMS * ONE_MS_IN_NS;
186748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		}
187748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
188748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		/* check for overflow */
189748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		if (timestamp > LLONG_MAX - period) {
190748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			ALOGE("%s: Timestamp overflow", __func__);
191748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			goto mutex_unlock;
192748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		}
193748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
194748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		timestamp += period;
195748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
196748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		/* sleep until target_time or the cond var is signaled */
197748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		set_timestamp(&target_time, timestamp);
198748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		rc = pthread_cond_timedwait(&dev->flash_cond, &dev->flash_signal_mutex, &target_time);
199748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		if ((rc != 0) && (rc != ETIMEDOUT)) {
200748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			ALOGE("%s: pthread_cond_timedwait returned an error", __func__);
201748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			goto mutex_unlock;
202c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare		}
203c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	}
204748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
205748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscamutex_unlock:
206748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_unlock(&dev->flash_signal_mutex);
207748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
208748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return NULL;
209c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare}
210c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
211748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
212748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Check lights flash state
213748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param state pointer to the state to check
214748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
215748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
216748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int check_flash_state(struct light_state_t const *state)
217748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
218748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int64_t ns = 0;
219748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
220748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if ((state->flashOffMS < 0) || (state->flashOnMS < 0)) {
221748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
222748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
223748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
224748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if ((state->flashOffMS == 0) && (state->flashOnMS) == 0) {
225748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
226748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
227748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
228748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	/* check for overflow in ns */
229748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	ns = state->flashOffMS * ONE_MS_IN_NS;
230748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (ns / ONE_MS_IN_NS != state->flashOffMS) {
231748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
232748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
233748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	ns = state->flashOnMS * ONE_MS_IN_NS;
234748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (ns / ONE_MS_IN_NS != state->flashOnMS) {
235748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
236748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
237748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
238748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return 0;
239748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
240c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
241748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
242748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Generic function for setting the state of the light
243748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param base_dev light device data structure
244748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param state what state to set
245748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
246748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
247748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int set_light_generic(struct light_device_t *base_dev,
248748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		struct light_state_t const *state)
249c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
250748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct light_device_ext_t *dev = (struct light_device_ext_t *)base_dev;
251748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct light_state_t *current_state;
252748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int rc = 0;
253748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
254748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (dev == NULL) {
255748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		ALOGE("%s: Cannot set state for NULL device", __func__);
256748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
257748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
258748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
259748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	current_state = &dev->state;
260748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
261748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_lock(&dev->write_mutex);
262748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
263748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	ALOGV("%s: flashMode:%x, color:%x", __func__, state->flashMode, state->color);
264748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
265748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (current_state->flashMode) {
266748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		/* destroy flashing thread */
267748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_mutex_lock(&dev->flash_signal_mutex);
268748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		current_state->flashMode = LIGHT_FLASH_NONE;
269748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_cond_signal(&dev->flash_cond);
270748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_mutex_unlock(&dev->flash_signal_mutex);
271748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_join(dev->flash_thread, NULL);
272748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
273748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
274748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	*current_state = *state;
275748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
276748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (state->flashMode) {
277748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		/* start flashing thread */
278748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		if (check_flash_state(current_state) == 0) {
279748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			rc = pthread_create(&dev->flash_thread, NULL,
280748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca					flash_routine, (void *)dev);
281748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			if (rc != 0) {
282748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca				ALOGE("%s: Cannot create flashing thread", __func__);
283748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca				current_state->flashMode = LIGHT_FLASH_NONE;
284748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			}
285748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		} else {
286748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			ALOGE("%s: Flash state is invalid", __func__);
287748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			current_state->flashMode = LIGHT_FLASH_NONE;
288748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		}
289c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	} else {
290748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		rc = set_gpio_value(dev->pin, state->color);
291748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		if (rc != 0) {
292748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			ALOGE("%s: Cannot set light color.", __func__);
293748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		}
294748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
295748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
296748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_unlock(&dev->write_mutex);
297748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
298748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return rc;
299748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
300748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
301748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
302748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Initialize light synchronization resources
303748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param cond what condition variable to initialize
304748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param signal_mutex what mutex (associated with the condvar) to initialize
305748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
306748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
307748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int init_light_sync_resources(pthread_cond_t *cond,
308748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_mutex_t *signal_mutex)
309748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
310748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int rc = 0;
311748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_condattr_t condattr;
312748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
313748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	rc = pthread_condattr_init(&condattr);
314748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (rc != 0) {
315748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		ALOGE("%s: Cannot initialize the pthread condattr", __func__);
316748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return rc;
317748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
318748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
319748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	rc = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
320748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (rc != 0) {
321748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		ALOGE("%s: Cannot set the clock of condattr to monotonic", __func__);
322748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto destroy_condattr;
323748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
324748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
325748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	rc = pthread_cond_init(cond, &condattr);
326748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (rc != 0) {
327748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		ALOGE("%s: Cannot intialize the pthread structure", __func__);
328748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto destroy_condattr;
329748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
330748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
331748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	rc = pthread_mutex_init(signal_mutex, NULL);
332748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (rc != 0) {
333748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		ALOGE("%s: Cannot initialize the mutex associated with the pthread cond", __func__);
334748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto destroy_cond;
335748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
336748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
337748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_condattr_destroy(&condattr);
338748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return rc;
339748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
340748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscadestroy_cond:
341748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_cond_destroy(cond);
342748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscadestroy_condattr:
343748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_condattr_destroy(&condattr);
344748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return rc;
345748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
346748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
347748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
348748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Free light synchronization resources
349748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param cond what condition variable to free
350748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param signal_mutex what mutex (associated with the condvar) to free
351748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
352748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic void free_light_sync_resources(pthread_cond_t *cond,
353748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_mutex_t *signal_mutex)
354748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
355748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_destroy(signal_mutex);
356748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_cond_destroy(cond);
357748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca}
358748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
359748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
360748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Close the lights module
361748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param base_dev light device data structure
362748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
363748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
364748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int close_lights(struct light_device_t *base_dev)
365748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca{
366748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct light_device_ext_t *dev = (struct light_device_ext_t *)base_dev;
367748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int rc = 0;
368748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
369748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (dev == NULL) {
370748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		ALOGE("%s: Cannot deallocate a NULL light device", __func__);
371748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
372c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	}
373c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
374748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_lock(&dev->write_mutex);
375748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
376748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (dev->refs == 0) {
377748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		/* the light device is not open */
378748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		rc = EINVAL;
379748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto mutex_unlock;
380748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	} else if (dev->refs > 1) {
381748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto dec_refs;
382748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
383748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
384748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (dev->state.flashMode) {
385748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		/* destroy flashing thread */
386748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_mutex_lock(&dev->flash_signal_mutex);
387748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		dev->state.flashMode = LIGHT_FLASH_NONE;
388748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_cond_signal(&dev->flash_cond);
389748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_mutex_unlock(&dev->flash_signal_mutex);
390748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		pthread_join(dev->flash_thread, NULL);
391748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
392748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
393748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	free_light_sync_resources(&dev->flash_cond,
394748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca			&dev->flash_signal_mutex);
395748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
396748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscadec_refs:
397748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	dev->refs--;
398748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
399748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscamutex_unlock:
400748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_unlock(&dev->write_mutex);
401748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
402748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return rc;
403c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare}
404c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
405748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
406748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Module initialization routine which detects the LEDs' GPIOs
407748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param type light device type
408748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
409748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
410748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscastatic int init_module(int type)
411c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
412748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	mraa_gpio_context gpio;
413748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
414748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (type < 0 || type >= LIGHTS_TYPE_NUM) {
415748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
416748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
417748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
418748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	gpio = mraa_gpio_init_raw(TRI_STATE_ALL_GPIO_RAW_PIN);
419748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (gpio != NULL) {
420748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		/* Arduino board detected */
421748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		mraa_gpio_close(gpio);
422748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		light_devices[type].pin = ARDUINO_PINS[type];
423748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	} else {
424748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		light_devices[type].pin = NON_ARDUINO_PINS[type];
425748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
426748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
427c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	return 0;
428c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare}
429c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
430748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca/*
431748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * Open a new lights device instance by name
432748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param module associated hw module data structure
433748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param name lights device name
434748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @param device where to store the pointer of the allocated device
435748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca * @return 0 if success, error code otherwise
436748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca */
437c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Bearestatic int open_lights(const struct hw_module_t *module, char const *name,
438c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare		struct hw_device_t **device)
439c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
440748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	struct light_device_ext_t *dev;
441748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	int rc = 0, type = -1;
442c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
443748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	ALOGV("%s: Opening %s lights module", __func__, name);
444748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
445748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
446748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		type = NOTIFICATIONS_TYPE;
447748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	} else {
448748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		return EINVAL;
449c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	}
450c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
451748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	dev = (struct light_device_ext_t *)(light_devices + type);
452c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
453748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_lock(&dev->write_mutex);
454c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
455748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (dev->refs != 0) {
456748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		/* already opened; nothing to do */
457748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto inc_refs;
458748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
459748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
460748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	rc = init_module(type);
461748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (rc != 0) {
462748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		ALOGE("%s: Failed to initialize lights module", __func__);
463748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto mutex_unlock;
464748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
465c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
466748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	rc = init_light_sync_resources(&dev->flash_cond,
467748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca				&dev->flash_signal_mutex);
468748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	if (rc != 0) {
469748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca		goto mutex_unlock;
470748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	}
471748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
472748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	dev->base_dev.common.tag = HARDWARE_DEVICE_TAG;
473748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	dev->base_dev.common.version = 0;
474748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	dev->base_dev.common.module = (struct hw_module_t *)module;
475748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	dev->base_dev.common.close = (int (*)(struct hw_device_t *))close_lights;
476748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	dev->base_dev.set_light = set_light_generic;
477748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca
478748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscainc_refs:
479748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	dev->refs++;
480c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	*device = (struct hw_device_t *)dev;
481c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
482748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Muscamutex_unlock:
483748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	pthread_mutex_unlock(&dev->write_mutex);
484748d6cd3dec472369f0de2eab0fff7a1e80d77abConstantin Musca	return rc;
485c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare}
486c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
487c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Bearestatic struct hw_module_methods_t lights_methods =
488c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
489c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	.open =  open_lights,
490c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare};
491c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare
492c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Bearestruct hw_module_t HAL_MODULE_INFO_SYM =
493c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare{
494c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	.tag = HARDWARE_MODULE_TAG,
495c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	.version_major = 1,
496c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	.version_minor = 0,
497c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	.id = LIGHTS_HARDWARE_MODULE_ID,
498c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	.name = "Edison lights module",
499c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	.author = "Intel",
500c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare	.methods = &lights_methods,
501c7c4ec1204c73d3844935d3da7d07ddebd4f6607Bruce Beare};
502