tizen 2.3 release
[framework/system/deviced.git] / src / hdmi-cec / cec.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19
20 #include <linux/input.h>
21 #include <pthread.h>
22 #include <poll.h>
23
24 #include "core/common.h"
25 #include "core/list.h"
26 #include "core/udev.h"
27 #include "core/log.h"
28 #include "core/devices.h"
29 #include "core/device-notifier.h"
30 #include "core/edbus-handler.h"
31 #include "libcec.h"
32
33 #define CED_PATH                "/devices/soc/*.cec"
34
35 struct cec_dev{
36         pthread_t cec_thread;
37         int             mCecFd;
38         int             mCecPaddr;
39         int             mCecLaddr;
40         int             mCecTvOnOff;
41         int             mCecRoutPaddr;
42 };
43
44 static struct cec_dev *cec_device = NULL;
45
46 void send_CEConeTouchPlay(struct cec_dev *pdev)
47 {
48         int size = 0;
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;
54
55         buffer[0] = 0x40;
56         buffer[1] = CEC_OPCODE_TEXT_VIEW_ON;
57         size = 2;
58         _I("Tx : [CEC_OPCODE_TEXT_VIEW_ON]");
59
60         if (CECSendMessage(buffer, size) != size)
61                 _E("CECSendMessage() failed!!!");
62         usleep(500000);
63
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;
68         size = 4;
69         _I("Tx : [CEC_OPCODE_ACTIVE_SOURCE]");
70
71         if (CECSendMessage(buffer, size) != size)
72                 _E("CECSendMessage() failed!!!");
73         usleep(500000);
74
75         buffer[0] = 0x40;
76         buffer[1] = CEC_OPCODE_IMAGE_VIEW_ON;
77         size = 2;
78         _I("Tx : [CEC_OPCODE_IMAGE_VIEW_ON]");
79
80         if (CECSendMessage(buffer, size) != size)
81                 _E("CECSendMessage() failed!!!");
82         usleep(500000);
83
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;
88         size = 4;
89         _I("Tx : [CEC_OPCODE_ACTIVE_SOURCE]");
90
91         if (CECSendMessage(buffer, size) != size)
92                 _E("CECSendMessage() failed!!!");
93         return;
94 }
95
96 static void handle_cec(struct cec_dev *pdev)
97 {
98         unsigned char buffer[16];
99         int size;
100         unsigned char lsrc, ldst, opcode;
101         int Psrc;
102         int ceconoff = 0;
103
104         size = CECReceiveMessage(buffer, CEC_MAX_FRAME_SIZE, 1000);
105
106         /* no data available or ctrl-c */
107         if (!size) {
108                 _E("fail");
109                 return;
110         }
111         /* "Polling Message" */
112         if (size == 1) {
113                 _E("fail");
114                 return;
115         }
116
117         if (!pdev) {
118                 _E("there is no cec handle");
119                 return;
120         }
121         lsrc = buffer[0] >> 4;
122
123         /* ignore messages with src address == mCecLaddr */
124         if (lsrc == pdev->mCecLaddr) {
125                 _E("fail %x %x", lsrc, pdev->mCecLaddr);
126                 return;
127         }
128         opcode = buffer[1];
129
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);
135                         return;
136                 }
137         }
138
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);
144         }
145
146         if (CECIgnoreMessage(opcode, lsrc)) {
147                 _E("### ignore message coming from address 15 (unregistered)");
148                 return;
149         }
150
151         if (buffer[0] == CEC_MSG_BROADCAST) {
152                 switch (opcode) {
153                 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
154                 case CEC_OPCODE_GET_CEC_VERSION:
155                         _I("### ignore broadcast message : 0x%x ", opcode);
156                         return;
157                 default:
158                         break;
159                 }
160         }
161
162         if (!CECCheckMessageSize(opcode, size)) {
163                 /*
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
167                 * the correct size
168                 */
169                 _I("### invalid message size: %d(opcode: 0x%x) ###", size, opcode);
170                 return;
171         }
172
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) ###");
176                 return;
177         }
178
179         ldst = lsrc;
180
181         /* TODO: macros to extract src and dst logical addresses */
182         /* TODO: macros to extract opcode */
183
184         if (opcode == CEC_OPCODE_SET_STREAM_PATH)
185                 ceconoff = 1;
186         size = CECProcessOpcode(buffer,pdev-> mCecLaddr, pdev->mCecPaddr,
187         pdev->mCecRoutPaddr);
188
189         if (size > 0) {
190                 if (CECSendMessage(buffer, size) != size)
191                         _E("CECSendMessage() failed!!!");
192         }
193
194         if (ceconoff)
195                 send_CEConeTouchPlay(pdev);
196 }
197
198 static void *hwc_cec_thread(void *data)
199 {
200     struct cec_dev *pdev =
201             (struct cec_dev *)data;
202        struct pollfd fds;
203        fds.fd = pdev->mCecFd;
204        fds.events = POLLIN;
205
206        while (true) {
207                int err;
208                fds.fd = pdev->mCecFd;
209                if (fds.fd > 0)
210                        err = poll(&fds, 1, -1);
211
212                if (err > 0) {
213                        if (fds.revents & POLLIN) {
214                                handle_cec(pdev);
215                        }
216                }
217                else if (err == -1) {
218                        if (errno == EINTR)
219                                break;
220                        _E("error in cec thread: %s", strerror(errno));
221                }
222        }
223     return NULL;
224 }
225
226 static int check_cec(void)
227 {
228         static int cec = -1;
229
230         if (cec != -1)
231                 goto out;
232
233         if(access("/dev/cec0", F_OK) == 0)
234                 cec = 1;
235         cec = 0;
236 out:
237         return cec;
238 }
239
240 static void start_cec(struct cec_dev *pdev)
241 {
242         unsigned char buffer[CEC_MAX_FRAME_SIZE];
243         int size;
244
245         if (!pdev) {
246                 _E("there is no cec handle");
247                 return;
248         }
249         pdev->mCecPaddr = 0x100B;//CEC_NOT_VALID_PHYSICAL_ADDRESS;
250
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;
256         size = 2;
257         if (CECSendMessage(buffer, size) != size)
258                 _E("CECSendMessage(%#x) failed!!!", buffer[0]);
259         /* Wakeup Homekey at first connection */
260         CECReportKey(KEY_POWER);
261 }
262
263 static void open_cec(struct cec_dev *pdev)
264 {
265         int ret;
266
267         if (pdev) {
268                 _I("already initialized");
269                 return;
270         }
271         pdev = (struct cec_dev *)malloc(sizeof(*pdev));
272         if (!pdev) {
273                 _E("there is no cec handle");
274                 return;
275         }
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);
281                 if (ret) {
282                         _E("failed to start cec thread: %s", strerror(ret));
283                         pdev->mCecFd = -1;
284                         CECClose();
285                 } else {
286                         _I("run thread");
287                         start_cec(pdev);
288                         _I("start cec");
289                         init_input_key_fd();
290                 }
291
292         }
293 }
294
295 static void close_cec(struct cec_dev *pdev)
296 {
297         CECClose();
298
299         if (!pdev)
300                 return;
301
302         _I("cec is %d", pdev->mCecFd);
303         pthread_kill(pdev->cec_thread, SIGTERM);
304         pthread_join(pdev->cec_thread, NULL);
305         pdev->mCecFd = -1;
306         free(pdev);
307 }
308
309 static void init_cec(struct cec_dev *pdev)
310 {
311         if (pdev) {
312                 _I("already initialized");
313                 return;
314         }
315         pdev = (struct cec_dev *)malloc(sizeof(*pdev));
316         if (!pdev) {
317                 _E("there is no cec handle");
318                 return;
319         }
320         memset(pdev, 0, sizeof(*pdev)); 
321 }
322
323 static void cec_uevent_changed (struct udev_device *dev)
324 {
325         const char *state = NULL;
326         const char *devpath = NULL;
327         const char *value = NULL;
328
329         int ret;
330         static int cradle;
331
332         devpath = udev_device_get_property_value(dev, "DEVNAME");
333         value = udev_device_get_property_value(dev, "HDMICEC");
334         _I("%s %s", devpath, value);
335 }
336
337 const static struct uevent_handler cec_uevent_handler[] = {
338         { "misc"       ,     cec_uevent_changed       ,    NULL    },
339 };
340
341 static DBusMessage *dbus_get_state(E_DBus_Object *obj, DBusMessage *msg)
342 {
343         DBusMessageIter iter;
344         DBusMessage *reply;
345         int ret = 0;
346
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);
350         return reply;
351 }
352
353 static const struct edbus_method edbus_methods[] = {
354         { "GetState"  ,  NULL, "i" ,  dbus_get_state },
355 };
356
357 static int cec_init_booting_done(void *data)
358 {
359         int ret, i;
360
361         for (i = 0 ; i < ARRAY_SIZE(cec_uevent_handler) ; i++) {
362                 ret = register_uevent_control(&cec_uevent_handler[i]);
363                 if (ret < 0)
364                         _E("FAIL: reg_uevent_control()");
365         }
366         ret = register_edbus_method(DEVICED_PATH_HDMICEC, edbus_methods, ARRAY_SIZE(edbus_methods));
367         if (ret < 0)
368                 _E("fail to init edbus method(%d)", ret);
369
370         return 0;
371 }
372
373 static void hdmi_cec_init(void *data)
374 {
375         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, cec_init_booting_done);
376         _I("open cec");
377         open_cec(cec_device);
378 }
379
380 static void hdmi_cec_exit(void *data)
381 {
382         int i;
383
384         for (i = 0 ; i < ARRAY_SIZE(cec_uevent_handler) ; i++) {
385                 unregister_uevent_control(&cec_uevent_handler[i]);
386         }
387 }
388
389 static int hdmi_cec_execute(void *data)
390 {
391         int state = (int)data;
392 /*
393         if (check_cec() == 0) {
394                 _E("there is no cec");
395                 return 0;
396         }
397 */
398         if (state) {
399                 _I("start cec");
400                 start_cec(cec_device);
401         } else
402                 close_cec(cec_device);
403         return 0;
404 }
405
406 static const struct device_ops cec_device_ops = {
407         .priority = DEVICE_PRIORITY_NORMAL,
408         .name     = "hdmi-cec",
409         .init     = hdmi_cec_init,
410         .exit     = hdmi_cec_exit,
411         .execute = hdmi_cec_execute,
412 };
413
414 DEVICE_OPS_REGISTER(&cec_device_ops)