summaryrefslogtreecommitdiff
path: root/hdmi_cec.c (plain)
blob: 7ce0cbd131680ff8c89e5db822e5f5d10c72c93c
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 = 0x%x addr = %d\n", __func__, __LINE__, (unsigned int)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 = 0x%x\n", __func__, __LINE__, (unsigned int)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 = 0x%x msg = 0x%x\n", __func__, __LINE__, (unsigned int)dev, (unsigned int)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 = 0x%x version = 0x%x\n", __func__, __LINE__, (unsigned int)dev, (unsigned int)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 = 0x%x vendor_id = 0x%x\n", __func__, __LINE__, (unsigned int)dev, (unsigned int)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 = 0x%x list = 0x%x total = 0x%x\n", __func__, __LINE__, (unsigned int)dev, (unsigned int)list, (unsigned int)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 = 0x%x flag = 0x%x value = 0x%x\n", __func__, __LINE__, (unsigned int)dev, (unsigned int)flag, (unsigned int)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 write(fd, "0xf", 3);
224 break;
225 case HDMI_OPTION_SYSTEM_CEC_CONTROL:
226 ALOGE("%s[%d]HDMI_OPTION_SYSTEM_CEC_CONTROL TODO\n", __func__, __LINE__);
227 break;
228 default:
229 ALOGE("%s[%d] un-recognized flag = %d\n", __func__, __LINE__, flag);
230 break;
231 }
232 close(fd);
233}
234
235/*
236 * (*set_audio_return_channel)() configures ARC circuit in the hardware logic
237 * to start or stop the feature. Flag can be either 1 to start the feature
238 * or 0 to stop it.
239 *
240 * Returns 0 on success or -errno on error.
241 */
242static void hdmitx_cec_set_audio_return_channel(const struct hdmi_cec_device* dev, int flag)
243{
244 ALOGE("%s[%d] dev = 0x%x flag = 0x%x\n", __func__, __LINE__, (unsigned int)dev, (unsigned int)flag);
245}
246
247/*
248 * (*is_connected)() returns the connection status of the specified port.
249 * Returns HDMI_CONNECTED if a device is connected, otherwise HDMI_NOT_CONNECTED.
250 * The HAL should watch for +5V power signal to determine the status.
251 */
252static int hdmitx_cec_is_connected(const struct hdmi_cec_device* dev, int port_id)
253{
254 int fd = 0;
255 char st = '0';
256 dev = dev; // prevent warning
257 fd = open(HDMITX_HPD_STATE_SYSFS, O_RDONLY);
258 if (fd < 0) {
259 ALOGE("%s[%d][FILE]%s open failed\n", __func__, __LINE__, HDMITX_HPD_STATE_SYSFS);
260 return 1;
261 }
262 read(fd, &st, 1);
263 close(fd);
264 ALOGE("port_id = %d cec_is_connected = %c\n", port_id, st);
265 return (st == '1') ? HDMI_CONNECTED : HDMI_NOT_CONNECTED;
266}
267
268/** Close the hdmitx cec device */
269static int hdmitx_cec_close(struct hw_device_t *dev)
270{
271 ALOGE("%s[%d] dev = 0x%x n", __func__, __LINE__, (unsigned int)dev);
272 if (dev_fd)
273 close(dev_fd);
274 free(dev);
275 return 0;
276}
277/**
278 * module methods
279 */
280static int open_hdmitx_cec( const struct hw_module_t* module, char const *name,
281 struct hw_device_t **device )
282{
283 ALOGE("%s[%d] %s\n", __func__, __LINE__, name);
284 if (strcmp(name, HDMI_CEC_HARDWARE_INTERFACE) != 0) {
285 ALOGE("hdmitx_cec strcmp fail !!!");
286 return -EINVAL;
287 }
288 if (device == NULL) {
289 ALOGE("NULL hdmitx_cec device on open");
290 return -EINVAL;
291 }
292
293 hdmi_cec_device_t *dev = malloc(sizeof(hdmi_cec_device_t));
294 memset(dev, 0, sizeof(hdmi_cec_device_t));
295
296 dev->common.tag = HARDWARE_DEVICE_TAG;
297 dev->common.version = 0;
298 dev->common.module = (struct hw_module_t*) module;
299 dev->common.close = hdmitx_cec_close;
300
301 dev->add_logical_address = hdmitx_cec_add_logical_address;
302 dev->clear_logical_address = hdmitx_cec_clear_logical_address;
303 dev->get_physical_address = hdmitx_cec_get_physical_address;
304 dev->send_message = hdmitx_cec_send_message;
305 dev->register_event_callback = hdmitx_cec_register_event_callback;
306 dev->get_version = hdmitx_cec_get_version;
307 dev->get_vendor_id = hdmitx_cec_get_vendor_id;
308 dev->get_port_info = hdmitx_cec_get_port_info;
309 dev->set_option = hdmitx_cec_set_option;
310 dev->set_audio_return_channel = hdmitx_cec_set_audio_return_channel;
311 dev->is_connected = hdmitx_cec_is_connected;
312
313 *device = (hw_device_t*) dev;
314
315 dev_fd = open(HDMITX_CEC_SYSFS, O_RDWR);
316 if (dev_fd < 0) {
317 ALOGE("open cec device error\n");
318 return -1;
319 }
320
321 return 0;
322}
323
324static struct hw_module_methods_t hdmitx_cec_module_methods = {
325 .open = open_hdmitx_cec,
326};
327
328/*
329 * The hdmitx cec Module
330 */
331struct hdmi_cec_module HAL_MODULE_INFO_SYM = {
332 .common = {
333 .tag = HARDWARE_MODULE_TAG,
334 .module_api_version = HDMI_CEC_MODULE_API_VERSION_1_0,
335 .hal_api_version = HARDWARE_HAL_API_VERSION,
336 .id = HDMI_CEC_HARDWARE_MODULE_ID,
337 .name = "Amlogic hdmitx cec Module",
338 .author = "Amlogic Corp.",
339 .methods = &hdmitx_cec_module_methods,
340 },
341};
342
343