2 * Copyright@ Samsung Electronics Co. LTD
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <sys/types.h>
21 #include <sys/ioctl.h>
24 #include <linux/input.h>
25 #include <linux/uinput.h>
34 #define CEC_KEY_RELEASED 0
35 #define CEC_KEY_PRESSED 1
37 * @def CEC_DEVICE_NAME
38 * Defines simbolic name of the CEC device.
40 #define CEC_DEVICE_NAME "/dev/cec0"
43 enum CECDeviceType devtype;
46 { CEC_DEVICE_RECODER, 1 },
47 { CEC_DEVICE_RECODER, 2 },
48 { CEC_DEVICE_TUNER, 3 },
49 { CEC_DEVICE_PLAYER, 4 },
50 { CEC_DEVICE_AUDIO, 5 },
51 { CEC_DEVICE_TUNER, 6 },
52 { CEC_DEVICE_TUNER, 7 },
53 { CEC_DEVICE_PLAYER, 8 },
54 { CEC_DEVICE_RECODER, 9 },
55 { CEC_DEVICE_TUNER, 10 },
56 { CEC_DEVICE_PLAYER, 11 },
65 {"Connect", 0x40, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_F6},
66 {"Connect", 0x40, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_F6},
67 {"Enter", 0x0, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_ENTER},
68 {"Enter", 0x0, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_ENTER},
69 {"Up", 0x1, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_UP},
70 {"Up", 0x1, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_UP},
71 {"Down", 0x2, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_DOWN},
72 {"Down", 0x2, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_DOWN},
73 {"Left", 0x3, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_LEFT},
74 {"Left", 0x3, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_LEFT},
75 {"Right", 0x4, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_RIGHT},
76 {"Right", 0x4, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_RIGHT},
77 {"Exit", 0xD, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_MENU},
78 {"Exit", 0xD, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_MENU},
79 {"Clear", 0x2C, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_BACK},
80 {"Clear", 0x2C, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_BACK},
81 {"Clear2", 0x91, CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN, KEY_BACK},/* samsung key*/
82 {"Play", 0x24, CEC_OPCODE_PLAY, KEY_PLAY},
83 {"Play", 0x44, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_PLAY},
84 {"Play", 0x44, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_PLAY},
85 {"Stop", 0x3, CEC_OPCODE_DECK_CONTROL, KEY_STOP},
86 {"Stop", 0x45, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_STOP},
87 {"Stop", 0x45, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_STOP},
88 {"Pause", 0x25, CEC_OPCODE_PLAY, KEY_PAUSECD},
89 {"Pause", 0x46, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_PAUSECD},
90 {"Pause", 0x46, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_PAUSECD},
91 {"Rewind", 0x48, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_REWIND},
92 {"Rewind", 0x48, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_REWIND},
93 {"FastForward", 0x49, CEC_OPCODE_USER_CONTROL_PRESSED, KEY_FASTFORWARD},
94 {"FastForward", 0x49, CEC_OPCODE_USER_CONTROL_RELEASED, KEY_FASTFORWARD},
95 {"TV Standby", 0x36, CEC_OPCODE_STANDBY, KEY_HOMEPAGE},
96 {"TV Routing Change", 0x80, CEC_OPCODE_ROUTING_CHANGE, KEY_HOMEPAGE},
99 static int CECSetLogicalAddr(unsigned int laddr);
102 inline static void CECPrintFrame(unsigned char *buffer, unsigned int size);
106 static int key_fd = -1;
108 * Open device driver and assign CEC file descriptor.
110 * @return If success to assign CEC file descriptor, return fd; otherwise, return -1.
117 if ((fd = open(CEC_DEVICE_NAME, O_RDWR)) < 0) {
118 _E("Can't open %s!\n", CEC_DEVICE_NAME);
126 * Close CEC file descriptor.
128 * @return If success to close CEC file descriptor, return 1; otherwise, return 0.
135 if (close(fd) != 0) {
136 _E("close() failed!\n");
146 * Allocate logical address.
148 * @param paddr [in] CEC device physical address.
149 * @param devtype [in] CEC device type.
151 * @return new logical address, or 0 if an error occured.
153 int CECAllocLogicalAddress(int paddr, enum CECDeviceType devtype)
155 unsigned char laddr = CEC_LADDR_UNREGISTERED;
158 _I("physical %x type %d", paddr, devtype);
160 _E("open device first!\n");
164 if (CECSetLogicalAddr(laddr) < 0) {
165 _E("CECSetLogicalAddr() failed!\n");
169 if (paddr == CEC_NOT_VALID_PHYSICAL_ADDRESS)
170 return CEC_LADDR_UNREGISTERED;
172 /* send "Polling Message" */
173 while (i < sizeof(laddresses) / sizeof(laddresses[0])) {
174 if (laddresses[i].devtype == devtype) {
175 unsigned char _laddr = laddresses[i].laddr;
176 unsigned char message = ((_laddr << 4) | _laddr);
177 if (CECSendMessage(&message, 1) != 1) {
179 _I("find logical address %x %d", laddresses[i].laddr, laddresses[i].devtype);
186 if (laddr == CEC_LADDR_UNREGISTERED) {
187 _E("All LA addresses in use!!!\n");
188 return CEC_LADDR_UNREGISTERED;
191 if (CECSetLogicalAddr(laddr) < 0) {
192 _E("CECSetLogicalAddr() failed!\n");
196 /* broadcast "Report Physical Address" */
197 unsigned char buffer[5];
198 buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
199 buffer[1] = CEC_OPCODE_REPORT_PHYSICAL_ADDRESS;
200 buffer[2] = (paddr >> 8) & 0xFF;
201 buffer[3] = paddr & 0xFF;
204 if (CECSendMessage(buffer, 5) != 5) {
205 _E("CECSendMessage() failed!\n");
215 * @param *buffer [in] pointer to buffer address where message located.
216 * @param size [in] message size.
218 * @return number of bytes written, or 0 if an error occured.
220 int CECSendMessage(unsigned char *buffer, int size)
223 _E("open device first!\n");
227 if (size > CEC_MAX_FRAME_SIZE) {
228 _E("size should not exceed %d\n", CEC_MAX_FRAME_SIZE);
233 _I("CECSendMessage() : size(%d)", size);
234 CECPrintFrame(buffer, size);
236 _I("CEC send : 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X",
237 buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7],
238 buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15] );
240 return write(fd, buffer, size);
244 * Receive CEC message.
246 * @param *buffer [in] pointer to buffer address where message will be stored.
247 * @param size [in] buffer size.
248 * @param timeout [in] timeout in microseconds.
250 * @return number of bytes received, or 0 if an error occured.
252 int CECReceiveMessage(unsigned char *buffer, int size, long timeout)
260 _E("open device first!\n");
265 tv.tv_usec = timeout;
270 retval = select(fd + 1, &rfds, NULL, NULL, &tv);
276 bytes = read(fd, buffer, size);
278 _I("CECReceiveMessage() : size(%d)", bytes);
280 CECPrintFrame(buffer, bytes);
288 * Set CEC logical address.
290 * @return 1 if success, otherwise, return 0.
292 int CECSetLogicalAddr(unsigned int laddr)
294 if (ioctl(fd, CEC_IOC_SETLADDR, &laddr)) {
295 _E("ioctl(CEC_IOC_SETLA) failed!\n");
302 int init_input_key_fd(void)
304 struct uinput_user_dev uidev;
305 int key_idx = sizeof(supportkeys)/sizeof(supportkeys[0]);
308 key_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
313 memset(&uidev, 0, sizeof(uidev));
314 snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "cec-input");
315 uidev.id.bustype = BUS_USB;
316 uidev.id.version = 1;
318 uidev.id.product = 1;
319 ioctl(key_fd, UI_SET_EVBIT, EV_KEY);
321 while (--key_idx >= 0) {
322 if (CEC_OPCODE_USER_CONTROL_PRESSED == supportkeys[key_idx].opcode ||
323 CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN == supportkeys[key_idx].opcode) {
324 ioctl (key_fd, UI_SET_KEYBIT, supportkeys[key_idx].ui_id);
325 _I("register key %s key(%d)",
326 supportkeys[key_idx].key_name,
327 supportkeys[key_idx].ui_id);
330 write (key_fd, &uidev, sizeof(uidev));
331 ioctl(key_fd, UI_DEV_CREATE);
336 static int input_key_event(unsigned char opcode, unsigned int key)
338 struct input_event ev;
341 if (opcode != CEC_OPCODE_USER_CONTROL_PRESSED &&
342 opcode != CEC_OPCODE_USER_CONTROL_RELEASED &&
343 opcode != CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN &&
344 opcode != CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP) {
345 _E("unregister key event opcode(0x%X) key(%d)", opcode, key);
348 memset(&ev, 0, sizeof(ev));
351 if (opcode == CEC_OPCODE_USER_CONTROL_PRESSED ||
352 opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN)
353 ev.value = CEC_KEY_PRESSED;
355 ev.value = CEC_KEY_RELEASED;
356 ret = write(key_fd, &ev, sizeof(ev));
363 * @return 1 if success, otherwise, return 0.
365 int CECReportKey(unsigned int key)
367 int key_idx = sizeof(supportkeys)/sizeof(supportkeys[0]);
369 while (--key_idx >= 0) {
370 if (key == supportkeys[key_idx].ui_id) {
371 _I("%s %d", supportkeys[key_idx].key_name, key);
375 // if (ioctl(fd, CEC_IOC_HANDLEKEY, &key)) {
376 _E("ioctl(CEC_IOC_HANDLEKEY) failed!");
387 void CECPrintFrame(unsigned char *buffer, unsigned int size)
391 _I("fsize: %d ", size);
393 for (i = 0; i < size; i++)
394 _I("0x%02x ", buffer[i]);
404 * @param opcode [in] pointer to buffer address where message will be stored.
405 * @param lsrc [in] buffer size.
407 * @return 1 if message should be ignored, otherwise, return 0.
410 int CECIgnoreMessage(unsigned char opcode, unsigned char lsrc)
414 /* if a message coming from address 15 (unregistered) */
415 if (lsrc == CEC_LADDR_UNREGISTERED) {
417 case CEC_OPCODE_DECK_CONTROL:
418 case CEC_OPCODE_PLAY:
431 * @param opcode [in] pointer to buffer address where message will be stored.
432 * @param size [in] message size.
434 * @return 0 if message should be ignored, otherwise, return 1.
437 int CECCheckMessageSize(unsigned char opcode, int size)
442 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
443 case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
444 case CEC_OPCODE_IMAGE_VIEW_ON:
445 case CEC_OPCODE_TEXT_VIEW_ON:
449 case CEC_OPCODE_PLAY:
450 case CEC_OPCODE_DECK_CONTROL:
451 case CEC_OPCODE_SET_MENU_LANGUAGE:
452 case CEC_OPCODE_ACTIVE_SOURCE:
453 case CEC_OPCODE_ROUTING_INFORMATION:
457 case CEC_OPCODE_SET_STREAM_PATH:
461 case CEC_OPCODE_FEATURE_ABORT:
462 case CEC_OPCODE_DEVICE_VENDOR_ID:
463 case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
467 case CEC_OPCODE_ROUTING_CHANGE:
473 if (!(size > 5 && size <= 16))
486 * @param opcode [in] pointer to buffer address where message will be stored.
487 * @param broadcast [in] broadcast/direct message.
489 * @return 0 if message should be ignored, otherwise, return 1.
492 int CECCheckMessageMode(unsigned char opcode, int broadcast)
497 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
498 case CEC_OPCODE_SET_MENU_LANGUAGE:
499 case CEC_OPCODE_ACTIVE_SOURCE:
503 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
504 case CEC_OPCODE_DECK_CONTROL:
505 case CEC_OPCODE_PLAY:
506 case CEC_OPCODE_USER_CONTROL_PRESSED:
507 case CEC_OPCODE_FEATURE_ABORT:
508 case CEC_OPCODE_ABORT:
520 * handle key message.
522 * @param opcode [in] opcode.
523 * @param key [in] received key
526 void CECHandleKey(unsigned char opcode, unsigned char key)
529 int key_idx = sizeof(supportkeys)/sizeof(supportkeys[0]);
531 while (--key_idx >= 0) {
532 if (opcode == supportkeys[key_idx].opcode &&
533 key == supportkeys[key_idx].cec_id)
539 _I("[CEC] %s(opcode 0x%X,key 0x%X(key code %d)",
540 supportkeys[key_idx].key_name, (int)opcode, (int)key, supportkeys[key_idx].ui_id);
541 ret = input_key_event(supportkeys[key_idx].opcode, supportkeys[key_idx].ui_id);
543 _E("ioctl(CEC_IOC_HANDLEKEY) failed! (fd %d %d: err[%s])", key_fd, ret, strerror(errno));
545 _E("[CEC] 0x%X 0x%X is not supported key\n", opcode, key);
550 * process CEC OneTouchPlay
552 * OneTouchPlay is disabled at normal case
553 * Enable : "adb shell setprop persist.hdmi.onetouch_enabled 1"
557 void CECOneTouchPlay(unsigned char *buffer, int laddr, int paddr)
560 unsigned char ldst = buffer[0] >> 4;
561 unsigned char opcode = buffer[1];
563 buffer[0] = (laddr << 4) | ldst;
564 buffer[1] = CEC_OPCODE_TEXT_VIEW_ON;
566 _I("Tx : [CEC_OPCODE_TEXT_VIEW_ON]");
569 if (CECSendMessage(buffer, size) != size)
570 _E("CECSendMessage() failed!!!");
574 buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
575 buffer[1] = CEC_OPCODE_ACTIVE_SOURCE;
576 buffer[2] = (paddr >> 8) & 0xFF;
577 buffer[3] = paddr & 0xFF;
579 _I("Tx : [CEC_OPCODE_ACTIVE_SOURCE]");
581 if (CECSendMessage(buffer, size) != size)
582 _E("CECSendMessage() failed!!!");
587 * process CEC message.
589 * @param buffer [in/out] pointer to buffer address where message will be stored.
590 * @param laddr [in] logical address
591 * @param paddr [in] physical address
593 * @return return size of CEC message to send.
595 int CECProcessOpcode(unsigned char *buffer, int laddr, int paddr, int raddr)
598 unsigned char ldst = buffer[0] >> 4;
599 unsigned char opcode = buffer[1];
602 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
603 /* responce with "Report Physical Address" */
604 buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
605 buffer[1] = CEC_OPCODE_REPORT_PHYSICAL_ADDRESS;
606 buffer[2] = (paddr >> 8) & 0xFF;
607 buffer[3] = paddr & 0xFF;
608 buffer[4] = CEC_DEVICE_PLAYER;
611 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
612 _I("[CEC_OPCODE_REQUEST_ACTIVE_SOURCE 0x%X]", opcode);
613 if( raddr != paddr ) {
614 _I("Not Currently active source r:0x0%x p:0x0%x", raddr, paddr);
617 buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
618 buffer[1] = CEC_OPCODE_ACTIVE_SOURCE;
619 buffer[2] = (paddr >> 8) & 0xFF;
620 buffer[3] = paddr & 0xFF;
622 _I("Tx : [CEC_OPCODE_ACTIVE_SOURCE 0x%X]", CEC_OPCODE_ACTIVE_SOURCE);
624 case CEC_OPCODE_IMAGE_VIEW_ON:
625 case CEC_OPCODE_TEXT_VIEW_ON:
626 _I("[CEC_OPCODE_IMAGE_VIEW_ON 0x%X]", opcode);
627 buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
628 buffer[1] = CEC_OPCODE_ACTIVE_SOURCE;
629 buffer[2] = (paddr >> 8) & 0xFF;
630 buffer[3] = paddr & 0xFF;
632 _I("Tx : [CEC_OPCODE_ACTIVE_SOURCE 0x%X]", CEC_OPCODE_ACTIVE_SOURCE);
634 case CEC_OPCODE_SET_STREAM_PATH: //11.2.2-3 test
635 _I("[CEC_OPCODE_SET_STREAM_PATH 0x%X]", opcode);
636 buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
637 buffer[1] = CEC_OPCODE_ACTIVE_SOURCE;
639 buffer[2] = (paddr >> 8) & 0xFF;
640 buffer[3] = paddr & 0xFF;
643 _I("Tx : [CEC_OPCODE_ACTIVE_SOURCE 0x%X]", CEC_OPCODE_ACTIVE_SOURCE);
644 CECReportKey(KEY_HOMEPAGE);
646 case CEC_OPCODE_MENU_REQUEST:
647 _I("[CEC_OPCODE_MENU_REQUEST 0x%X]", opcode);
648 buffer[0] = (laddr << 4) | ldst;
649 buffer[1] = CEC_OPCODE_MENU_STATUS;
650 buffer[2] = 0x0;/*active*/
652 _I("Tx : [CEC_OPCODE_MENU_STATUS 0x%X]", CEC_OPCODE_MENU_STATUS);
654 case CEC_OPCODE_GET_DEVICE_VENDOR_ID:
655 _I("[CEC_OPCODE_GET_DEVICE_VENDOR_ID 0x%X]", opcode);
656 buffer[0] = (laddr << 4) | ldst;
657 buffer[1] = CEC_OPCODE_DEVICE_VENDOR_ID;
662 _I("Tx : [CEC_OPCODE_GET_DEVICE_VENDOR_ID 0x%X]", CEC_OPCODE_DEVICE_VENDOR_ID);
664 case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
665 _I("[CEC_OPCODE_VENDOR_COMMAND_WITH_ID 0x%X] : %2X%2X%2X", opcode,
666 buffer[2], buffer[3], buffer[4]);
668 case CEC_OPCODE_GET_CEC_VERSION:
669 buffer[0] = (laddr << 4) | ldst;
670 buffer[1] = CEC_OPCODE_CEC_VERSION;
673 _I("Tx : [CEC_OPCODE_CEC_VERSION 0x%X] : 0x%X", CEC_OPCODE_CEC_VERSION, buffer[2]);
675 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
676 _I("[CEC_OPCODE_GIVE_DEVICE_POWER_STATUS 0x%X]", opcode);
677 buffer[0] = (laddr << 4) | ldst;
678 buffer[1] = CEC_OPCODE_REPORT_POWER_STATUS;
681 _I("Tx : [CEC_OPCODE_REPORT_POWER_STATUS 0x%X]", CEC_OPCODE_REPORT_POWER_STATUS);
683 case CEC_OPCODE_REPORT_POWER_STATUS:
684 _I("[CEC_OPCODE_REPORT_POWER_STATUS 0x%X]", opcode);
685 CECOneTouchPlay(buffer, laddr, paddr);
687 case CEC_OPCODE_STANDBY:
688 _I("CEC_OPCODE_STANDBY 0x%X", opcode);
689 CECHandleKey(opcode, buffer[1]);
691 case CEC_OPCODE_ROUTING_CHANGE:
692 _I("CEC_OPCODE_ROUTING_CHANGE 0x%X r:0x0%x p:0x0%x", opcode, raddr, paddr);
694 CECHandleKey(opcode, buffer[1]);
695 _I("CEC_OPCODE_ROUTING_CHANGE Send HomeKey");
698 case CEC_OPCODE_GIVE_OSD_NAME:
699 _I("CEC_OPCODE_GIVE_OSD_NAME 0x%X", opcode);
700 buffer[0] = (laddr << 4) | ldst;
701 buffer[1] = CEC_OPCODE_SET_OSD_NAME;
715 _I("Tx : [CEC_OPCODE_SET_OSD_NAME 0x%X]", CEC_OPCODE_SET_OSD_NAME);
717 case CEC_OPCODE_USER_CONTROL_PRESSED:
718 case CEC_OPCODE_USER_CONTROL_RELEASED:
719 case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
720 case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
721 case CEC_OPCODE_DECK_CONTROL:
722 case CEC_OPCODE_PLAY:
723 CECHandleKey(opcode, buffer[2]);
725 case CEC_OPCODE_ABORT:
726 case CEC_OPCODE_FEATURE_ABORT:
728 /* send "Feature Abort" */
729 buffer[0] = (laddr << 4) | ldst;
730 buffer[1] = CEC_OPCODE_FEATURE_ABORT;
731 buffer[2] = CEC_OPCODE_ABORT;
732 buffer[3] = 0x04; // "refused"