aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpk33 <pk33@pk33.space>2024-11-01 23:51:15 +0100
committerpk33 <pk33@pk33.space>2024-11-01 23:51:15 +0100
commit294b585994da4427ac98a8353ff41aed5f301d54 (patch)
treeaafcd885c1fe28819ef1a511da5e6344411b5597 /src
parentf0958551b43959174d28b2056f584d2081494e6c (diff)
downloadengine33-294b585994da4427ac98a8353ff41aed5f301d54.tar.gz
Import and fix old code
Diffstat (limited to 'src')
-rw-r--r--src/clock.c19
-rw-r--r--src/display.c623
-rw-r--r--src/logger.c77
-rw-r--r--src/main.c54
-rw-r--r--src/system.c29
5 files changed, 802 insertions, 0 deletions
diff --git a/src/clock.c b/src/clock.c
new file mode 100644
index 0000000..7cb5ec3
--- /dev/null
+++ b/src/clock.c
@@ -0,0 +1,19 @@
+#include "sys/time.h"
+
+#include "clock.h"
+
+
+Size clock_get_us( void )
+{
+ static struct timeval tv;
+ gettimeofday( &tv, 0 );
+ return (tv.tv_sec * 1000000) + tv.tv_usec;
+}
+
+f64 clock_get_s_hires( void )
+{
+ static struct timeval tv;
+ gettimeofday( &tv, 0 );
+ return (f64)((f64)tv.tv_sec + ((f64)tv.tv_usec / 1000000));
+}
+
diff --git a/src/display.c b/src/display.c
new file mode 100644
index 0000000..69c7bb2
--- /dev/null
+++ b/src/display.c
@@ -0,0 +1,623 @@
+#include "string.h"
+#include "stdlib.h"
+#include "signal.h"
+#include "fcntl.h"
+#include "errno.h"
+#include "termios.h"
+#include "unistd.h"
+#include "poll.h"
+#include "dirent.h"
+#include "termio.h"
+#include "stdio.h"
+
+#include "libdrm/drm_mode.h"
+#include "sys/vt.h"
+#include "sys/kd.h"
+
+#include "sys/ioctl.h"
+#include "sys/mman.h"
+
+#include "display.h"
+#include "system.h"
+#include "logger.h"
+
+
+#define REL_SIGNAL SIGUSR1
+#define ACQ_SIGNAL SIGUSR2
+#define REL_EVENT 1
+#define ACQ_EVENT 2
+
+
+Display __display = {0};
+
+
+typedef struct {
+ struct drm_mode_card_res drmRes;
+ __u64 *drmRes_fbs;
+ __u32 *drmRes_conns;
+ __u64 *drmRes_encs;
+ __u64 *drmRes_crtcs;
+
+ struct drm_mode_get_connector connector;
+ __u64 connProps[ 16 ];
+ __u64 connPropVals[ 16 ];
+ __u64 connEncs[ 16 ];
+ struct drm_mode_modeinfo connModes[ 32 ];
+ struct drm_mode_modeinfo *mode;
+
+ struct drm_mode_create_dumb drmCreateDumb[2];
+ struct drm_mode_map_dumb drmMapDumb[2];
+ struct drm_mode_fb_cmd drmFBCmd[2];
+} DRMData_d;
+
+static DRMData_d drmData = {0,};
+
+static Size vtPipe[2] = { -1, -1 };
+
+static struct termios termOldConfig;
+
+
+static Size _get_drm_resources( Size fd );
+static Size _get_drm_connector( Size fd );
+static Size _get_drm_crtc( Size fd );
+static Size _get_drm_framebuffer( Size fd );
+
+static int _is_card( const struct dirent *f );
+static Size _open_graphics_device( Size *fd );
+
+static Size _init_vt_switch( void );
+static void _vt_release( void );
+static void _vt_acquire( void );
+static void _vt_switch_sighandler(int sig);
+static Size _has_signal(Size signo);
+static Size _set_signal(Size signo, void(*sig_handler)(int));
+
+
+Size display_init( void )
+{
+ Size i, fd;
+
+ struct termios termConfig;
+
+
+ if(!isatty(STDIN_FILENO)) {
+ logf( "stdin is not a terminal" );
+ return E33_EXIT_FAILURE;
+ }
+
+ if( tcgetattr(STDIN_FILENO, &termOldConfig) == -1 ) {
+ logf( "Could not get terminal attributes" );
+ return E33_EXIT_FAILURE;
+ }
+ else {
+ termConfig = termOldConfig;
+ termConfig.c_iflag &= ~(IGNBRK | BRKINT | PARMRK);
+ termConfig.c_lflag &= ~(ICANON | ECHO | IEXTEN | TOSTOP);
+ termConfig.c_lflag |= ISIG;
+ termConfig.c_cc[VTIME] = 0;
+ termConfig.c_cc[VMIN] = 0;
+ termConfig.c_cc[VSTART] = 0;
+ termConfig.c_cc[VSTOP] = 0;
+
+ if( tcsetattr(STDIN_FILENO, TCSANOW, &termConfig) == -1 ) {
+ logf( "Could not set terminal attributes" );
+ return E33_EXIT_FAILURE;
+ }
+ }
+
+ if( _init_vt_switch() ) {
+ logw( "Failed to initialize VT switcher. VT switching will not be available" );
+ }
+
+
+ if( _open_graphics_device( &fd ) ) {
+ logf( "Failed to find a suitable graphics device" );
+ return E33_EXIT_FAILURE;
+ }
+
+
+ if( e33_ioctl( fd, DRM_IOCTL_SET_MASTER, 0 ) == -1 )
+ {
+ logf( "Failed to set DRM master" );
+ return E33_EXIT_FAILURE;
+ }
+
+
+ if( _get_drm_resources( fd ) ) {
+ logf( "Failed to get resources" );
+ return E33_EXIT_FAILURE;
+ }
+ if( _get_drm_connector( fd ) ) {
+ logf( "Failed to set connector" );
+ return E33_EXIT_FAILURE;
+ }
+ if( _get_drm_framebuffer( fd ) ) {
+ logf( "Failed to set framebuffer" );
+ return E33_EXIT_FAILURE;
+ }
+ if( _get_drm_crtc( fd ) ) {
+ logf( "Failed to set crtc" );
+ return E33_EXIT_FAILURE;
+ }
+
+
+ __display.devFd = fd;
+ __display.surface.w = drmData.mode->hdisplay;
+ __display.surface.h = drmData.mode->vdisplay;
+ __display.fb.size = (Size)drmData.drmCreateDumb[0].size;
+ __display.surface.data = __display.fb.map[0];
+ __display.active = 1;
+
+
+ return E33_EXIT_SUCCESS;
+}
+
+void display_flip( void )
+{
+ static u8 i = 1;
+
+ struct drm_mode_crtc_page_flip flip = { 0, };
+
+ __display.surface.data = __display.fb.map[i];
+ i ^= 1;
+ __display.crtc.fb_id = __display.fb.id[i];
+
+ if( e33_ioctl( __display.devFd, (int)DRM_IOCTL_MODE_SETCRTC, &__display.crtc ) == -1 ) {
+ return;
+ }
+
+ flip.fb_id = __display.fb.id[i];
+ flip.crtc_id = __display.crtc.crtc_id;
+ flip.user_data = ((__u64)(&__display.crtc.crtc_id));
+ flip.flags = DRM_MODE_PAGE_FLIP_EVENT;
+
+ if( e33_ioctl( __display.devFd, (int)DRM_IOCTL_MODE_PAGE_FLIP, &flip ) == -1 ) {
+ return;
+ }
+
+ /* TODO remove later */
+ memset( __display.surface.data, 0, (uSize)__display.fb.size );
+}
+
+void display_term( void )
+{
+ if( e33_ioctl( __display.devFd, DRM_IOCTL_DROP_MASTER, 0 ) == -1 ) {
+ logw( "Failed to drop drm master. Oh well." );
+ }
+
+ if( ioctl(__display.ttyFd, VT_RELDISP, 1) == -1 ) {
+ logw( "Failed to drop release vt. Oh well." );
+ }
+
+ if( munmap( __display.fb.map[0], (uSize)__display.fb.size ) == -1 ) {
+ logw( "Failed to unmap framebuffer[0]. Oh well." );
+ }
+ if( munmap( __display.fb.map[1], (uSize)__display.fb.size ) == -1 ) {
+ logw( "Failed to unmap framebuffer[1]. Oh well." );
+ }
+
+ free( drmData.drmRes_fbs );
+ free( drmData.drmRes_crtcs );
+ free( drmData.drmRes_encs );
+ free( drmData.drmRes_conns );
+
+ if( close( __display.ttyFd ) == -1 ) {
+ logw( "Failed to close TTY. Oh well." );
+ }
+ if( close( __display.devFd ) ) {
+ logw( "Failed to close graphics device. Oh well." );
+ }
+
+ if( tcsetattr(STDIN_FILENO, TCSAFLUSH, &termOldConfig) == -1 ) {
+ logw( "Failed to set stdin attributes. Oh well." );
+ }
+}
+
+
+void display_vtswitcher_poll( int timeout )
+{
+ struct pollfd fds[1];
+ unsigned char event;
+
+ fds[0].fd = vtPipe[0];
+ fds[0].events = POLLIN;
+ fds[0].revents = 0;
+
+ poll( fds, 1, timeout );
+ if( !fds[0].revents ) {
+ return;
+ }
+
+ if( read(fds[0].fd, &event, sizeof(event)) != sizeof(event) ) {
+ logw( "Invalid VT switch events read");
+ return;
+ }
+
+ switch(event) {
+ case REL_EVENT: _vt_release();
+ break;
+ case ACQ_EVENT: _vt_acquire();
+ break;
+ }
+}
+
+static void _vt_release( void )
+{
+ logi( "VT release signal");
+
+ if( ioctl( __display.devFd, DRM_IOCTL_DROP_MASTER, 0 ) ) {
+ loge( "Could not drop DRM master" );
+ }
+
+ if( ioctl(__display.ttyFd, VT_RELDISP, 1) < 0 ) {
+ loge( "Failed to release VT");
+ }
+
+ __display.active = 0;
+}
+
+static void _vt_acquire( void )
+{
+ logi( "VT acquire signal");
+
+ if( ioctl( __display.devFd, DRM_IOCTL_SET_MASTER, 0 ) == -1 ) {
+ logw( "Could not become DRM master." );
+ }
+
+ if( ioctl(__display.ttyFd, VT_RELDISP, VT_ACKACQ) < 0 ) {
+ loge( "(vt_acquire) Failed to acquire VT.");
+ }
+
+ if( ioctl( __display.devFd, (int)DRM_IOCTL_MODE_SETCRTC, &__display.crtc ) == -1 ) {
+ loge( "Failed to set crtc on VT switch." );
+ }
+
+ __display.active = 1;
+}
+
+
+static int _set_pipe(int fd)
+{
+ if (fd >= 0)
+ {
+ int flags = fcntl(fd, F_GETFD);
+
+ if (flags == -1) {
+ logw( "Could not get flags for VT switcher pipe");
+ return E33_EXIT_FAILURE;
+ }
+
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ logw( "Could not set flags for VT switcher pipe");
+ return E33_EXIT_FAILURE;
+ }
+ }
+
+ return E33_EXIT_SUCCESS;
+}
+
+static Size _has_signal(Size signo)
+{
+ struct sigaction sact = {0};
+ sigaction(signo, 0, &sact);
+ return sact.sa_handler != 0;
+}
+
+static Size _set_signal(Size signo, void(*sig_handler)(int))
+{
+ struct sigaction sact = {0};
+ sact.sa_handler = sig_handler;
+ sigemptyset(&sact.sa_mask);
+ sact.sa_flags = SA_RESTART;
+ return sigaction(signo, &sact, NULL);
+}
+
+static void _vt_switch_sighandler(int sig)
+{
+ unsigned char event = REL_EVENT;
+
+ if( sig == ACQ_SIGNAL ) {
+ event = ACQ_EVENT;
+ }
+
+ (void)write( vtPipe[1], &event, sizeof(event) );
+}
+
+static Size _init_vt_switch( void )
+{
+ struct vt_mode vt_mode = {0,};
+ sigset_t set;
+
+ __display.ttyFd = -1;
+
+
+ /* Init VT pipes */
+ if (pipe(vtPipe) != 0) {
+ vtPipe[0] = vtPipe[1] = -1;
+ loge( "Could not set VT pipes");
+ return E33_EXIT_FAILURE;
+ }
+
+ if( _set_pipe(vtPipe[0]) ) {
+ loge( "Could not set VT read pipe" );
+ return E33_EXIT_FAILURE;
+ }
+ if( _set_pipe(vtPipe[1]) ) {
+ loge( "Could not set VT write pipe" );
+ return E33_EXIT_FAILURE;
+ }
+ /**/
+
+
+ if( __display.ttyFd = open("/dev/tty", O_RDWR | O_CLOEXEC ) < 0 ) {
+ loge( "Could not open TTY for VT control" );
+ return E33_EXIT_FAILURE;
+ }
+
+
+ /* Setup signals */
+ if( _has_signal(REL_SIGNAL) ) {
+ loge( "VT release signal is already in use");
+ return E33_EXIT_FAILURE;
+ }
+ if( _has_signal(ACQ_SIGNAL) ) {
+ loge( "VT acquire signal is already in use");
+ return E33_EXIT_FAILURE;
+ }
+
+ if( _set_signal( REL_SIGNAL, _vt_switch_sighandler ) ) {
+ loge( "Could not set relese signal handler");
+ return E33_EXIT_FAILURE;
+ }
+ if( _set_signal( ACQ_SIGNAL, _vt_switch_sighandler ) ) {
+ loge( "Could not set acquire signal handler");
+ return E33_EXIT_FAILURE;
+ }
+ /**/
+
+
+
+ if( ioctl(__display.ttyFd, VT_GETMODE, &vt_mode) < 0 ) {
+ logw( "Could not get VT mode" );
+ return E33_EXIT_FAILURE;
+ }
+
+ vt_mode.mode = VT_PROCESS;
+ vt_mode.relsig = REL_SIGNAL;
+ vt_mode.acqsig = ACQ_SIGNAL;
+ vt_mode.frsig = SIGIO;
+
+ if( ioctl(__display.ttyFd, VT_SETMODE, &vt_mode) < 0 ) {
+ logw( "Could not set VT mode" );
+ return E33_EXIT_FAILURE;
+ }
+
+ return E33_EXIT_SUCCESS;
+}
+
+
+static Size _get_drm_resources( Size fd )
+{
+ if( e33_ioctl(fd, (int)DRM_IOCTL_MODE_GETRESOURCES, &drmData.drmRes) == -1 ) {
+ logw( "Failed to init drm resources" );
+ return E33_EXIT_FAILURE;
+ }
+
+ drmData.drmRes_fbs = malloc( sizeof(__u64) * drmData.drmRes.count_fbs );
+ drmData.drmRes_crtcs = malloc( sizeof(__u64) * drmData.drmRes.count_crtcs );
+ drmData.drmRes_encs = malloc( sizeof(__u64) * drmData.drmRes.count_encoders );
+ drmData.drmRes_conns = malloc( sizeof(__u64) * drmData.drmRes.count_connectors );
+
+ /* DRM resource objects must also be zero'd before second call */
+ memset( drmData.drmRes_fbs, 0, sizeof(__u64) * drmData.drmRes.count_fbs );
+ memset( drmData.drmRes_crtcs, 0, sizeof(__u64) * drmData.drmRes.count_crtcs );
+ memset( drmData.drmRes_encs, 0, sizeof(__u64) * drmData.drmRes.count_encoders );
+ memset( drmData.drmRes_conns, 0, sizeof(__u64) * drmData.drmRes.count_connectors );
+
+ drmData.drmRes.fb_id_ptr = (__u64)drmData.drmRes_fbs;
+ drmData.drmRes.crtc_id_ptr = (__u64)drmData.drmRes_crtcs;
+ drmData.drmRes.connector_id_ptr = (__u64)drmData.drmRes_conns;
+ drmData.drmRes.encoder_id_ptr = (__u64)drmData.drmRes_encs;
+
+ /* Second call writes drm resource data using the given pointers */
+ if( ioctl( fd, (int)DRM_IOCTL_MODE_GETRESOURCES, &drmData.drmRes ) == -1 ) {
+ logw( "Failed to get drm resources" );
+ return E33_EXIT_FAILURE;
+ }
+
+ return E33_EXIT_SUCCESS;
+}
+
+
+static Size _get_drm_connector( Size fd )
+{
+ struct drm_mode_get_connector *connector = &__display.connector;
+ u16 i, j;
+
+ for( i = 0; i < drmData.drmRes.count_connectors; ++i )
+ {
+ connector->connector_id = drmData.drmRes_conns[i];
+
+ if( connector->connector_id <= 0 ) {
+ continue;
+ }
+
+ if( e33_ioctl( fd, (int)DRM_IOCTL_MODE_GETCONNECTOR, connector ) == -1 ) {
+ continue;
+ }
+
+ if( connector->connection && connector->count_modes > 0 &&
+ connector->encoder_id && connector->count_encoders > 0 )
+ {
+ connector->modes_ptr = (__u64)drmData.connModes;
+ connector->props_ptr = (__u64)drmData.connProps;
+ connector->prop_values_ptr = (__u64)drmData.connPropVals;
+ connector->encoders_ptr = (__u64)drmData.connEncs;
+
+ if( e33_ioctl( fd, (int)DRM_IOCTL_MODE_GETCONNECTOR, connector) == -1 ) {
+ continue;
+ }
+
+ goto success;
+ }
+ }
+
+ loge( "Failed to find suitable connector");
+ return E33_EXIT_FAILURE;
+
+success:
+ drmData.mode = &drmData.connModes[0];
+
+ logi( "Using mode '%s'", drmData.mode->name );
+
+ /* TODO there has to be a better way */
+ if( _strcomp( drmData.mode->name, "1366x768" ) ) {
+ drmData.mode->hdisplay += 10;
+ }
+ return E33_EXIT_SUCCESS;
+}
+
+static Size _get_drm_crtc( Size fd )
+{
+ struct drm_mode_get_encoder *encoder = &__display.encoder;
+ struct drm_mode_crtc *crtc = &__display.crtc;
+
+ encoder->encoder_id = __display.connector.encoder_id;
+
+ if( e33_ioctl( fd, (int)DRM_IOCTL_MODE_GETENCODER, encoder ) == -1 ) {
+ loge( "Failed to get encoder" );
+ return E33_EXIT_FAILURE;
+ }
+
+ crtc->crtc_id = encoder->crtc_id;
+
+ if( e33_ioctl( fd, (int)DRM_IOCTL_MODE_GETCRTC, crtc ) == -1 ) {
+ loge( "Failed to get CRTC" );
+ return E33_EXIT_FAILURE;
+ }
+
+ crtc->fb_id = drmData.drmFBCmd[0].fb_id;
+ crtc->set_connectors_ptr = (__u64)drmData.drmRes_conns;
+ crtc->count_connectors = 1;
+ crtc->mode = *drmData.mode;
+ crtc->mode_valid = 1;
+
+ if( e33_ioctl( fd, (int)DRM_IOCTL_MODE_SETCRTC, crtc ) == -1 ) {
+ loge( "Could not set CRTC" );
+ return E33_EXIT_FAILURE;
+ }
+
+ return E33_EXIT_SUCCESS;
+}
+
+static Size _get_drm_framebuffer( Size fd )
+{
+ struct drm_mode_create_dumb *drmCreateDumb = drmData.drmCreateDumb;
+ struct drm_mode_map_dumb *drmMapDumb = drmData.drmMapDumb;
+ struct drm_mode_fb_cmd *drmFBCmd = drmData.drmFBCmd;
+ struct drm_mode_modeinfo *mode = drmData.mode;
+ u8 i;
+
+ for( i = 0; i < 2; ++i )
+ {
+ drmCreateDumb[i].width = mode->hdisplay;
+ drmCreateDumb[i].height = mode->vdisplay;
+ drmCreateDumb[i].bpp = 32;
+
+ if( e33_ioctl( fd, (int)DRM_IOCTL_MODE_CREATE_DUMB,
+ drmCreateDumb + i ) == -1 )
+ {
+ loge( "Failed to create dumb buffer #%d", i );
+ return E33_EXIT_FAILURE;
+ }
+
+ drmFBCmd[i].width = drmCreateDumb[i].width;
+ drmFBCmd[i].height = drmCreateDumb[i].height;
+ drmFBCmd[i].bpp = drmCreateDumb[i].bpp;
+ drmFBCmd[i].pitch = drmCreateDumb[i].pitch;
+ drmFBCmd[i].depth = 24;
+ drmFBCmd[i].handle = drmCreateDumb[i].handle;
+
+ if( e33_ioctl( fd, (int)DRM_IOCTL_MODE_ADDFB, drmFBCmd + i ) == -1 ) {
+ loge( "Failed to add framebuffer #%d", i );
+ return E33_EXIT_FAILURE;
+ }
+
+ __display.fb.id[i] = drmFBCmd[i].fb_id;
+
+ drmMapDumb[i].handle = drmCreateDumb[i].handle;
+
+ if( e33_ioctl( fd, (int)DRM_IOCTL_MODE_MAP_DUMB, drmMapDumb + i ) == -1 )
+ {
+ loge( "Failed to map dumb buffer #%d", i );
+ return E33_EXIT_FAILURE;
+ }
+
+ __display.fb.map[i] =
+ mmap( 0, drmCreateDumb[i].size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, drmMapDumb[i].offset );
+
+ if( __display.fb.map[i] == MAP_FAILED ) {
+ loge( "Failed to map framebuffer #%d", i );
+ return E33_EXIT_FAILURE;
+ }
+ }
+
+ return E33_EXIT_SUCCESS;
+}
+
+
+static int _is_card( const struct dirent *f )
+{
+ return _strcomp(f->d_name, "card");
+}
+
+
+static Size _open_graphics_device( Size *fd )
+{
+ Size i, num, _fd;
+ struct dirent **evfs;
+ char path[512];
+
+ num = scandir( "/dev/dri", &evfs, _is_card, 0 );
+
+ if( num <= 0 ) {
+ loge( "No graphics devices found" );
+ goto failure;
+ }
+
+ for( i = 0; i < num; ++i )
+ {
+ struct drm_get_cap cap = {0,};
+
+ snprintf( path, 512, "%s%s", "/dev/dri/", evfs[i]->d_name );
+
+ logi( "Trying '%s'", path );
+
+ if( (_fd = open(path, O_RDWR )) == -1 ) {
+ logw( "Failed to open graphics device '%s'", path );
+ continue;
+ }
+
+ cap.capability = DRM_CAP_DUMB_BUFFER;
+ if( e33_ioctl( _fd, DRM_IOCTL_GET_CAP, &cap ) == -1 ) {
+ logw( "Failed to get device capabilities for '%s'", path );
+ continue;
+ }
+
+ if( cap.value )
+ {
+ logi("Using device: %s", path);
+ *fd = _fd;
+ free( evfs );
+ return E33_EXIT_SUCCESS;
+ }
+
+ close( _fd );
+ }
+
+failure:
+ free( evfs );
+ return E33_EXIT_FAILURE;
+}
+
diff --git a/src/logger.c b/src/logger.c
new file mode 100644
index 0000000..c944da8
--- /dev/null
+++ b/src/logger.c
@@ -0,0 +1,77 @@
+#include <linux/vt.h>
+
+#include "fcntl.h"
+#include "stdarg.h"
+#include "errno.h"
+#include "time.h"
+#include "unistd.h"
+#include "stdio.h"
+#include "string.h"
+
+#include "logger.h"
+
+Logger __logger;
+
+
+static char *colours[5] = {
+ "[\x1b[36mDebug\x1b[37m]",
+ "[\x1b[32mInfo\x1b[37m]",
+ "[\x1b[35mWarn\x1b[37m]",
+ "[\x1b[33mError\x1b[37m]",
+ "[\x1b[31mFatal\x1b[37m]",
+};
+
+Size logger_init( void )
+{
+ String logfile[512];
+
+
+ snprintf(logfile, 512, "%s/%s", getenv("HOME"), ".engine33.log");
+
+ __logger.fd = open(logfile, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
+
+ if( __logger.fd < 0 ) {
+ printf( "Unable to initialize logger. Exiting." );
+ return E33_EXIT_FAILURE;
+ }
+
+ __logger.func = 0;
+
+ dprintf( __logger.fd, "\033[3J\033[1;1HWelcome to Engine33!\r\n\r\n" );
+
+ return E33_EXIT_SUCCESS;
+}
+
+void logger_term( void )
+{
+ dprintf( __logger.fd, "\r\n\r\nGoodbye!" );
+ close( __logger.fd );
+}
+
+void logger( Size level, const char *fmt, ... )
+{
+ time_t currentTime;
+ struct tm *m_time;
+
+
+ va_list args;
+ va_start(args, fmt);
+
+ time(&currentTime);
+ m_time = localtime(&currentTime);
+
+ dprintf( __logger.fd, "Engine33 [%02d:%02d:%02d] -", m_time->tm_hour, m_time->tm_min, m_time->tm_sec );
+
+ dprintf( __logger.fd, " %s ", colours[level] );
+ vdprintf(__logger.fd, fmt, args);
+
+ if( (level > LOG_INFO) && errno ) {
+ dprintf( __logger.fd, ". Reason: %s", strerror(errno) );
+ errno = 0;
+ }
+
+ dprintf( __logger.fd, ".\r\n" );
+
+ va_end(args);
+}
+
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..2d345ba
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,54 @@
+#include "display.h"
+#include "clock.h"
+#include "logger.h"
+#include "options.h"
+
+
+int main(int argc, char *argv[])
+{
+ Size fps, FPS;
+ long timeOld, time;
+
+ timeOld = clock_get_us();
+ time = 0;
+ fps = 0;
+ FPS = 0;
+
+ if( logger_init() ) {
+ return EXIT_FAILURE;
+ }
+
+ if( display_init() ) {
+ return EXIT_FAILURE;
+ }
+
+ while(1)
+ {
+ display_vtswitcher_poll(1);
+
+ if( __display.active )
+ {
+ __display.surface.data[10] = GREEN;
+ display_flip();
+ }
+
+
+ time += clock_get_us() - timeOld;
+ timeOld = clock_get_us();
+
+ if(time >= 1000000)
+ {
+ logi("FPS: %d", FPS);
+ FPS = fps;
+ time = 0;
+ fps = 0;
+ }
+ ++fps;
+ }
+
+ display_term();
+ logger_term();
+
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/system.c b/src/system.c
new file mode 100644
index 0000000..ffb8c4a
--- /dev/null
+++ b/src/system.c
@@ -0,0 +1,29 @@
+#include "sys/ioctl.h"
+#include "errno.h"
+
+#include "types.h"
+
+
+err e33_ioctl( Size fd, unsigned long req, void *arg )
+{
+ Size ret;
+
+ do {
+ ret = ioctl(fd, req, arg);
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+ return ret;
+}
+
+boolean _strcomp( String s1, String s2 )
+{
+ while( (*s1 != '\0') && (*s2 != '\0') )
+ {
+ if( (*s1++) != (*s2++) ) {
+ return E33_EXIT_SUCCESS;
+ }
+ }
+
+ return E33_EXIT_FAILURE;
+}
+