etc/services - sync with NetBSD-8
[minix.git] / minix / drivers / video / tda19988 / tda19988.c
blob7e0afa5d7b35e39218b246899b1e6070aabf7de2
1 #include <minix/blockdriver.h>
2 #include <minix/drivers.h>
3 #include <minix/ds.h>
4 #include <minix/i2c.h>
5 #include <minix/i2cdriver.h>
6 #include <minix/log.h>
8 #include <ctype.h>
9 #include <stdio.h>
10 #include <stdlib.h>
12 /* constants */
13 #define NR_DEVS 1 /* number of devices this driver handles */
14 #define TDA19988_DEV 0 /* index of TDA19988 device */
15 #define EDID_LEN 128 /* length of standard EDID block */
17 /* When passing data over a grant one needs to pass
18 * a buffer to sys_safecopy copybuff is used for that*/
19 #define COPYBUF_SIZE 0x1000 /* 4k buf */
20 static unsigned char copybuf[COPYBUF_SIZE];
22 /* The device has two I2C interfaces CEC (0x34) and HDMI (0x70). This driver
23 * needs access to both.
27 * CEC - Register and Bit Definitions
30 #define CEC_STATUS_REG 0xfe
31 #define CEC_STATUS_CONNECTED_MASK 0x02
33 #define CEC_ENABLE_REG 0xff
34 #define CEC_ENABLE_ALL_MASK 0x87
37 * HDMI - Pages
39 * The HDMI part is much bigger than the CEC part. Memory is accessed according
40 * to page and address. Once the page is set, only the address needs to be
41 * sent if accessing memory locations within the same page (you don't need to
42 * send the page number every time).
45 #define HDMI_CTRL_PAGE 0x00
46 #define HDMI_PPL_PAGE 0x02
47 #define HDMI_EDID_PAGE 0x09
48 #define HDMI_INFO_PAGE 0x10
49 #define HDMI_AUDIO_PAGE 0x11
50 #define HDMI_HDCP_OTP_PAGE 0x12
51 #define HDMI_GAMUT_PAGE 0x13
53 /*
54 * The page select register isn't part of a page. A dummy value of 0xff is
55 * used to signfiy this in the code.
57 #define HDMI_PAGELESS 0xff
60 * Control Page Registers and Bit Definitions
63 #define HDMI_CTRL_REV_LO_REG 0x00
64 #define HDMI_CTRL_REV_HI_REG 0x02
66 #define HDMI_CTRL_RESET_REG 0x0a
67 #define HDMI_CTRL_RESET_DDC_MASK 0x02
69 #define HDMI_CTRL_DDC_CTRL_REG 0x0b
70 #define HDMI_CTRL_DDC_EN_MASK 0x00
72 #define HDMI_CTRL_DDC_CLK_REG 0x0c
73 #define HDMI_CTRL_DDC_CLK_EN_MASK 0x01
75 #define HDMI_CTRL_INTR_CTRL_REG 0x0f
76 #define HDMI_CTRL_INTR_EN_GLO_MASK 0x04
78 #define HDMI_CTRL_INT_REG 0x11
79 #define HDMI_CTRL_INT_EDID_MASK 0x02
82 * EDID Page Registers and Bit Definitions
85 #define HDMI_EDID_DATA_REG 0x00
87 #define HDMI_EDID_DEV_ADDR_REG 0xfb
88 #define HDMI_EDID_DEV_ADDR 0xa0
90 #define HDMI_EDID_OFFSET_REG 0xfc
91 #define HDMI_EDID_OFFSET 0x00
93 #define HDMI_EDID_SEG_PTR_ADDR_REG 0xfc
94 #define HDMI_EDID_SEG_PTR_ADDR 0x00
96 #define HDMI_EDID_SEG_ADDR_REG 0xfe
97 #define HDMI_EDID_SEG_ADDR 0x00
99 #define HDMI_EDID_REQ_REG 0xfa
100 #define HDMI_EDID_REQ_READ_MASK 0x01
103 * HDCP and OTP
105 #define HDMI_HDCP_OTP_DDC_CLK_REG 0x9a
106 #define HDMI_HDCP_OTP_DDC_CLK_MASK 0x27
108 /* this register/mask isn't documented but it has to be cleared/set */
109 #define HDMI_HDCP_OTP_SOME_REG 0x9b
110 #define HDMI_HDCP_OTP_SOME_MASK 0x02
113 * Pageless Registers
116 #define HDMI_PAGE_SELECT_REG 0xff
119 * Constants
122 /* Revision of the TDA19988. */
123 #define HDMI_REV_TDA19988 0x0331
125 /* the bus that this device is on (counting starting at 1) */
126 static uint32_t cec_bus;
127 static uint32_t hdmi_bus;
129 /* slave address of the device */
130 static i2c_addr_t cec_address;
131 static i2c_addr_t hdmi_address;
133 /* endpoint for the driver for the bus itself. */
134 static endpoint_t cec_bus_endpoint;
135 static endpoint_t hdmi_bus_endpoint;
137 /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
138 static struct log log = {
139 .name = "tda19988",
140 .log_level = LEVEL_INFO,
141 .log_func = default_log
144 /* CEC Module */
145 static int is_display_connected(void);
146 static int enable_hdmi_module(void);
148 /* HDMI Module */
149 static int set_page(uint8_t page);
150 static int hdmi_read(uint8_t page, uint8_t reg, uint8_t * val);
151 static int hdmi_write(uint8_t page, uint8_t reg, uint8_t val);
152 static int hdmi_set(uint8_t page, uint8_t reg, uint8_t mask);
153 static int hdmi_clear(uint8_t page, uint8_t reg, uint8_t mask);
155 static int hdmi_ddc_enable(void);
156 static int hdmi_init(void);
157 static int check_revision(void);
158 static int read_edid(uint8_t * data, size_t count);
160 /* libblockdriver callbacks */
161 static int tda19988_blk_open(devminor_t minor, int access);
162 static int tda19988_blk_close(devminor_t minor);
163 static ssize_t tda19988_blk_transfer(devminor_t minor, int do_write, u64_t pos,
164 endpoint_t endpt, iovec_t * iov, unsigned int count, int flags);
165 static int tda19988_blk_ioctl(devminor_t minor, unsigned long request,
166 endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt);
167 static struct device *tda19988_blk_part(devminor_t minor);
168 static void tda19988_blk_other(message * m, int ipc_status);
170 /* Entry points into the device dependent code of block drivers. */
171 struct blockdriver tda19988_tab = {
172 .bdr_type = BLOCKDRIVER_TYPE_OTHER,
173 .bdr_open = tda19988_blk_open,
174 .bdr_close = tda19988_blk_close,
175 .bdr_transfer = tda19988_blk_transfer,
176 .bdr_ioctl = tda19988_blk_ioctl, /* always returns ENOTTY */
177 .bdr_part = tda19988_blk_part,
178 .bdr_other = tda19988_blk_other /* for notify events from DS */
181 /* counts the number of times a device file is open */
182 static int openct[NR_DEVS];
184 /* base and size of each device */
185 static struct device geom[NR_DEVS];
187 static int
188 tda19988_blk_open(devminor_t minor, int access)
190 log_trace(&log, "tda19988_blk_open(%d,%d)\n", minor, access);
191 if (tda19988_blk_part(minor) == NULL) {
192 return ENXIO;
195 openct[minor]++;
197 return OK;
200 static int
201 tda19988_blk_close(devminor_t minor)
203 log_trace(&log, "tda19988_blk_close(%d)\n", minor);
204 if (tda19988_blk_part(minor) == NULL) {
205 return ENXIO;
208 if (openct[minor] < 1) {
209 log_warn(&log, "closing unopened device %d\n", minor);
210 return EINVAL;
212 openct[minor]--;
214 return OK;
217 static ssize_t
218 tda19988_blk_transfer(devminor_t minor, int do_write, u64_t pos64,
219 endpoint_t endpt, iovec_t * iov, unsigned int nr_req, int flags)
221 unsigned count;
222 struct device *dv;
223 u64_t dv_size;
224 int r;
225 cp_grant_id_t grant;
227 log_trace(&log, "tda19988_blk_transfer()\n");
229 /* Get minor device information. */
230 dv = tda19988_blk_part(minor);
231 if (dv == NULL) {
232 return ENXIO;
235 if (nr_req > NR_IOREQS) {
236 return EINVAL;
239 dv_size = dv->dv_size;
240 if (pos64 >= dv_size) {
241 return OK; /* Beyond EOF */
244 if (nr_req > 0) {
246 /* How much to transfer and where to / from. */
247 count = iov->iov_size;
248 grant = (cp_grant_id_t) iov->iov_addr;
250 /* check for EOF */
251 if (pos64 >= dv_size) {
252 return 0;
255 /* don't go past the end of the device */
256 if (pos64 + count > dv_size) {
257 count = dv_size - pos64;
260 /* don't overflow copybuf */
261 if (count > COPYBUF_SIZE) {
262 count = COPYBUF_SIZE;
265 log_debug(&log, "transfering 0x%x bytes\n", count);
267 if (do_write) {
269 log_warn(&log, "Error: writing to read-only device\n");
270 return EACCES;
272 } else {
274 if (is_display_connected() == 1) {
276 r = hdmi_init();
277 if (r != OK) {
278 log_warn(&log,
279 "Failed to enable HDMI module\n");
280 return EIO;
283 memset(copybuf, '\0', COPYBUF_SIZE);
284 r = read_edid(copybuf, count);
285 if (r != OK) {
286 log_warn(&log,
287 "read_edid() failed (r=%d)\n", r);
288 return r;
291 r = sys_safecopyto(endpt, grant, (vir_bytes)
292 0, (vir_bytes) copybuf, count);
293 if (r != OK) {
294 log_warn(&log, "safecopyto failed\n");
295 return EINVAL;
298 return iov->iov_size;
299 } else {
300 log_warn(&log, "Display not connected.\n");
301 return ENODEV;
304 } else {
306 /* empty request */
307 return 0;
311 static int
312 tda19988_blk_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
313 cp_grant_id_t grant, endpoint_t UNUSED(user_endpt))
315 log_trace(&log, "tda19988_blk_ioctl(%d)\n", minor);
316 /* no supported ioctls for this device */
317 return ENOTTY;
320 static struct device *
321 tda19988_blk_part(devminor_t minor)
323 log_trace(&log, "tda19988_blk_part(%d)\n", minor);
325 if (minor < 0 || minor >= NR_DEVS) {
326 return NULL;
329 return &geom[minor];
332 static void
333 tda19988_blk_other(message * m, int ipc_status)
335 log_trace(&log, "tda19988_blk_other(0x%x)\n", m->m_type);
337 if (is_ipc_notify(ipc_status)) {
338 if (m->m_source == DS_PROC_NR) {
339 log_debug(&log,
340 "bus driver changed state, update endpoint\n");
341 i2cdriver_handle_bus_update(&cec_bus_endpoint, cec_bus,
342 cec_address);
343 i2cdriver_handle_bus_update(&hdmi_bus_endpoint,
344 hdmi_bus, hdmi_address);
346 } else {
347 log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
352 * Check to see if a display is connected.
353 * Returns 1 for yes, 0 for no, -1 for error.
355 static int
356 is_display_connected(void)
358 int r;
359 uint8_t val;
361 r = i2creg_read8(cec_bus_endpoint, cec_address, CEC_STATUS_REG, &val);
362 if (r != OK) {
363 log_warn(&log, "Reading connection status failed (r=%d)\n", r);
364 return -1;
367 if ((CEC_STATUS_CONNECTED_MASK & val) == 0) {
368 log_debug(&log, "No Display Detected\n");
369 return 0;
370 } else {
371 log_debug(&log, "Display Detected\n");
372 return 1;
377 * Enable all the modules and clocks.
379 static int
380 enable_hdmi_module(void)
382 int r;
384 r = i2creg_write8(cec_bus_endpoint, cec_address, CEC_ENABLE_REG,
385 CEC_ENABLE_ALL_MASK);
386 if (r != OK) {
387 log_warn(&log, "Writing enable bits failed (r=%d)\n", r);
388 return -1;
391 log_debug(&log, "HDMI module enabled\n");
393 return OK;
396 static int
397 set_page(uint8_t page)
399 int r;
400 static int current_page = HDMI_PAGELESS;
402 if (page != current_page) {
404 r = i2creg_write8(hdmi_bus_endpoint, hdmi_address,
405 HDMI_PAGE_SELECT_REG, page);
406 if (r != OK) {
407 return r;
410 current_page = page;
413 return OK;
416 static int
417 hdmi_read_block(uint8_t page, uint8_t reg, uint8_t * buf, size_t buflen)
420 int r;
421 minix_i2c_ioctl_exec_t ioctl_exec;
423 if (buf == NULL || buflen > I2C_EXEC_MAX_BUFLEN) {
424 log_warn(&log,
425 "Read block called with NULL pointer or invalid buflen.\n");
426 return EINVAL;
429 if (page != HDMI_PAGELESS) {
430 r = set_page(page);
431 if (r != OK) {
432 log_warn(&log, "Unable to set page to 0x%x\n", page);
433 return r;
437 memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
439 /* Read from HDMI */
440 ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
441 ioctl_exec.iie_addr = hdmi_address;
443 /* write the register address */
444 ioctl_exec.iie_cmd[0] = reg;
445 ioctl_exec.iie_cmdlen = 1;
447 /* read bytes */
448 ioctl_exec.iie_buflen = buflen;
450 r = i2cdriver_exec(hdmi_bus_endpoint, &ioctl_exec);
451 if (r != OK) {
452 log_warn(&log, "hdmi_read() failed (r=%d)\n", r);
453 return -1;
456 memcpy(buf, ioctl_exec.iie_buf, buflen);
458 log_trace(&log, "Read %d bytes from reg 0x%x in page 0x%x\n", buflen,
459 reg, page);
461 return OK;
464 static int
465 hdmi_read(uint8_t page, uint8_t reg, uint8_t * val)
468 int r;
470 if (val == NULL) {
471 log_warn(&log, "Read called with NULL pointer\n");
472 return EINVAL;
475 if (page != HDMI_PAGELESS) {
476 r = set_page(page);
477 if (r != OK) {
478 log_warn(&log, "Unable to set page to 0x%x\n", page);
479 return r;
483 r = i2creg_read8(hdmi_bus_endpoint, hdmi_address, reg, val);
484 if (r != OK) {
485 log_warn(&log, "hdmi_read() failed (r=%d)\n", r);
486 return -1;
489 log_trace(&log, "Read 0x%x from reg 0x%x in page 0x%x\n", *val, reg,
490 page);
492 return OK;
495 static int
496 hdmi_write(uint8_t page, uint8_t reg, uint8_t val)
498 int r;
500 if (page != HDMI_PAGELESS) {
501 r = set_page(page);
502 if (r != OK) {
503 log_warn(&log, "Unable to set page to 0x%x\n", page);
504 return r;
508 r = i2creg_write8(hdmi_bus_endpoint, hdmi_address, reg, val);
509 if (r != OK) {
510 log_warn(&log, "hdmi_write() failed (r=%d)\n", r);
511 return -1;
514 log_trace(&log, "Successfully wrote 0x%x to reg 0x%x in page 0x%x\n",
515 val, reg, page);
517 return OK;
520 static int
521 hdmi_set(uint8_t page, uint8_t reg, uint8_t mask)
524 int r;
525 uint8_t val;
527 val = 0x00;
529 r = hdmi_read(page, reg, &val);
530 if (r != OK) {
531 return r;
534 val |= mask;
536 r = hdmi_write(page, reg, val);
537 if (r != OK) {
538 return r;
541 return OK;
544 static int
545 hdmi_clear(uint8_t page, uint8_t reg, uint8_t mask)
548 int r;
549 uint8_t val;
551 val = 0x00;
553 r = hdmi_read(page, reg, &val);
554 if (r != OK) {
555 return r;
558 val &= ~mask;
560 r = hdmi_write(page, reg, val);
561 if (r != OK) {
562 return r;
565 return OK;
568 static int
569 check_revision(void)
571 int r;
572 uint8_t rev_lo;
573 uint8_t rev_hi;
574 uint16_t revision;
576 r = hdmi_read(HDMI_CTRL_PAGE, HDMI_CTRL_REV_LO_REG, &rev_lo);
577 if (r != OK) {
578 log_warn(&log, "Failed to read rev_lo (r=%d)\n", r);
579 return -1;
582 r = hdmi_read(HDMI_CTRL_PAGE, HDMI_CTRL_REV_HI_REG, &rev_hi);
583 if (r != OK) {
584 log_warn(&log, "Failed to read rev_hi (r=%d)\n", r);
585 return -1;
588 revision = ((rev_hi << 8) | rev_lo);
589 if (revision != HDMI_REV_TDA19988) {
591 log_warn(&log, "Unrecognized value in revision registers.\n");
592 log_warn(&log, "Read: 0x%x | Expected: 0x%x\n", revision,
593 HDMI_REV_TDA19988);
594 return -1;
597 log_debug(&log, "Device Revision: 0x%x\n", revision);
599 return OK;
602 static int
603 hdmi_ddc_enable(void)
605 int r;
607 /* Soft Reset DDC Bus */
608 r = hdmi_set(HDMI_CTRL_PAGE, HDMI_CTRL_RESET_REG,
609 HDMI_CTRL_RESET_DDC_MASK);
610 if (r != OK) {
611 return r;
613 micro_delay(100000);
614 r = hdmi_clear(HDMI_CTRL_PAGE, HDMI_CTRL_RESET_REG,
615 HDMI_CTRL_RESET_DDC_MASK);
616 if (r != OK) {
617 return r;
619 micro_delay(100000);
621 /* Enable DDC */
622 r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_DDC_CTRL_REG,
623 HDMI_CTRL_DDC_EN_MASK);
624 if (r != OK) {
625 return r;
628 /* Setup the clock (I think) */
629 r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_DDC_CLK_REG,
630 HDMI_CTRL_DDC_CLK_EN_MASK);
631 if (r != OK) {
632 return r;
635 r = hdmi_write(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_DDC_CLK_REG,
636 HDMI_HDCP_OTP_DDC_CLK_MASK);
637 if (r != OK) {
638 return r;
640 log_debug(&log, "DDC Enabled\n");
642 return OK;
645 static int
646 hdmi_init(void)
648 int r;
650 /* Turn on HDMI module (slave 0x70) */
651 r = enable_hdmi_module();
652 if (r != OK) {
653 log_warn(&log, "HDMI Module Init Failed\n");
654 return -1;
657 /* Read chip version to ensure compatibility */
658 r = check_revision();
659 if (r != OK) {
660 log_warn(&log, "Couldn't find expected TDA19988 revision\n");
661 return -1;
664 /* Turn on DDC interface between TDA19988 and display */
665 r = hdmi_ddc_enable();
666 if (r != OK) {
667 log_warn(&log, "Failed to enable DDC\n");
668 return -1;
671 return OK;
674 static int
675 read_edid(uint8_t * buf, size_t count)
677 int r;
678 int i, j;
679 int tries;
680 int edid_ready;
681 uint8_t val;
683 log_debug(&log, "Reading edid...\n");
685 if (buf == NULL || count < EDID_LEN) {
686 log_warn(&log, "Expected 128 byte data buffer\n");
687 return -1;
690 r = hdmi_clear(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_SOME_REG,
691 HDMI_HDCP_OTP_SOME_MASK);
692 if (r != OK) {
693 log_warn(&log, "Failed to clear bit in HDCP OTP reg\n");
694 return -1;
697 /* Enable EDID Block Read Interrupt */
698 r = hdmi_set(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG,
699 HDMI_CTRL_INT_EDID_MASK);
700 if (r != OK) {
701 log_warn(&log, "Failed to enable EDID Block Read interrupt\n");
702 return -1;
705 /* enable global interrupts */
706 r = hdmi_write(HDMI_CTRL_PAGE, HDMI_CTRL_INTR_CTRL_REG,
707 HDMI_CTRL_INTR_EN_GLO_MASK);
708 if (r != OK) {
709 log_warn(&log, "Failed to enable interrupts\n");
710 return -1;
713 /* Set Device Address */
714 r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_DEV_ADDR_REG,
715 HDMI_EDID_DEV_ADDR);
716 if (r != OK) {
717 log_warn(&log, "Couldn't set device address\n");
718 return -1;
721 /* Set Offset */
722 r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_OFFSET_REG, HDMI_EDID_OFFSET);
723 if (r != OK) {
724 log_warn(&log, "Couldn't set offset\n");
725 return -1;
728 /* Set Segment Pointer Address */
729 r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_SEG_PTR_ADDR_REG,
730 HDMI_EDID_SEG_PTR_ADDR);
731 if (r != OK) {
732 log_warn(&log, "Couldn't set segment pointer address\n");
733 return -1;
736 /* Set Segment Address */
737 r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_SEG_ADDR_REG,
738 HDMI_EDID_SEG_ADDR);
739 if (r != OK) {
740 log_warn(&log, "Couldn't set segment address\n");
741 return -1;
745 * Toggle EDID Read Request Bit to request a read.
748 r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_REQ_REG,
749 HDMI_EDID_REQ_READ_MASK);
750 if (r != OK) {
751 log_warn(&log, "Couldn't set Read Request bit\n");
752 return -1;
755 r = hdmi_write(HDMI_EDID_PAGE, HDMI_EDID_REQ_REG, 0x00);
756 if (r != OK) {
757 log_warn(&log, "Couldn't clear Read Request bit\n");
758 return -1;
761 log_debug(&log, "Starting polling\n");
763 /* poll interrupt status flag */
764 edid_ready = 0;
765 for (tries = 0; tries < 100; tries++) {
767 r = hdmi_read(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG, &val);
768 if (r != OK) {
769 log_warn(&log, "Read failed while polling int flag\n");
770 return -1;
773 if (val & HDMI_CTRL_INT_EDID_MASK) {
774 log_debug(&log, "Mask Set\n");
775 edid_ready = 1;
776 break;
779 micro_delay(1000);
782 if (!edid_ready) {
783 log_warn(&log, "Data Ready interrupt never fired.\n");
784 return EBUSY;
787 log_debug(&log, "Ready to read\n");
789 /* Finally, perform the read. */
790 memset(buf, '\0', count);
791 r = hdmi_read_block(HDMI_EDID_PAGE, HDMI_EDID_DATA_REG, buf, EDID_LEN);
792 if (r != OK) {
793 log_warn(&log, "Failed to read EDID data\n");
794 return -1;
797 /* Disable EDID Block Read Interrupt */
798 r = hdmi_clear(HDMI_CTRL_PAGE, HDMI_CTRL_INT_REG,
799 HDMI_CTRL_INT_EDID_MASK);
800 if (r != OK) {
801 log_warn(&log,
802 "Failed to disable EDID Block Read interrupt\n");
803 return -1;
806 r = hdmi_set(HDMI_HDCP_OTP_PAGE, HDMI_HDCP_OTP_SOME_REG,
807 HDMI_HDCP_OTP_SOME_MASK);
808 if (r != OK) {
809 log_warn(&log, "Failed to set bit in HDCP/OTP reg\n");
810 return -1;
813 log_debug(&log, "Done EDID Reading\n");
815 return OK;
818 static int
819 sef_cb_lu_state_save(int UNUSED(result), int UNUSED(flags))
821 ds_publish_u32("cec_bus", cec_bus, DSF_OVERWRITE);
822 ds_publish_u32("hdmi_bus", hdmi_bus, DSF_OVERWRITE);
823 ds_publish_u32("cec_address", cec_address, DSF_OVERWRITE);
824 ds_publish_u32("hdmi_address", hdmi_address, DSF_OVERWRITE);
825 return OK;
828 static int
829 lu_state_restore(void)
831 /* Restore the state. */
832 u32_t value;
834 ds_retrieve_u32("cec_bus", &value);
835 ds_delete_u32("cec_bus");
836 cec_bus = (int) value;
838 ds_retrieve_u32("hdmi_bus", &value);
839 ds_delete_u32("hdmi_bus");
840 hdmi_bus = (int) value;
842 ds_retrieve_u32("cec_address", &value);
843 ds_delete_u32("cec_address");
844 cec_address = (int) value;
846 ds_retrieve_u32("hdmi_address", &value);
847 ds_delete_u32("hdmi_address");
848 hdmi_address = (int) value;
850 return OK;
853 static int
854 sef_cb_init(int type, sef_init_info_t * UNUSED(info))
856 int r;
858 if (type == SEF_INIT_LU) {
859 /* Restore the state. */
860 lu_state_restore();
863 geom[TDA19988_DEV].dv_base = ((u64_t) (0));
864 geom[TDA19988_DEV].dv_size = ((u64_t) (128));
867 * CEC Module
870 /* look-up the endpoint for the bus driver */
871 cec_bus_endpoint = i2cdriver_bus_endpoint(cec_bus);
872 if (cec_bus_endpoint == 0) {
873 log_warn(&log, "Couldn't find bus driver.\n");
874 return EXIT_FAILURE;
877 /* claim the device */
878 r = i2cdriver_reserve_device(cec_bus_endpoint, cec_address);
879 if (r != OK) {
880 log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
881 cec_address, r);
882 return EXIT_FAILURE;
886 * HDMI Module
889 /* look-up the endpoint for the bus driver */
890 hdmi_bus_endpoint = i2cdriver_bus_endpoint(hdmi_bus);
891 if (hdmi_bus_endpoint == 0) {
892 log_warn(&log, "Couldn't find bus driver.\n");
893 return EXIT_FAILURE;
896 /* claim the device */
897 r = i2cdriver_reserve_device(hdmi_bus_endpoint, hdmi_address);
898 if (r != OK) {
899 log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
900 hdmi_address, r);
901 return EXIT_FAILURE;
904 if (type != SEF_INIT_LU) {
906 /* sign up for updates about the i2c bus going down/up */
907 r = i2cdriver_subscribe_bus_updates(cec_bus);
908 if (r != OK) {
909 log_warn(&log, "Couldn't subscribe to bus updates\n");
910 return EXIT_FAILURE;
913 /* sign up for updates about the i2c bus going down/up */
914 r = i2cdriver_subscribe_bus_updates(hdmi_bus);
915 if (r != OK) {
916 log_warn(&log, "Couldn't subscribe to bus updates\n");
917 return EXIT_FAILURE;
920 i2cdriver_announce(cec_bus);
921 if (cec_bus != hdmi_bus) {
922 i2cdriver_announce(hdmi_bus);
925 blockdriver_announce(type);
926 log_trace(&log, "announced\n");
929 return OK;
932 static void
933 sef_local_startup(void)
936 * Register init callbacks. Use the same function for all event types
938 sef_setcb_init_fresh(sef_cb_init);
939 sef_setcb_init_lu(sef_cb_init);
940 sef_setcb_init_restart(sef_cb_init);
943 * Register live update callbacks.
945 sef_setcb_lu_state_save(sef_cb_lu_state_save);
947 /* Let SEF perform startup. */
948 sef_startup();
951 static int
952 tda19988_env_parse()
954 int r;
955 long int cec_busl;
956 long int cec_addressl;
957 long int hdmi_busl;
958 long int hdmi_addressl;
960 r = env_parse("cec_bus", "d", 0, &cec_busl, 1, 3);
961 if (r != EP_SET) {
962 return -1;
964 cec_bus = (uint32_t) cec_busl;
966 r = env_parse("cec_address", "x", 0, &cec_addressl, 0x34, 0x37);
967 if (r != EP_SET) {
968 return -1;
970 cec_address = (i2c_addr_t) cec_addressl;
972 r = env_parse("hdmi_bus", "d", 0, &hdmi_busl, 1, 3);
973 if (r != EP_SET) {
974 return -1;
976 hdmi_bus = (uint32_t) hdmi_busl;
978 r = env_parse("hdmi_address", "x", 0, &hdmi_addressl, 0x70, 0x73);
979 if (r != EP_SET) {
980 return -1;
982 hdmi_address = (i2c_addr_t) hdmi_addressl;
984 return OK;
988 main(int argc, char *argv[])
990 int r;
992 env_setargs(argc, argv);
994 r = tda19988_env_parse();
995 if (r < 0) {
996 log_warn(&log,
997 "Expecting -args 'cec_bus=X cec_address=0xAA hdmi_bus=Y hdmi_address=0xBB'\n");
998 log_warn(&log,
999 "Example -args 'cec_bus=1 cec_address=0x34 hdmi_bus=1 hdmi_address=0x70'\n");
1000 return EXIT_FAILURE;
1003 sef_local_startup();
1005 log_debug(&log, "Startup Complete\n");
1006 blockdriver_task(&tda19988_tab);
1007 log_debug(&log, "Shutting down\n");
1009 return OK;