1 #include <minix/blockdriver.h>
2 #include <minix/drivers.h>
5 #include <minix/i2cdriver.h>
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
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
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
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
116 #define HDMI_PAGE_SELECT_REG 0xff
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
= {
140 .log_level
= LEVEL_INFO
,
141 .log_func
= default_log
144 static void sef_local_startup(void);
145 static int sef_cb_lu_state_save(int);
146 static int lu_state_restore(void);
147 static int sef_cb_init(int type
, sef_init_info_t
* info
);
150 static int is_display_connected(void);
151 static int enable_hdmi_module(void);
154 static int set_page(uint8_t page
);
155 static int hdmi_read(uint8_t page
, uint8_t reg
, uint8_t * val
);
156 static int hdmi_write(uint8_t page
, uint8_t reg
, uint8_t val
);
157 static int hdmi_set(uint8_t page
, uint8_t reg
, uint8_t mask
);
158 static int hdmi_clear(uint8_t page
, uint8_t reg
, uint8_t mask
);
160 static int hdmi_ddc_enable(void);
161 static int hdmi_init(void);
162 static int check_revision(void);
163 static int read_edid(uint8_t * data
, size_t count
);
165 /* libblockdriver callbacks */
166 static int tda19988_blk_open(devminor_t minor
, int access
);
167 static int tda19988_blk_close(devminor_t minor
);
168 static ssize_t
tda19988_blk_transfer(devminor_t minor
, int do_write
, u64_t pos
,
169 endpoint_t endpt
, iovec_t
* iov
, unsigned int count
, int flags
);
170 static int tda19988_blk_ioctl(devminor_t minor
, unsigned long request
,
171 endpoint_t endpt
, cp_grant_id_t grant
, endpoint_t user_endpt
);
172 static struct device
*tda19988_blk_part(devminor_t minor
);
173 static void tda19988_blk_other(message
* m
, int ipc_status
);
175 /* Entry points into the device dependent code of block drivers. */
176 struct blockdriver tda19988_tab
= {
177 .bdr_type
= BLOCKDRIVER_TYPE_OTHER
,
178 .bdr_open
= tda19988_blk_open
,
179 .bdr_close
= tda19988_blk_close
,
180 .bdr_transfer
= tda19988_blk_transfer
,
181 .bdr_ioctl
= tda19988_blk_ioctl
, /* always returns ENOTTY */
182 .bdr_part
= tda19988_blk_part
,
183 .bdr_other
= tda19988_blk_other
/* for notify events from DS */
186 /* counts the number of times a device file is open */
187 static int openct
[NR_DEVS
];
189 /* base and size of each device */
190 static struct device geom
[NR_DEVS
];
193 tda19988_blk_open(devminor_t minor
, int access
)
195 log_trace(&log
, "tda19988_blk_open(%d,%d)\n", minor
, access
);
196 if (tda19988_blk_part(minor
) == NULL
) {
206 tda19988_blk_close(devminor_t minor
)
208 log_trace(&log
, "tda19988_blk_close(%d)\n", minor
);
209 if (tda19988_blk_part(minor
) == NULL
) {
213 if (openct
[minor
] < 1) {
214 log_warn(&log
, "closing unopened device %d\n", minor
);
223 tda19988_blk_transfer(devminor_t minor
, int do_write
, u64_t pos64
,
224 endpoint_t endpt
, iovec_t
* iov
, unsigned int nr_req
, int flags
)
232 log_trace(&log
, "tda19988_blk_transfer()\n");
234 /* Get minor device information. */
235 dv
= tda19988_blk_part(minor
);
240 if (nr_req
> NR_IOREQS
) {
244 dv_size
= dv
->dv_size
;
245 if (pos64
>= dv_size
) {
246 return OK
; /* Beyond EOF */
251 /* How much to transfer and where to / from. */
252 count
= iov
->iov_size
;
253 grant
= (cp_grant_id_t
) iov
->iov_addr
;
256 if (pos64
>= dv_size
) {
260 /* don't go past the end of the device */
261 if (pos64
+ count
> dv_size
) {
262 count
= dv_size
- pos64
;
265 /* don't overflow copybuf */
266 if (count
> COPYBUF_SIZE
) {
267 count
= COPYBUF_SIZE
;
270 log_debug(&log
, "transfering 0x%x bytes\n", count
);
274 log_warn(&log
, "Error: writing to read-only device\n");
279 if (is_display_connected() == 1) {
284 "Failed to enable HDMI module\n");
288 memset(copybuf
, '\0', COPYBUF_SIZE
);
289 r
= read_edid(copybuf
, count
);
292 "read_edid() failed (r=%d)\n", r
);
296 r
= sys_safecopyto(endpt
, grant
, (vir_bytes
)
297 0, (vir_bytes
) copybuf
, count
);
299 log_warn(&log
, "safecopyto failed\n");
303 return iov
->iov_size
;
305 log_warn(&log
, "Display not connected.\n");
317 tda19988_blk_ioctl(devminor_t minor
, unsigned long request
, endpoint_t endpt
,
318 cp_grant_id_t grant
, endpoint_t
UNUSED(user_endpt
))
320 log_trace(&log
, "tda19988_blk_ioctl(%d)\n", minor
);
321 /* no supported ioctls for this device */
325 static struct device
*
326 tda19988_blk_part(devminor_t minor
)
328 log_trace(&log
, "tda19988_blk_part(%d)\n", minor
);
330 if (minor
< 0 || minor
>= NR_DEVS
) {
338 tda19988_blk_other(message
* m
, int ipc_status
)
340 log_trace(&log
, "tda19988_blk_other(0x%x)\n", m
->m_type
);
342 if (is_ipc_notify(ipc_status
)) {
343 if (m
->m_source
== DS_PROC_NR
) {
345 "bus driver changed state, update endpoint\n");
346 i2cdriver_handle_bus_update(&cec_bus_endpoint
, cec_bus
,
348 i2cdriver_handle_bus_update(&hdmi_bus_endpoint
,
349 hdmi_bus
, hdmi_address
);
352 log_warn(&log
, "Invalid message type (0x%x)\n", m
->m_type
);
357 * Check to see if a display is connected.
358 * Returns 1 for yes, 0 for no, -1 for error.
361 is_display_connected(void)
366 r
= i2creg_read8(cec_bus_endpoint
, cec_address
, CEC_STATUS_REG
, &val
);
368 log_warn(&log
, "Reading connection status failed (r=%d)\n", r
);
372 if ((CEC_STATUS_CONNECTED_MASK
& val
) == 0) {
373 log_debug(&log
, "No Display Detected\n");
376 log_debug(&log
, "Display Detected\n");
382 * Enable all the modules and clocks.
385 enable_hdmi_module(void)
389 r
= i2creg_write8(cec_bus_endpoint
, cec_address
, CEC_ENABLE_REG
,
390 CEC_ENABLE_ALL_MASK
);
392 log_warn(&log
, "Writing enable bits failed (r=%d)\n", r
);
396 log_debug(&log
, "HDMI module enabled\n");
402 set_page(uint8_t page
)
405 static int current_page
= HDMI_PAGELESS
;
407 if (page
!= current_page
) {
409 r
= i2creg_write8(hdmi_bus_endpoint
, hdmi_address
,
410 HDMI_PAGE_SELECT_REG
, page
);
422 hdmi_read_block(uint8_t page
, uint8_t reg
, uint8_t * buf
, size_t buflen
)
426 minix_i2c_ioctl_exec_t ioctl_exec
;
428 if (buf
== NULL
|| buflen
> I2C_EXEC_MAX_BUFLEN
) {
430 "Read block called with NULL pointer or invalid buflen.\n");
434 if (page
!= HDMI_PAGELESS
) {
437 log_warn(&log
, "Unable to set page to 0x%x\n", page
);
442 memset(&ioctl_exec
, '\0', sizeof(minix_i2c_ioctl_exec_t
));
445 ioctl_exec
.iie_op
= I2C_OP_READ_WITH_STOP
;
446 ioctl_exec
.iie_addr
= hdmi_address
;
448 /* write the register address */
449 ioctl_exec
.iie_cmd
[0] = reg
;
450 ioctl_exec
.iie_cmdlen
= 1;
453 ioctl_exec
.iie_buflen
= buflen
;
455 r
= i2cdriver_exec(hdmi_bus_endpoint
, &ioctl_exec
);
457 log_warn(&log
, "hdmi_read() failed (r=%d)\n", r
);
461 memcpy(buf
, ioctl_exec
.iie_buf
, buflen
);
463 log_trace(&log
, "Read %d bytes from reg 0x%x in page 0x%x\n", buflen
,
470 hdmi_read(uint8_t page
, uint8_t reg
, uint8_t * val
)
476 log_warn(&log
, "Read called with NULL pointer\n");
480 if (page
!= HDMI_PAGELESS
) {
483 log_warn(&log
, "Unable to set page to 0x%x\n", page
);
488 r
= i2creg_read8(hdmi_bus_endpoint
, hdmi_address
, reg
, val
);
490 log_warn(&log
, "hdmi_read() failed (r=%d)\n", r
);
494 log_trace(&log
, "Read 0x%x from reg 0x%x in page 0x%x\n", *val
, reg
,
501 hdmi_write(uint8_t page
, uint8_t reg
, uint8_t val
)
505 if (page
!= HDMI_PAGELESS
) {
508 log_warn(&log
, "Unable to set page to 0x%x\n", page
);
513 r
= i2creg_write8(hdmi_bus_endpoint
, hdmi_address
, reg
, val
);
515 log_warn(&log
, "hdmi_write() failed (r=%d)\n", r
);
519 log_trace(&log
, "Successfully wrote 0x%x to reg 0x%x in page 0x%x\n",
526 hdmi_set(uint8_t page
, uint8_t reg
, uint8_t mask
)
534 r
= hdmi_read(page
, reg
, &val
);
541 r
= hdmi_write(page
, reg
, val
);
550 hdmi_clear(uint8_t page
, uint8_t reg
, uint8_t mask
)
558 r
= hdmi_read(page
, reg
, &val
);
565 r
= hdmi_write(page
, reg
, val
);
581 r
= hdmi_read(HDMI_CTRL_PAGE
, HDMI_CTRL_REV_LO_REG
, &rev_lo
);
583 log_warn(&log
, "Failed to read rev_lo (r=%d)\n", r
);
587 r
= hdmi_read(HDMI_CTRL_PAGE
, HDMI_CTRL_REV_HI_REG
, &rev_hi
);
589 log_warn(&log
, "Failed to read rev_hi (r=%d)\n", r
);
593 revision
= ((rev_hi
<< 8) | rev_lo
);
594 if (revision
!= HDMI_REV_TDA19988
) {
596 log_warn(&log
, "Unrecognized value in revision registers.\n");
597 log_warn(&log
, "Read: 0x%x | Expected: 0x%x\n", revision
,
602 log_debug(&log
, "Device Revision: 0x%x\n", revision
);
608 hdmi_ddc_enable(void)
612 /* Soft Reset DDC Bus */
613 r
= hdmi_set(HDMI_CTRL_PAGE
, HDMI_CTRL_RESET_REG
,
614 HDMI_CTRL_RESET_DDC_MASK
);
619 r
= hdmi_clear(HDMI_CTRL_PAGE
, HDMI_CTRL_RESET_REG
,
620 HDMI_CTRL_RESET_DDC_MASK
);
627 r
= hdmi_write(HDMI_CTRL_PAGE
, HDMI_CTRL_DDC_CTRL_REG
,
628 HDMI_CTRL_DDC_EN_MASK
);
633 /* Setup the clock (I think) */
634 r
= hdmi_write(HDMI_CTRL_PAGE
, HDMI_CTRL_DDC_CLK_REG
,
635 HDMI_CTRL_DDC_CLK_EN_MASK
);
640 r
= hdmi_write(HDMI_HDCP_OTP_PAGE
, HDMI_HDCP_OTP_DDC_CLK_REG
,
641 HDMI_HDCP_OTP_DDC_CLK_MASK
);
645 log_debug(&log
, "DDC Enabled\n");
655 /* Turn on HDMI module (slave 0x70) */
656 r
= enable_hdmi_module();
658 log_warn(&log
, "HDMI Module Init Failed\n");
662 /* Read chip version to ensure compatibility */
663 r
= check_revision();
665 log_warn(&log
, "Couldn't find expected TDA19988 revision\n");
669 /* Turn on DDC interface between TDA19988 and display */
670 r
= hdmi_ddc_enable();
672 log_warn(&log
, "Failed to enable DDC\n");
680 read_edid(uint8_t * buf
, size_t count
)
688 log_debug(&log
, "Reading edid...\n");
690 if (buf
== NULL
|| count
< EDID_LEN
) {
691 log_warn(&log
, "Expected 128 byte data buffer\n");
695 r
= hdmi_clear(HDMI_HDCP_OTP_PAGE
, HDMI_HDCP_OTP_SOME_REG
,
696 HDMI_HDCP_OTP_SOME_MASK
);
698 log_warn(&log
, "Failed to clear bit in HDCP OTP reg\n");
702 /* Enable EDID Block Read Interrupt */
703 r
= hdmi_set(HDMI_CTRL_PAGE
, HDMI_CTRL_INT_REG
,
704 HDMI_CTRL_INT_EDID_MASK
);
706 log_warn(&log
, "Failed to enable EDID Block Read interrupt\n");
710 /* enable global interrupts */
711 r
= hdmi_write(HDMI_CTRL_PAGE
, HDMI_CTRL_INTR_CTRL_REG
,
712 HDMI_CTRL_INTR_EN_GLO_MASK
);
714 log_warn(&log
, "Failed to enable interrupts\n");
718 /* Set Device Address */
719 r
= hdmi_write(HDMI_EDID_PAGE
, HDMI_EDID_DEV_ADDR_REG
,
722 log_warn(&log
, "Couldn't set device address\n");
727 r
= hdmi_write(HDMI_EDID_PAGE
, HDMI_EDID_OFFSET_REG
, HDMI_EDID_OFFSET
);
729 log_warn(&log
, "Couldn't set offset\n");
733 /* Set Segment Pointer Address */
734 r
= hdmi_write(HDMI_EDID_PAGE
, HDMI_EDID_SEG_PTR_ADDR_REG
,
735 HDMI_EDID_SEG_PTR_ADDR
);
737 log_warn(&log
, "Couldn't set segment pointer address\n");
741 /* Set Segment Address */
742 r
= hdmi_write(HDMI_EDID_PAGE
, HDMI_EDID_SEG_ADDR_REG
,
745 log_warn(&log
, "Couldn't set segment address\n");
750 * Toggle EDID Read Request Bit to request a read.
753 r
= hdmi_write(HDMI_EDID_PAGE
, HDMI_EDID_REQ_REG
,
754 HDMI_EDID_REQ_READ_MASK
);
756 log_warn(&log
, "Couldn't set Read Request bit\n");
760 r
= hdmi_write(HDMI_EDID_PAGE
, HDMI_EDID_REQ_REG
, 0x00);
762 log_warn(&log
, "Couldn't clear Read Request bit\n");
766 log_debug(&log
, "Starting polling\n");
768 /* poll interrupt status flag */
770 for (tries
= 0; tries
< 100; tries
++) {
772 r
= hdmi_read(HDMI_CTRL_PAGE
, HDMI_CTRL_INT_REG
, &val
);
774 log_warn(&log
, "Read failed while polling int flag\n");
778 if (val
& HDMI_CTRL_INT_EDID_MASK
) {
779 log_debug(&log
, "Mask Set\n");
788 log_warn(&log
, "Data Ready interrupt never fired.\n");
792 log_debug(&log
, "Ready to read\n");
794 /* Finally, perform the read. */
795 memset(buf
, '\0', count
);
796 r
= hdmi_read_block(HDMI_EDID_PAGE
, HDMI_EDID_DATA_REG
, buf
, EDID_LEN
);
798 log_warn(&log
, "Failed to read EDID data\n");
802 /* Disable EDID Block Read Interrupt */
803 r
= hdmi_clear(HDMI_CTRL_PAGE
, HDMI_CTRL_INT_REG
,
804 HDMI_CTRL_INT_EDID_MASK
);
807 "Failed to disable EDID Block Read interrupt\n");
811 r
= hdmi_set(HDMI_HDCP_OTP_PAGE
, HDMI_HDCP_OTP_SOME_REG
,
812 HDMI_HDCP_OTP_SOME_MASK
);
814 log_warn(&log
, "Failed to set bit in HDCP/OTP reg\n");
818 log_debug(&log
, "Done EDID Reading\n");
824 sef_cb_lu_state_save(int UNUSED(state
))
826 ds_publish_u32("cec_bus", cec_bus
, DSF_OVERWRITE
);
827 ds_publish_u32("hdmi_bus", hdmi_bus
, DSF_OVERWRITE
);
828 ds_publish_u32("cec_address", cec_address
, DSF_OVERWRITE
);
829 ds_publish_u32("hdmi_address", hdmi_address
, DSF_OVERWRITE
);
834 lu_state_restore(void)
836 /* Restore the state. */
839 ds_retrieve_u32("cec_bus", &value
);
840 ds_delete_u32("cec_bus");
841 cec_bus
= (int) value
;
843 ds_retrieve_u32("hdmi_bus", &value
);
844 ds_delete_u32("hdmi_bus");
845 hdmi_bus
= (int) value
;
847 ds_retrieve_u32("cec_address", &value
);
848 ds_delete_u32("cec_address");
849 cec_address
= (int) value
;
851 ds_retrieve_u32("hdmi_address", &value
);
852 ds_delete_u32("hdmi_address");
853 hdmi_address
= (int) value
;
859 sef_cb_init(int type
, sef_init_info_t
* UNUSED(info
))
863 if (type
== SEF_INIT_LU
) {
864 /* Restore the state. */
868 geom
[TDA19988_DEV
].dv_base
= ((u64_t
) (0));
869 geom
[TDA19988_DEV
].dv_size
= ((u64_t
) (128));
875 /* look-up the endpoint for the bus driver */
876 cec_bus_endpoint
= i2cdriver_bus_endpoint(cec_bus
);
877 if (cec_bus_endpoint
== 0) {
878 log_warn(&log
, "Couldn't find bus driver.\n");
882 /* claim the device */
883 r
= i2cdriver_reserve_device(cec_bus_endpoint
, cec_address
);
885 log_warn(&log
, "Couldn't reserve device 0x%x (r=%d)\n",
894 /* look-up the endpoint for the bus driver */
895 hdmi_bus_endpoint
= i2cdriver_bus_endpoint(hdmi_bus
);
896 if (hdmi_bus_endpoint
== 0) {
897 log_warn(&log
, "Couldn't find bus driver.\n");
901 /* claim the device */
902 r
= i2cdriver_reserve_device(hdmi_bus_endpoint
, hdmi_address
);
904 log_warn(&log
, "Couldn't reserve device 0x%x (r=%d)\n",
909 if (type
!= SEF_INIT_LU
) {
911 /* sign up for updates about the i2c bus going down/up */
912 r
= i2cdriver_subscribe_bus_updates(cec_bus
);
914 log_warn(&log
, "Couldn't subscribe to bus updates\n");
918 /* sign up for updates about the i2c bus going down/up */
919 r
= i2cdriver_subscribe_bus_updates(hdmi_bus
);
921 log_warn(&log
, "Couldn't subscribe to bus updates\n");
925 i2cdriver_announce(cec_bus
);
926 if (cec_bus
!= hdmi_bus
) {
927 i2cdriver_announce(hdmi_bus
);
930 blockdriver_announce(type
);
931 log_trace(&log
, "announced\n");
938 sef_local_startup(void)
941 * Register init callbacks. Use the same function for all event types
943 sef_setcb_init_fresh(sef_cb_init
);
944 sef_setcb_init_lu(sef_cb_init
);
945 sef_setcb_init_restart(sef_cb_init
);
948 * Register live update callbacks.
950 /* Agree to update immediately when LU is requested in a valid state. */
951 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready
);
952 /* Support live update starting from any standard state. */
953 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard
);
954 /* Register a custom routine to save the state. */
955 sef_setcb_lu_state_save(sef_cb_lu_state_save
);
957 /* Let SEF perform startup. */
966 long int cec_addressl
;
968 long int hdmi_addressl
;
970 r
= env_parse("cec_bus", "d", 0, &cec_busl
, 1, 3);
974 cec_bus
= (uint32_t) cec_busl
;
976 r
= env_parse("cec_address", "x", 0, &cec_addressl
, 0x34, 0x37);
980 cec_address
= (i2c_addr_t
) cec_addressl
;
982 r
= env_parse("hdmi_bus", "d", 0, &hdmi_busl
, 1, 3);
986 hdmi_bus
= (uint32_t) hdmi_busl
;
988 r
= env_parse("hdmi_address", "x", 0, &hdmi_addressl
, 0x70, 0x73);
992 hdmi_address
= (i2c_addr_t
) hdmi_addressl
;
998 main(int argc
, char *argv
[])
1002 env_setargs(argc
, argv
);
1004 r
= tda19988_env_parse();
1007 "Expecting -args 'cec_bus=X cec_address=0xAA hdmi_bus=Y hdmi_address=0xBB'\n");
1009 "Example -args 'cec_bus=1 cec_address=0x34 hdmi_bus=1 hdmi_address=0x70'\n");
1010 return EXIT_FAILURE
;
1013 sef_local_startup();
1015 log_debug(&log
, "Startup Complete\n");
1016 blockdriver_task(&tda19988_tab
);
1017 log_debug(&log
, "Shutting down\n");