/* * (c) 2020, SWD Embedded Systems Limited, http://www.kpda.ru */ /*************************************************/ /* HEADERS */ /*************************************************/ #include "vpoutfb.h" /*************************************************/ /* VARS / DEFS */ /*************************************************/ static char *vpout_opts[] = { #define VPOUT_OPT_DISPMODE 0 "dispmode", #define VPOUT_OPT_BASE 1 "base", #define VPOUT_OPT_SIZE 2 "size", #define VPOUT_OPT_IRQ 3 "irq", #define VPOUT_OPT_HDMI 4 "hdmi", #define VPOUT_OPT_ENABLE 5 "enable", #define VPOUT_OPT_VERBOSE 6 "verbose", NULL }; int verbose = VPOUT_SLOG_LEVEL_0; /*************************************************/ /* FUNCTIONS */ /*************************************************/ int parse_options( disp_adapter_t *adapter, vpout_context_t *vpout, char *filename ) { FILE *fin = NULL; char buf[256], *c = NULL, *opt = NULL, *value = NULL; char path[255]; if ( (filename == NULL) || ( strlen( filename ) == 0 ) ) { int fd = 0; strcpy( path, "/etc/system/config/vpoutfb.conf" ); fd = open( path, O_RDONLY ); if ( fd != -1 ) { close( fd ); filename = path; } } if ( (filename == NULL) || ( strlen( filename ) == 0 ) ) { /* Fatal: configuration file not found */ } else if ( (fin = fopen( filename, "r" )) == NULL ) disp_printf( adapter, "[vpoutfb] Critical: could not open config file \"%s\": %s", filename, strerror( errno ) ); else disp_printf( adapter, "[vpoutfb] Configuration: \"%s\"", filename ); vpout->display[0] = CONFIG_DISPLAY_PORT_HDMI0; vpout->enabled = 0; vpout->registers_size = 0x1000; if ( fin == NULL ) { disp_printf( adapter, "[vpoutfb] Fatal: configuration file not found" ); return (-1); } while ( fgets( buf, sizeof (buf), fin ) != NULL ) { c = buf; while ( *c == ' ' || *c == '\t' ) c++; if ( *c == '\015' || *c== '\032' || *c == '\0' || *c == '\n' || *c == '#' ) continue; opt = c; while ( *c == '\015' || *c== '\032' || (*c != '\0' && *c != '\n' && *c != '#') ) c++; *c = '\0'; break; } while ( *opt != '\0' ) { c = opt; switch ( getsubopt( &opt, vpout_opts, &value ) ) { case VPOUT_OPT_DISPMODE: if ( strcmp( value, "hdmi-0" ) == 0 ) { vpout->display[0] = CONFIG_DISPLAY_PORT_HDMI0; disp_printf( adapter, "[vpoutfb] Configuration: display[0] -> HDMI-0" ); } else disp_printf( adapter, "[vpoutfb] Warning: unknown display configuration (see vpoutfb.conf)" ); break; case VPOUT_OPT_BASE: vpout->registers_base = strtoul( value, NULL, 0 ); disp_printf( adapter, "[vpoutfb] Configuration: display controller registers base - 0x%08x", vpout->registers_base ); break; case VPOUT_OPT_SIZE: vpout->registers_size = strtoul( value, NULL, 0 ); disp_printf( adapter, "[vpoutfb] Configuration: display controller registers size - 0x%x", vpout->registers_size ); break; case VPOUT_OPT_IRQ: vpout->irq = strtoul( value, NULL, 0 ); disp_printf( adapter, "[vpoutfb] Configuration: display controller interrupt - %d", vpout->irq ); break; case VPOUT_OPT_HDMI: if ( strncmp( value, VPOUT_OPT_HDMI_IT66121":", strlen( VPOUT_OPT_HDMI_IT66121 ) + 1 ) == 0 ) { char *name = value; int bus; int address; int speed; int base; int reg; int pin; value += strlen( VPOUT_OPT_HDMI_IT66121 ); *value= 0; value++; if ( sscanf( value, "%d:0x%x:%d:0x%x:0x%x:%d", &bus, &address, &speed, &base, ®, &pin ) == 6 ) { if ( bus < 0 || bus > 3 ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C bus invalid (see vpoutfb.conf)" ); break; } if ( address < 0 || address > 0xffff ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C address invalid (see vpoutfb.conf)" ); break; } if ( speed <= 0 ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C speed invalid (see vpoutfb.conf)" ); break; } if ( base <= 0 ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter GPIO base invalid (see vpoutfb.conf)" ); break; } if ( reg < 0xa || reg > 0xd ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter GPIO register invalid (see vpoutfb.conf: [0xa; 0xd] expected)" ); break; } if ( vpout->hdmi_count >= VPOUT_HDMI_PORTS ) { disp_printf( adapter, "[vpoutfb] Error: only %d HDMI ports supported", VPOUT_HDMI_PORTS ); break; } vpout->hdmi[vpout->hdmi_count].assigned = true; strcpy( vpout->hdmi[vpout->hdmi_count].transmitter, name ); vpout->hdmi[vpout->hdmi_count].device.it66121.bus = bus; vpout->hdmi[vpout->hdmi_count].device.it66121.address = address; vpout->hdmi[vpout->hdmi_count].device.it66121.speed = speed; vpout->hdmi[vpout->hdmi_count].device.it66121.base = base; vpout->hdmi[vpout->hdmi_count].device.it66121.reg = reg; vpout->hdmi[vpout->hdmi_count].device.it66121.pin = pin; vpout->hdmi_count++; disp_printf( adapter, "[vpoutfb] Configuration: HDMI[%d] - controller:%s I2C:bus=%d,address=0x%x,speed=%d GPIO:base=0x%x,reg=GPIO%X,pin=%d", vpout->hdmi_count - 1, name, bus, address, speed * 1000, base, reg, pin ); break; } } else if ( strncmp( value, VPOUT_OPT_HDMI_TDA998x":", strlen( VPOUT_OPT_HDMI_TDA998x ) + 1 ) == 0 ) { char *name = value; int bus; int address; int speed; int video_ports = 0; value += strlen( VPOUT_OPT_HDMI_TDA998x ); *value= 0; value++; if ( sscanf( value, "%d:0x%x:%d:0x%x", &bus, &address, &speed, &video_ports ) == 4 ) { if ( bus < 0 || bus > 3 ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C bus invalid (see vpoutfb.conf)" ); break; } if ( address < 0 || address > 0xffff ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C address invalid (see vpoutfb.conf)" ); break; } if ( speed <= 0 ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C speed invalid (see vpoutfb.conf)" ); break; } if ( vpout->hdmi_count >= VPOUT_HDMI_PORTS ) { disp_printf( adapter, "[vpoutfb] Error: only %d HDMI ports supported", VPOUT_HDMI_PORTS ); break; } vpout->hdmi[vpout->hdmi_count].assigned = true; strcpy( vpout->hdmi[vpout->hdmi_count].transmitter, name ); vpout->hdmi[vpout->hdmi_count].device.tda998x.bus = bus; vpout->hdmi[vpout->hdmi_count].device.tda998x.address = address; vpout->hdmi[vpout->hdmi_count].device.tda998x.speed = speed; vpout->hdmi[vpout->hdmi_count].device.tda998x.video_ports = video_ports; vpout->hdmi_count++; disp_printf( adapter, "[vpoutfb] Configuration: HDMI[%d] - controller:%s I2C:bus=%d,address=0x%x,speed=%d", vpout->hdmi_count - 1, name, bus, address, speed * 1000 ); break; } } else if ( strncmp( value, VPOUT_OPT_HDMI_TFP410EP":", strlen( VPOUT_OPT_HDMI_TFP410EP ) + 1 ) == 0 ) { char *name = value; int bus; int address; int speed; int ddc_bus; int ddc_slave; value += strlen( VPOUT_OPT_HDMI_TFP410EP ); *value= 0; value++; if ( sscanf( value, "%d:0x%x:%d:%d:0x%x", &bus, &address, &speed, &ddc_bus, &ddc_slave ) == 5 ) { if ( bus < 0 || bus > 3 ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C bus invalid (see vpoutfb.conf)" ); break; } if ( address < 0 || address > 0xffff ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C address invalid (see vpoutfb.conf)" ); break; } if ( speed <= 0 ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter I2C speed invalid (see vpoutfb.conf)" ); break; } if ( ddc_bus < 0 || ddc_bus > 2 ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter DDC bus invalid (see vpoutfb.conf)" ); break; } if ( ddc_slave < 0 || ddc_slave > 0x7f ) { disp_printf( adapter, "[vpoutfb] Error: HDMI transmitter DDC slave invalid (see vpoutfb.conf)" ); break; } if ( vpout->hdmi_count >= VPOUT_HDMI_PORTS ) { disp_printf( adapter, "[vpoutfb] Error: only %d HDMI ports supported", VPOUT_HDMI_PORTS ); break; } vpout->hdmi[vpout->hdmi_count].assigned = true; strcpy( vpout->hdmi[vpout->hdmi_count].transmitter, name ); vpout->hdmi[vpout->hdmi_count].device.tfp410ep.bus = bus; vpout->hdmi[vpout->hdmi_count].device.tfp410ep.address = address; vpout->hdmi[vpout->hdmi_count].device.tfp410ep.speed = speed; vpout->hdmi[vpout->hdmi_count].device.tfp410ep.ddc_bus = ddc_bus; vpout->hdmi[vpout->hdmi_count].device.tfp410ep.ddc_slave = ddc_slave; vpout->hdmi_count++; disp_printf( adapter, "[vpoutfb] Configuration: HDMI[%d] - controller:%s I2C:bus=%d,address=0x%x,speed=%d,ddc-bus=%d,ddc-slave=0x%x", vpout->hdmi_count - 1, name, bus, address, speed * 1000, ddc_bus, ddc_slave ); break; } } disp_printf( adapter, "[vpoutfb] Warning: unknown HDMI transmitter configuration (see vpoutfb.conf; configuration->\"%s\")", value ); break; case VPOUT_OPT_ENABLE: if ( strstr( value, "lcd_sync_fix" ) != NULL ) { disp_printf( adapter, "[vpoutfb] Configuration: LCD sync generation fix enabled" ); vpout->enabled |= CONFIG_ENABLE_LCD_SYNC_FIX; } break; case VPOUT_OPT_VERBOSE: if ( strstr( value, "silent" ) != NULL ) { disp_printf( adapter, "[vpoutfb] Configuration: \"silent\" output level" ); verbose = VPOUT_SLOG_LEVEL_0; } else if ( strstr( value, "warn" ) != NULL ) { disp_printf( adapter, "[vpoutfb] Configuration: \"warn\" output level" ); verbose = VPOUT_SLOG_LEVEL_WARNING; } else if ( strstr( value, "info" ) != NULL ) { disp_printf( adapter, "[vpoutfb] Configuration: \"info\" output level" ); verbose = VPOUT_SLOG_LEVEL_INFO; } else if ( strstr( value, "debug" ) != NULL ) { disp_printf( adapter, "[vpoutfb] Configuration: \"debug\" output level" ); verbose = VPOUT_SLOG_LEVEL_DEBUG; } else disp_printf( adapter, "[vpoutfb] Warning: unknown verbosity level (see vpoutfb.conf)" ); break; default: disp_printf( adapter, "[vpoutfb] Unknown option %s", c ); break; } } fclose( fin ); /* Error detection */ #define CONFIG_ERROR( text ) { disp_printf( adapter, text ); return (-1); } /* base option */ if ( vpout->registers_base == 0 ) CONFIG_ERROR( "[vpoutfb] Fatal: unknown display controller registers base phys-address (see vpoutfb.conf)" ); /* size option */ if ( vpout->registers_size == 0 ) disp_printf( adapter, "[vpoutfb] Warning: using display controller default registers size (see vpoutfb.conf)" ); /* irq option */ if ( vpout->irq == 0 ) disp_printf( adapter, "[vpoutfb] Warning: unknown display controller interrupt (see vpoutfb.conf)" ); /* dispmode option */ switch ( vpout->display[0] ) { case CONFIG_DISPLAY_PORT_HDMI0: if ( !vpout->hdmi[DISPLAY_PORT_INDEX( CONFIG_DISPLAY_PORT_HDMI0 )].assigned ) CONFIG_ERROR( "[vpoutfb] Fatal: damaged display controller configuration (see vpoutfb.conf::hdmi option)" ); break; } return (0); }