4 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <linux/input.h>
24 #include "core/common.h"
25 #include "core/list.h"
26 #include "core/udev.h"
28 #include "core/devices.h"
29 #include "core/device-notifier.h"
30 #include "core/edbus-handler.h"
33 #define CED_PATH "/devices/soc/*.cec"
44 static struct cec_dev *cec_device = NULL;
46 void send_CEConeTouchPlay(struct cec_dev *pdev)
49 unsigned char buffer[4];
50 unsigned char ldst = buffer[0] >> 4;
51 unsigned char opcode = buffer[1];
52 int laddr = pdev->mCecLaddr;
53 int paddr = pdev->mCecPaddr;
56 buffer[1] = CEC_OPCODE_TEXT_VIEW_ON;
58 _I("Tx : [CEC_OPCODE_TEXT_VIEW_ON]");
60 if (CECSendMessage(buffer, size) != size)
61 _E("CECSendMessage() failed!!!");
64 buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
65 buffer[1] = CEC_OPCODE_ACTIVE_SOURCE;
66 buffer[2] = (paddr >> 8) & 0xFF;
67 buffer[3] = paddr & 0xFF;
69 _I("Tx : [CEC_OPCODE_ACTIVE_SOURCE]");
71 if (CECSendMessage(buffer, size) != size)
72 _E("CECSendMessage() failed!!!");
76 buffer[1] = CEC_OPCODE_IMAGE_VIEW_ON;
78 _I("Tx : [CEC_OPCODE_IMAGE_VIEW_ON]");
80 if (CECSendMessage(buffer, size) != size)
81 _E("CECSendMessage() failed!!!");
84 buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
85 buffer[1] = CEC_OPCODE_ACTIVE_SOURCE;
86 buffer[2] = (paddr >> 8) & 0xFF;
87 buffer[3] = paddr & 0xFF;
89 _I("Tx : [CEC_OPCODE_ACTIVE_SOURCE]");
91 if (CECSendMessage(buffer, size) != size)
92 _E("CECSendMessage() failed!!!");
96 static void handle_cec(struct cec_dev *pdev)
98 unsigned char buffer[16];
100 unsigned char lsrc, ldst, opcode;
104 size = CECReceiveMessage(buffer, CEC_MAX_FRAME_SIZE, 1000);
106 /* no data available or ctrl-c */
111 /* "Polling Message" */
118 _E("there is no cec handle");
121 lsrc = buffer[0] >> 4;
123 /* ignore messages with src address == mCecLaddr */
124 if (lsrc == pdev->mCecLaddr) {
125 _E("fail %x %x", lsrc, pdev->mCecLaddr);
130 if (lsrc != CEC_MSG_BROADCAST && (opcode ==CEC_OPCODE_SET_STREAM_PATH)) {
131 Psrc = buffer[2] << 8 | buffer[3];
132 _I("Psrc = 0x%x, dev->Paddr= 0x%x", Psrc, pdev->mCecPaddr);
133 if (pdev->mCecPaddr != Psrc) {
134 _I("### ignore message : 0x%x ", opcode);
139 if (opcode == CEC_OPCODE_ROUTING_CHANGE) {
140 Psrc = buffer[4] << 8 | buffer[5];
141 _I("Psrc = 0x%x, dev->Paddr= 0x%x", Psrc, pdev->mCecPaddr);
142 pdev->mCecRoutPaddr = Psrc;
143 _I("Opcode : 0x%x Routing addr 0x%x", opcode, pdev->mCecRoutPaddr);
146 if (CECIgnoreMessage(opcode, lsrc)) {
147 _E("### ignore message coming from address 15 (unregistered)");
151 if (buffer[0] == CEC_MSG_BROADCAST) {
153 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
154 case CEC_OPCODE_GET_CEC_VERSION:
155 _I("### ignore broadcast message : 0x%x ", opcode);
162 if (!CECCheckMessageSize(opcode, size)) {
164 * For some reason the TV sometimes sends messages that are too long
165 * Dropping these causes the connect process to fail, so for now we
166 * simply ignore the extra data and process the message as if it had
169 _I("### invalid message size: %d(opcode: 0x%x) ###", size, opcode);
173 /* check if message broadcasted/directly addressed */
174 if (!CECCheckMessageMode(opcode, (buffer[0] & 0x0F) == CEC_MSG_BROADCAST ? 1 : 0)) {
175 _E("### invalid message mode (directly addressed/broadcast) ###");
181 /* TODO: macros to extract src and dst logical addresses */
182 /* TODO: macros to extract opcode */
184 if (opcode == CEC_OPCODE_SET_STREAM_PATH)
186 size = CECProcessOpcode(buffer,pdev-> mCecLaddr, pdev->mCecPaddr,
187 pdev->mCecRoutPaddr);
190 if (CECSendMessage(buffer, size) != size)
191 _E("CECSendMessage() failed!!!");
195 send_CEConeTouchPlay(pdev);
198 static void *hwc_cec_thread(void *data)
200 struct cec_dev *pdev =
201 (struct cec_dev *)data;
203 fds.fd = pdev->mCecFd;
208 fds.fd = pdev->mCecFd;
210 err = poll(&fds, 1, -1);
213 if (fds.revents & POLLIN) {
217 else if (err == -1) {
220 _E("error in cec thread: %s", strerror(errno));
226 static int check_cec(void)
233 if(access("/dev/cec0", F_OK) == 0)
240 static void start_cec(struct cec_dev *pdev)
242 unsigned char buffer[CEC_MAX_FRAME_SIZE];
246 _E("there is no cec handle");
249 pdev->mCecPaddr = 0x100B;//CEC_NOT_VALID_PHYSICAL_ADDRESS;
251 //get TV physical address
252 pdev->mCecLaddr = CECAllocLogicalAddress(pdev->mCecPaddr, CEC_DEVICE_PLAYER);
253 /* Request power state from TV */
254 buffer[0] = (pdev->mCecLaddr << 4);
255 buffer[1] = CEC_OPCODE_GIVE_DEVICE_POWER_STATUS;
257 if (CECSendMessage(buffer, size) != size)
258 _E("CECSendMessage(%#x) failed!!!", buffer[0]);
259 /* Wakeup Homekey at first connection */
260 CECReportKey(KEY_POWER);
263 static void open_cec(struct cec_dev *pdev)
268 _I("already initialized");
271 pdev = (struct cec_dev *)malloc(sizeof(*pdev));
273 _E("there is no cec handle");
276 memset(pdev, 0, sizeof(*pdev));
277 pdev->mCecFd = CECOpen();
278 _I("cec is %d", pdev->mCecFd);
279 if (pdev->mCecFd > 0) {
280 ret = pthread_create(&pdev->cec_thread, NULL, hwc_cec_thread, pdev);
282 _E("failed to start cec thread: %s", strerror(ret));
295 static void close_cec(struct cec_dev *pdev)
302 _I("cec is %d", pdev->mCecFd);
303 pthread_kill(pdev->cec_thread, SIGTERM);
304 pthread_join(pdev->cec_thread, NULL);
309 static void init_cec(struct cec_dev *pdev)
312 _I("already initialized");
315 pdev = (struct cec_dev *)malloc(sizeof(*pdev));
317 _E("there is no cec handle");
320 memset(pdev, 0, sizeof(*pdev));
323 static void cec_uevent_changed (struct udev_device *dev)
325 const char *state = NULL;
326 const char *devpath = NULL;
327 const char *value = NULL;
332 devpath = udev_device_get_property_value(dev, "DEVNAME");
333 value = udev_device_get_property_value(dev, "HDMICEC");
334 _I("%s %s", devpath, value);
337 const static struct uevent_handler cec_uevent_handler[] = {
338 { "misc" , cec_uevent_changed , NULL },
341 static DBusMessage *dbus_get_state(E_DBus_Object *obj, DBusMessage *msg)
343 DBusMessageIter iter;
347 reply = dbus_message_new_method_return(msg);
348 dbus_message_iter_init_append(reply, &iter);
349 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
353 static const struct edbus_method edbus_methods[] = {
354 { "GetState" , NULL, "i" , dbus_get_state },
357 static int cec_init_booting_done(void *data)
361 for (i = 0 ; i < ARRAY_SIZE(cec_uevent_handler) ; i++) {
362 ret = register_uevent_control(&cec_uevent_handler[i]);
364 _E("FAIL: reg_uevent_control()");
366 ret = register_edbus_method(DEVICED_PATH_HDMICEC, edbus_methods, ARRAY_SIZE(edbus_methods));
368 _E("fail to init edbus method(%d)", ret);
373 static void hdmi_cec_init(void *data)
375 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, cec_init_booting_done);
377 open_cec(cec_device);
380 static void hdmi_cec_exit(void *data)
384 for (i = 0 ; i < ARRAY_SIZE(cec_uevent_handler) ; i++) {
385 unregister_uevent_control(&cec_uevent_handler[i]);
389 static int hdmi_cec_execute(void *data)
391 int state = (int)data;
393 if (check_cec() == 0) {
394 _E("there is no cec");
400 start_cec(cec_device);
402 close_cec(cec_device);
406 static const struct device_ops cec_device_ops = {
407 .priority = DEVICE_PRIORITY_NORMAL,
409 .init = hdmi_cec_init,
410 .exit = hdmi_cec_exit,
411 .execute = hdmi_cec_execute,
414 DEVICE_OPS_REGISTER(&cec_device_ops)