summaryrefslogtreecommitdiff
path: root/hdmi_cec.c (plain)
blob: 0b66810ec550f2043b0ac8c089d19c243e11561a
1/*
2 * Copyright (C) 2014 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 * Amlogic HDMITX CEC HAL
18 * Copyright (C) 2014
19 *
20 * This implements a hdmitx cec hardware library for the Android emulator.
21 * the following code should be built as a shared library that will be
22 * placed into /system/lib/hw/hdmitx_cec.so
23 *
24 * It will be loaded by the code in hardware/libhardware/hardware.c
25 * which is itself called from
26 * frameworks/base/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
27 */
28
29#ifdef LOG_TAG
30#undef LOG_TAG
31#define LOG_TAG "hdmi_cec"
32#endif
33#include <cutils/log.h>
34#include <stdint.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38#include <errno.h>
39#include <fcntl.h>
40#include <pthread.h>
41#include <sys/ioctl.h>
42#include <sys/types.h>
43#include <hardware/hdmi_cec.h>
44#include <hardware/hardware.h>
45
46/* Set to 1 to enable debug messages to the log */
47#define DEBUG 0
48#if DEBUG
49# define D(...) ALOGD(__VA_ARGS__)
50#else
51# define D(...) do{}while(0)
52#endif
53
54#define E(...) ALOGE(__VA_ARGS__)
55
56static int dev_fd = -1;
57
58#define HDMITX_CEC_SYSFS "/sys/class/amhdmitx/amhdmitx0/cec"
59#define HDMITX_CEC_CONFIG_SYSFS "/sys/class/amhdmitx/amhdmitx0/cec_config"
60#define HDMITX_PHY_ADDR_SYSFS "/sys/class/amhdmitx/amhdmitx0/phy_addr"
61#define HDMITX_HPD_STATE_SYSFS "/sys/class/amhdmitx/amhdmitx0/hpd_state"
62
63/*
64 * (*add_logical_address)() passes the logical address that will be used
65 * in this system.
66 *
67 * HAL may use it to configure the hardware so that the CEC commands addressed
68 * the given logical address can be filtered in. This method can be called
69 * as many times as necessary in order to support multiple logical devices.
70 * addr should be in the range of valid logical addresses for the call
71 * to succeed.
72 *
73 * Returns 0 on success or -errno on error.
74 */
75static int hdmitx_cec_add_logical_address(const struct hdmi_cec_device* dev, cec_logical_address_t addr)
76{
77 ALOGE("%s[%d] dev = %p addr = %d\n", __func__, __LINE__, dev, (unsigned int)addr);
78 return 0;
79}
80
81/*
82 * (*clear_logical_address)() tells HAL to reset all the logical addresses.
83 *
84 * It is used when the system doesn't need to process CEC command any more,
85 * hence to tell HAL to stop receiving commands from the CEC bus, and change
86 * the state back to the beginning.
87 */
88static void hdmitx_cec_clear_logical_address(const struct hdmi_cec_device* dev)
89{
90 ALOGE("%s[%d] dev = %p\n", __func__, __LINE__, dev);
91}
92
93/*
94 * (*get_physical_address)() returns the CEC physical address. The
95 * address is written to addr.
96 *
97 * The physical address depends on the topology of the network formed
98 * by connected HDMI devices. It is therefore likely to change if the cable
99 * is plugged off and on again. It is advised to call get_physical_address
100 * to get the updated address when hot plug event takes place.
101 *
102 * Returns 0 on success or -errno on error.
103 */
104static int hdmitx_cec_get_physical_address(const struct hdmi_cec_device* dev, uint16_t* addr)
105{
106 int fd = 0;
107 char paddr[4] = {0};
108
109 dev = dev;
110 fd = open(HDMITX_PHY_ADDR_SYSFS, O_RDONLY);
111 if (fd < 0) {
112 ALOGE("%s[%d] cat get physical address\n", __func__, __LINE__);
113 return -1;
114 }
115 read(fd, paddr, 4);
116 close(fd);
117 *addr = (uint16_t)strtoul(paddr, NULL, 16);
118 return 0;
119}
120
121/*
122 * (*send_message)() transmits HDMI-CEC message to other HDMI device.
123 *
124 * The method should be designed to return in a certain amount of time not
125 * hanging forever, which can happen if CEC signal line is pulled low for
126 * some reason. HAL implementation should take the situation into account
127 * so as not to wait forever for the message to get sent out.
128 *
129 * It should try retransmission at least once as specified in the standard.
130 *
131 * Returns error code. See HDMI_RESULT_SUCCESS, HDMI_RESULT_NACK, and
132 * HDMI_RESULT_BUSY.
133 */
134static int hdmitx_cec_send_message(const struct hdmi_cec_device* dev, const cec_message_t* msg)
135{
136 ALOGE("%s[%d] dev = %p msg = %p\n", __func__, __LINE__, dev, msg);
137 return HDMI_RESULT_SUCCESS;
138}
139
140/*
141 * (*register_event_callback)() registers a callback that HDMI-CEC HAL
142 * can later use for incoming CEC messages or internal HDMI events.
143 * When calling from C++, use the argument arg to pass the calling object.
144 * It will be passed back when the callback is invoked so that the context
145 * can be retrieved.
146 */
147static void hdmitx_cec_register_event_callback(const struct hdmi_cec_device* dev,
148 event_callback_t callback, void* arg)
149{
150 dev = dev;
151 callback = callback;
152 arg = arg;
153 ALOGE("%s[%d]TODO\n", __func__, __LINE__);
154 //callback(, arg);
155}
156
157/*
158 * (*get_version)() returns the CEC version supported by underlying hardware.
159 */
160static void hdmitx_cec_get_version(const struct hdmi_cec_device* dev, int* version)
161{
162 ALOGE("%s[%d] dev = %p version = %p\n", __func__, __LINE__, dev, version);
163 *version = 0x14;
164}
165
166/*
167 * (*get_vendor_id)() returns the identifier of the vendor. It is
168 * the 24-bit unique company ID obtained from the IEEE Registration
169 * Authority Committee (RAC).
170 */
171static void hdmitx_cec_get_vendor_id(const struct hdmi_cec_device* dev, uint32_t* vendor_id)
172{
173 ALOGE("%s[%d] dev = %p vendor_id = %p\n", __func__, __LINE__, dev, vendor_id);
174 *vendor_id = 0x4321;
175}
176
177static struct hdmi_port_info hdmitx_port0 = {
178 .type = HDMI_OUTPUT,
179 // Port ID should start from 1 which corresponds to HDMI "port 1".
180 .port_id = 1,
181 .cec_supported = 1,
182 .arc_supported = 0,
183 .physical_address = 0x1000,
184};
185
186/*
187 * (*get_port_info)() returns the hdmi port information of underlying hardware.
188 * info is the list of HDMI port information, and 'total' is the number of
189 * HDMI ports in the system.
190 */
191// FIXED 1 port for MBox
192static void hdmitx_cec_get_port_info(const struct hdmi_cec_device* dev,
193 struct hdmi_port_info* list[], int* total)
194{
195 ALOGE("%s[%d] dev = %p list = %p total = %p\n", __func__, __LINE__, dev, list, total);
196 *total = 1;
197 list[0] = &hdmitx_port0;
198}
199
200/*
201 * (*set_option)() passes flags controlling the way HDMI-CEC service works down
202 * to HAL implementation. Those flags will be used in case the feature needs
203 * update in HAL itself, firmware or microcontroller.
204 */
205static void hdmitx_cec_set_option(const struct hdmi_cec_device* dev, int flag, int value)
206{
207 int fd = 0;
208
209 ALOGE("%s[%d] dev = %p flag = %p value = %p\n", __func__, __LINE__, dev, flag, value);
210 fd = open(HDMITX_CEC_CONFIG_SYSFS, O_WRONLY);
211 if (fd < 0) {
212 ALOGE("%s[%d][FILE]%s open failed\n", __func__, __LINE__, HDMITX_CEC_CONFIG_SYSFS);
213 return ;
214 }
215 switch (flag) {
216 case HDMI_OPTION_ENABLE_CEC:
217 if (value == 1)
218 write(fd, "0xf", 3);
219 if (value == 0)
220 write(fd, "0x0", 3);
221 break;
222 case HDMI_OPTION_WAKEUP:
223 //Function: Automatic wake-up
224 //write(fd, "0xf", 3);
225 break;
226 case HDMI_OPTION_SYSTEM_CEC_CONTROL:
227 ALOGE("%s[%d]HDMI_OPTION_SYSTEM_CEC_CONTROL TODO\n", __func__, __LINE__);
228 break;
229 default:
230 ALOGE("%s[%d] un-recognized flag = %d\n", __func__, __LINE__, flag);
231 break;
232 }
233 close(fd);
234}
235
236/*
237 * (*set_audio_return_channel)() configures ARC circuit in the hardware logic
238 * to start or stop the feature. Flag can be either 1 to start the feature
239 * or 0 to stop it.
240 *
241 * Returns 0 on success or -errno on error.
242 */
243static void hdmitx_cec_set_audio_return_channel(const struct hdmi_cec_device* dev, int flag)
244{
245 ALOGE("%s[%d] dev = %p flag = %p\n", __func__, __LINE__, dev, flag);
246}
247
248/*
249 * (*is_connected)() returns the connection status of the specified port.
250 * Returns HDMI_CONNECTED if a device is connected, otherwise HDMI_NOT_CONNECTED.
251 * The HAL should watch for +5V power signal to determine the status.
252 */
253static int hdmitx_cec_is_connected(const struct hdmi_cec_device* dev, int port_id)
254{
255 int fd = 0;
256 char st = '0';
257 dev = dev; // prevent warning
258 fd = open(HDMITX_HPD_STATE_SYSFS, O_RDONLY);
259 if (fd < 0) {
260 ALOGE("%s[%d][FILE]%s open failed\n", __func__, __LINE__, HDMITX_HPD_STATE_SYSFS);
261 return 1;
262 }
263 read(fd, &st, 1);
264 close(fd);
265 ALOGE("port_id = %d cec_is_connected = %c\n", port_id, st);
266 return (st == '1') ? HDMI_CONNECTED : HDMI_NOT_CONNECTED;
267}
268
269/** Close the hdmitx cec device */
270static int hdmitx_cec_close(struct hw_device_t *dev)
271{
272 ALOGE("%s[%d] dev = %p n", __func__, __LINE__, dev);
273 if (dev_fd)
274 close(dev_fd);
275 free(dev);
276 return 0;
277}
278/**
279 * module methods
280 */
281static int open_hdmitx_cec( const struct hw_module_t* module, char const *name,
282 struct hw_device_t **device )
283{
284 ALOGE("%s[%d] %s\n", __func__, __LINE__, name);
285 if (strcmp(name, HDMI_CEC_HARDWARE_INTERFACE) != 0) {
286 ALOGE("hdmitx_cec strcmp fail !!!");
287 return -EINVAL;
288 }
289 if (device == NULL) {
290 ALOGE("NULL hdmitx_cec device on open");
291 return -EINVAL;
292 }
293
294 hdmi_cec_device_t *dev = malloc(sizeof(hdmi_cec_device_t));
295 memset(dev, 0, sizeof(hdmi_cec_device_t));
296
297 dev->common.tag = HARDWARE_DEVICE_TAG;
298 dev->common.version = 0;
299 dev->common.module = (struct hw_module_t*) module;
300 dev->common.close = hdmitx_cec_close;
301
302 dev->add_logical_address = hdmitx_cec_add_logical_address;
303 dev->clear_logical_address = hdmitx_cec_clear_logical_address;
304 dev->get_physical_address = hdmitx_cec_get_physical_address;
305 dev->send_message = hdmitx_cec_send_message;
306 dev->register_event_callback = hdmitx_cec_register_event_callback;
307 dev->get_version = hdmitx_cec_get_version;
308 dev->get_vendor_id = hdmitx_cec_get_vendor_id;
309 dev->get_port_info = hdmitx_cec_get_port_info;
310 dev->set_option = hdmitx_cec_set_option;
311 dev->set_audio_return_channel = hdmitx_cec_set_audio_return_channel;
312 dev->is_connected = hdmitx_cec_is_connected;
313
314 *device = (hw_device_t*) dev;
315
316 dev_fd = open(HDMITX_CEC_SYSFS, O_RDWR);
317 if (dev_fd < 0) {
318 ALOGE("open cec device error\n");
319 return -1;
320 }
321
322 return 0;
323}
324
325static struct hw_module_methods_t hdmitx_cec_module_methods = {
326 .open = open_hdmitx_cec,
327};
328
329/*
330 * The hdmitx cec Module
331 */
332struct hdmi_cec_module HAL_MODULE_INFO_SYM = {
333 .common = {
334 .tag = HARDWARE_MODULE_TAG,
335 .module_api_version = HDMI_CEC_MODULE_API_VERSION_1_0,
336 .hal_api_version = HARDWARE_HAL_API_VERSION,
337 .id = HDMI_CEC_HARDWARE_MODULE_ID,
338 .name = "Amlogic hdmitx cec Module",
339 .author = "Amlogic Corp.",
340 .methods = &hdmitx_cec_module_methods,
341 },
342};
343
344