From fa8167b94d13e94a6cb953e7f549a89f155f77c6 Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Wed, 21 Jan 2015 17:26:24 +1000
Subject: Big file rename to reduce problems with brain-dead IDE's that don't
 handle project file hierarchies well. Naming is more consistent with the new
 scheme. May affect some third party drivers (header file renames).

---
 demos/tools/touch_driver_test/main.c               |    4 +-
 demos/tools/touch_raw_readings/main.c              |    4 +-
 docs/src/containers.dox                            |    2 +-
 docs/src/widgets.dox                               |    2 +-
 docs/src/windows.dox                               |    2 +-
 drivers/gadc/AT91SAM7/gadc_lld.c                   |    2 +-
 drivers/gaudio/Win32/gaudio_play_lld.c             |    2 +-
 drivers/gaudio/Win32/gaudio_record_lld.c           |    2 +-
 drivers/gaudio/gadc/gaudio_record_lld.c            |    2 +-
 drivers/gaudio/pwm/gaudio_play_lld.c               |    2 +-
 drivers/gaudio/vs1053/gaudio_play_lld.c            |    2 +-
 drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c        |    2 +-
 drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c          |    2 +-
 drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c          |    2 +-
 drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c          |    2 +-
 drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c          |    2 +-
 drivers/gdisp/ILI93xx/gdisp_lld_ILI93xx.c          |    2 +-
 drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c          |    2 +-
 drivers/gdisp/LGDP4532/gdisp_lld_LGDP4532.c        |    2 +-
 .../gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c  |    2 +-
 .../gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c    |    2 +-
 drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c          |    2 +-
 drivers/gdisp/PCF8812/gdisp_lld_PCF8812.c          |    2 +-
 drivers/gdisp/R61505U/gdisp_lld_R61505U.c          |    2 +-
 drivers/gdisp/RA8875/gdisp_lld_RA8875.c            |    2 +-
 drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c          |    2 +-
 drivers/gdisp/SPFD54124B/gdisp_lld_SPFD54124B.c    |    2 +-
 drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c          |    2 +-
 drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c          |    2 +-
 drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c          |    2 +-
 drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c          |    2 +-
 drivers/gdisp/ST7565/gdisp_lld_ST7565.c            |    2 +-
 .../gdisp_lld_STM32F429iDiscovery.c                |    2 +-
 drivers/gdisp/TestStub/gdisp_lld_TestStub.c        |    2 +-
 drivers/gdisp/framebuffer/gdisp_lld_framebuffer.c  |    2 +-
 drivers/ginput/dial/GADC/ginput_lld_dial.c         |    2 +-
 drivers/ginput/toggle/Pal/ginput_lld_toggle.c      |    2 +-
 drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c  |    2 +-
 drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c    |    2 +-
 .../ginput/touch/MAX11802/gmouse_lld_MAX11802.c    |    2 +-
 drivers/ginput/touch/MCU/gmouse_lld_MCU.c          |    2 +-
 .../ginput/touch/STMPE811/gmouse_lld_STMPE811.c    |    2 +-
 drivers/multiple/Win32/gdisp_lld_Win32.c           |   10 +-
 drivers/multiple/X/gdisp_lld_X.c                   |    8 +-
 drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c       |    4 +-
 gfx.h                                              |   72 +-
 gfx.mk                                             |   24 +-
 src/gadc/driver.h                                  |  153 -
 src/gadc/gadc.c                                    |  353 ++
 src/gadc/gadc.h                                    |  252 ++
 src/gadc/gadc.mk                                   |    1 +
 src/gadc/gadc_driver.h                             |  153 +
 src/gadc/gadc_gadc.c                               |  362 ---
 src/gadc/gadc_options.h                            |   42 +
 src/gadc/gadc_rules.h                              |   41 +
 src/gadc/sys_defs.h                                |  252 --
 src/gadc/sys_make.mk                               |    1 -
 src/gadc/sys_options.h                             |   42 -
 src/gadc/sys_rules.h                               |   41 -
 src/gaudio/driver_play.h                           |  126 -
 src/gaudio/driver_record.h                         |  108 -
 src/gaudio/gaudio.c                                |  275 ++
 src/gaudio/gaudio.h                                |  297 ++
 src/gaudio/gaudio.mk                               |    1 +
 src/gaudio/gaudio_driver_play.h                    |  126 +
 src/gaudio/gaudio_driver_record.h                  |  108 +
 src/gaudio/gaudio_gaudio.c                         |  283 --
 src/gaudio/gaudio_options.h                        |   44 +
 src/gaudio/gaudio_rules.h                          |   56 +
 src/gaudio/sys_defs.h                              |  297 --
 src/gaudio/sys_make.mk                             |    1 -
 src/gaudio/sys_options.h                           |   44 -
 src/gaudio/sys_rules.h                             |   56 -
 src/gdisp/driver.h                                 | 1070 -------
 src/gdisp/gdisp.c                                  | 3370 +++++++++++++++++++
 src/gdisp/gdisp.h                                  | 1124 +++++++
 src/gdisp/gdisp.mk                                 |   14 +
 src/gdisp/gdisp_driver.h                           | 1070 +++++++
 src/gdisp/gdisp_fonts.c                            |    9 -
 src/gdisp/gdisp_gdisp.c                            | 3378 --------------------
 src/gdisp/gdisp_image.c                            |    8 -
 src/gdisp/gdisp_image_bmp.c                        |   33 -
 src/gdisp/gdisp_image_gif.c                        |    8 -
 src/gdisp/gdisp_image_jpg.c                        |    5 -
 src/gdisp/gdisp_image_native.c                     |    5 -
 src/gdisp/gdisp_image_png.c                        |    5 -
 src/gdisp/gdisp_options.h                          |  445 +++
 src/gdisp/gdisp_pixmap.c                           |    4 +-
 src/gdisp/gdisp_rules.h                            |   89 +
 src/gdisp/sys_defs.h                               | 1124 -------
 src/gdisp/sys_make.mk                              |   14 -
 src/gdisp/sys_options.h                            |  382 ---
 src/gdisp/sys_rules.h                              |   89 -
 src/gdriver/gdriver.c                              |  148 +
 src/gdriver/gdriver.h                              |  159 +
 src/gdriver/gdriver.mk                             |    1 +
 src/gdriver/gdriver_gdriver.c                      |  148 -
 src/gdriver/gdriver_options.h                      |   32 +
 src/gdriver/gdriver_rules.h                        |   23 +
 src/gdriver/sys_defs.h                             |  159 -
 src/gdriver/sys_make.mk                            |    1 -
 src/gdriver/sys_options.h                          |   32 -
 src/gdriver/sys_rules.h                            |   23 -
 src/gevent/gevent.c                                |  238 ++
 src/gevent/gevent.h                                |  246 ++
 src/gevent/gevent.mk                               |    1 +
 src/gevent/gevent_gevent.c                         |  246 --
 src/gevent/gevent_options.h                        |   55 +
 src/gevent/gevent_rules.h                          |   23 +
 src/gevent/sys_defs.h                              |  246 --
 src/gevent/sys_make.mk                             |    1 -
 src/gevent/sys_options.h                           |   55 -
 src/gevent/sys_rules.h                             |   23 -
 src/gfile/gfile.c                                  |  401 +++
 src/gfile/gfile.h                                  |  470 +++
 src/gfile/gfile.mk                                 |   18 +
 src/gfile/gfile_fatfs_diskio_chibios.c             |    6 -
 src/gfile/gfile_fatfs_wrapper.c                    |    6 -
 src/gfile/gfile_gfile.c                            |  407 ---
 src/gfile/gfile_options.h                          |  207 ++
 src/gfile/gfile_petitfs_diskio_chibios.c           |    6 -
 src/gfile/gfile_petitfs_wrapper.c                  |    6 -
 src/gfile/gfile_rules.h                            |   26 +
 src/gfile/sys_defs.h                               |  470 ---
 src/gfile/sys_make.mk                              |   18 -
 src/gfile/sys_options.h                            |  207 --
 src/gfile/sys_rules.h                              |   26 -
 src/ginput/driver_dial.h                           |   45 -
 src/ginput/driver_keyboard.h                       |  129 -
 src/ginput/driver_mouse.h                          |  174 -
 src/ginput/driver_toggle.h                         |   61 -
 src/ginput/ginput.c                                |   54 +
 src/ginput/ginput.h                                |   50 +
 src/ginput/ginput.mk                               |    6 +
 src/ginput/ginput_dial.c                           |    2 +-
 src/ginput/ginput_driver_dial.h                    |   45 +
 src/ginput/ginput_driver_keyboard.h                |  129 +
 src/ginput/ginput_driver_mouse.h                   |  174 +
 src/ginput/ginput_driver_toggle.h                  |   61 +
 src/ginput/ginput_ginput.c                         |   54 -
 src/ginput/ginput_keyboard.c                       |    4 +-
 src/ginput/ginput_keyboard_microcode.c             |   73 +
 src/ginput/ginput_keyboard_microcode.h             |  107 +
 src/ginput/ginput_mouse.c                          |    2 +-
 src/ginput/ginput_options.h                        |  221 ++
 src/ginput/ginput_rules.h                          |   52 +
 src/ginput/ginput_toggle.c                         |    2 +-
 src/ginput/keyboard_microcode.c                    |   73 -
 src/ginput/keyboard_microcode.h                    |  107 -
 src/ginput/sys_defs.h                              |   50 -
 src/ginput/sys_make.mk                             |    6 -
 src/ginput/sys_options.h                           |  221 --
 src/ginput/sys_rules.h                             |   52 -
 src/gmisc/gmisc.c                                  |   22 +
 src/gmisc/gmisc.h                                  |  471 +++
 src/gmisc/gmisc.mk                                 |    4 +
 src/gmisc/gmisc_arrayops.c                         |    8 -
 src/gmisc/gmisc_gmisc.c                            |   27 -
 src/gmisc/gmisc_matrix2d.c                         |    4 -
 src/gmisc/gmisc_options.h                          |   85 +
 src/gmisc/gmisc_rules.h                            |   23 +
 src/gmisc/gmisc_trig.c                             |    8 -
 src/gmisc/sys_defs.h                               |  471 ---
 src/gmisc/sys_make.mk                              |    4 -
 src/gmisc/sys_options.h                            |   85 -
 src/gmisc/sys_rules.h                              |   23 -
 src/gos/gos.h                                      |  470 +++
 src/gos/gos.mk                                     |    9 +
 src/gos/gos_options.h                              |  115 +
 src/gos/gos_rawrtos.c                              |    7 +
 src/gos/gos_rules.h                                |   36 +
 src/gos/gos_win32.c                                |    4 -
 src/gos/sys_defs.h                                 |  470 ---
 src/gos/sys_make.mk                                |    9 -
 src/gos/sys_options.h                              |  115 -
 src/gos/sys_rules.h                                |   36 -
 src/gqueue/gqueue.c                                |  464 +++
 src/gqueue/gqueue.h                                |  412 +++
 src/gqueue/gqueue.mk                               |    1 +
 src/gqueue/gqueue_gqueue.c                         |  469 ---
 src/gqueue/gqueue_options.h                        |   59 +
 src/gqueue/gqueue_rules.h                          |   30 +
 src/gqueue/sys_defs.h                              |  412 ---
 src/gqueue/sys_make.mk                             |    1 -
 src/gqueue/sys_options.h                           |   59 -
 src/gqueue/sys_rules.h                             |   30 -
 src/gtimer/gtimer.c                                |  229 ++
 src/gtimer/gtimer.h                                |  180 ++
 src/gtimer/gtimer.mk                               |    1 +
 src/gtimer/gtimer_gtimer.c                         |  238 --
 src/gtimer/gtimer_options.h                        |   46 +
 src/gtimer/gtimer_rules.h                          |   29 +
 src/gtimer/sys_defs.h                              |  180 --
 src/gtimer/sys_make.mk                             |    1 -
 src/gtimer/sys_options.h                           |   46 -
 src/gtimer/sys_rules.h                             |   29 -
 src/gwin/gwin.c                                    |  400 +++
 src/gwin/gwin.h                                    | 1026 ++++++
 src/gwin/gwin.mk                                   |   19 +
 src/gwin/gwin_console.h                            |    2 +-
 src/gwin/gwin_container.h                          |    2 +-
 src/gwin/gwin_gl3d.h                               |    2 +-
 src/gwin/gwin_graph.h                              |    2 +-
 src/gwin/gwin_gwin.c                               |  400 ---
 src/gwin/gwin_image.h                              |    2 +-
 src/gwin/gwin_options.h                            |  334 ++
 src/gwin/gwin_rules.h                              |  129 +
 src/gwin/gwin_widget.h                             |    2 +-
 src/gwin/sys_defs.h                                | 1026 ------
 src/gwin/sys_make.mk                               |   19 -
 src/gwin/sys_options.h                             |  334 --
 src/gwin/sys_rules.h                               |  129 -
 212 files changed, 15598 insertions(+), 15707 deletions(-)
 delete mode 100644 src/gadc/driver.h
 create mode 100644 src/gadc/gadc.c
 create mode 100644 src/gadc/gadc.h
 create mode 100644 src/gadc/gadc.mk
 create mode 100644 src/gadc/gadc_driver.h
 delete mode 100644 src/gadc/gadc_gadc.c
 create mode 100644 src/gadc/gadc_options.h
 create mode 100644 src/gadc/gadc_rules.h
 delete mode 100644 src/gadc/sys_defs.h
 delete mode 100644 src/gadc/sys_make.mk
 delete mode 100644 src/gadc/sys_options.h
 delete mode 100644 src/gadc/sys_rules.h
 delete mode 100644 src/gaudio/driver_play.h
 delete mode 100644 src/gaudio/driver_record.h
 create mode 100644 src/gaudio/gaudio.c
 create mode 100644 src/gaudio/gaudio.h
 create mode 100644 src/gaudio/gaudio.mk
 create mode 100644 src/gaudio/gaudio_driver_play.h
 create mode 100644 src/gaudio/gaudio_driver_record.h
 delete mode 100644 src/gaudio/gaudio_gaudio.c
 create mode 100644 src/gaudio/gaudio_options.h
 create mode 100644 src/gaudio/gaudio_rules.h
 delete mode 100644 src/gaudio/sys_defs.h
 delete mode 100644 src/gaudio/sys_make.mk
 delete mode 100644 src/gaudio/sys_options.h
 delete mode 100644 src/gaudio/sys_rules.h
 delete mode 100644 src/gdisp/driver.h
 create mode 100644 src/gdisp/gdisp.c
 create mode 100644 src/gdisp/gdisp.h
 create mode 100644 src/gdisp/gdisp.mk
 create mode 100644 src/gdisp/gdisp_driver.h
 delete mode 100644 src/gdisp/gdisp_gdisp.c
 create mode 100644 src/gdisp/gdisp_options.h
 create mode 100644 src/gdisp/gdisp_rules.h
 delete mode 100644 src/gdisp/sys_defs.h
 delete mode 100644 src/gdisp/sys_make.mk
 delete mode 100644 src/gdisp/sys_options.h
 delete mode 100644 src/gdisp/sys_rules.h
 create mode 100644 src/gdriver/gdriver.c
 create mode 100644 src/gdriver/gdriver.h
 create mode 100644 src/gdriver/gdriver.mk
 delete mode 100644 src/gdriver/gdriver_gdriver.c
 create mode 100644 src/gdriver/gdriver_options.h
 create mode 100644 src/gdriver/gdriver_rules.h
 delete mode 100644 src/gdriver/sys_defs.h
 delete mode 100644 src/gdriver/sys_make.mk
 delete mode 100644 src/gdriver/sys_options.h
 delete mode 100644 src/gdriver/sys_rules.h
 create mode 100644 src/gevent/gevent.c
 create mode 100644 src/gevent/gevent.h
 create mode 100644 src/gevent/gevent.mk
 delete mode 100644 src/gevent/gevent_gevent.c
 create mode 100644 src/gevent/gevent_options.h
 create mode 100644 src/gevent/gevent_rules.h
 delete mode 100644 src/gevent/sys_defs.h
 delete mode 100644 src/gevent/sys_make.mk
 delete mode 100644 src/gevent/sys_options.h
 delete mode 100644 src/gevent/sys_rules.h
 create mode 100644 src/gfile/gfile.c
 create mode 100644 src/gfile/gfile.h
 create mode 100644 src/gfile/gfile.mk
 delete mode 100644 src/gfile/gfile_gfile.c
 create mode 100644 src/gfile/gfile_options.h
 create mode 100644 src/gfile/gfile_rules.h
 delete mode 100644 src/gfile/sys_defs.h
 delete mode 100644 src/gfile/sys_make.mk
 delete mode 100644 src/gfile/sys_options.h
 delete mode 100644 src/gfile/sys_rules.h
 delete mode 100644 src/ginput/driver_dial.h
 delete mode 100644 src/ginput/driver_keyboard.h
 delete mode 100644 src/ginput/driver_mouse.h
 delete mode 100644 src/ginput/driver_toggle.h
 create mode 100644 src/ginput/ginput.c
 create mode 100644 src/ginput/ginput.h
 create mode 100644 src/ginput/ginput.mk
 create mode 100644 src/ginput/ginput_driver_dial.h
 create mode 100644 src/ginput/ginput_driver_keyboard.h
 create mode 100644 src/ginput/ginput_driver_mouse.h
 create mode 100644 src/ginput/ginput_driver_toggle.h
 delete mode 100644 src/ginput/ginput_ginput.c
 create mode 100644 src/ginput/ginput_keyboard_microcode.c
 create mode 100644 src/ginput/ginput_keyboard_microcode.h
 create mode 100644 src/ginput/ginput_options.h
 create mode 100644 src/ginput/ginput_rules.h
 delete mode 100644 src/ginput/keyboard_microcode.c
 delete mode 100644 src/ginput/keyboard_microcode.h
 delete mode 100644 src/ginput/sys_defs.h
 delete mode 100644 src/ginput/sys_make.mk
 delete mode 100644 src/ginput/sys_options.h
 delete mode 100644 src/ginput/sys_rules.h
 create mode 100644 src/gmisc/gmisc.c
 create mode 100644 src/gmisc/gmisc.h
 create mode 100644 src/gmisc/gmisc.mk
 delete mode 100644 src/gmisc/gmisc_gmisc.c
 create mode 100644 src/gmisc/gmisc_options.h
 create mode 100644 src/gmisc/gmisc_rules.h
 delete mode 100644 src/gmisc/sys_defs.h
 delete mode 100644 src/gmisc/sys_make.mk
 delete mode 100644 src/gmisc/sys_options.h
 delete mode 100644 src/gmisc/sys_rules.h
 create mode 100644 src/gos/gos.h
 create mode 100644 src/gos/gos.mk
 create mode 100644 src/gos/gos_options.h
 create mode 100644 src/gos/gos_rules.h
 delete mode 100644 src/gos/sys_defs.h
 delete mode 100644 src/gos/sys_make.mk
 delete mode 100644 src/gos/sys_options.h
 delete mode 100644 src/gos/sys_rules.h
 create mode 100644 src/gqueue/gqueue.c
 create mode 100644 src/gqueue/gqueue.h
 create mode 100644 src/gqueue/gqueue.mk
 delete mode 100644 src/gqueue/gqueue_gqueue.c
 create mode 100644 src/gqueue/gqueue_options.h
 create mode 100644 src/gqueue/gqueue_rules.h
 delete mode 100644 src/gqueue/sys_defs.h
 delete mode 100644 src/gqueue/sys_make.mk
 delete mode 100644 src/gqueue/sys_options.h
 delete mode 100644 src/gqueue/sys_rules.h
 create mode 100644 src/gtimer/gtimer.c
 create mode 100644 src/gtimer/gtimer.h
 create mode 100644 src/gtimer/gtimer.mk
 delete mode 100644 src/gtimer/gtimer_gtimer.c
 create mode 100644 src/gtimer/gtimer_options.h
 create mode 100644 src/gtimer/gtimer_rules.h
 delete mode 100644 src/gtimer/sys_defs.h
 delete mode 100644 src/gtimer/sys_make.mk
 delete mode 100644 src/gtimer/sys_options.h
 delete mode 100644 src/gtimer/sys_rules.h
 create mode 100644 src/gwin/gwin.c
 create mode 100644 src/gwin/gwin.h
 create mode 100644 src/gwin/gwin.mk
 delete mode 100644 src/gwin/gwin_gwin.c
 create mode 100644 src/gwin/gwin_options.h
 create mode 100644 src/gwin/gwin_rules.h
 delete mode 100644 src/gwin/sys_defs.h
 delete mode 100644 src/gwin/sys_make.mk
 delete mode 100644 src/gwin/sys_options.h
 delete mode 100644 src/gwin/sys_rules.h

diff --git a/demos/tools/touch_driver_test/main.c b/demos/tools/touch_driver_test/main.c
index 13136a57..39924032 100644
--- a/demos/tools/touch_driver_test/main.c
+++ b/demos/tools/touch_driver_test/main.c
@@ -30,8 +30,8 @@
 #include "gfx.h"
 
 // We get nasty and look at some internal structures - get the relevant information
-#include "src/gdriver/sys_defs.h"
-#include "src/ginput/driver_mouse.h"
+#include "src/gdriver/gdriver.h"
+#include "src/ginput/ginput_driver_mouse.h"
 
 #include <string.h>
 
diff --git a/demos/tools/touch_raw_readings/main.c b/demos/tools/touch_raw_readings/main.c
index d6c97920..fb1b0772 100644
--- a/demos/tools/touch_raw_readings/main.c
+++ b/demos/tools/touch_raw_readings/main.c
@@ -30,8 +30,8 @@
 #include "gfx.h"
 
 // We get nasty and look at some internal structures - get the relevant information
-#include "src/gdriver/sys_defs.h"
-#include "src/ginput/driver_mouse.h"
+#include "src/gdriver/gdriver.h"
+#include "src/ginput/ginput_driver_mouse.h"
 
 #include <string.h>
 
diff --git a/docs/src/containers.dox b/docs/src/containers.dox
index 3d0a6368..e8d6452c 100644
--- a/docs/src/containers.dox
+++ b/docs/src/containers.dox
@@ -6,7 +6,7 @@
  */
 
 /**
- * @file		src/gwin/sys_defs.h
+ * @file		src/gwin/gwin.h
  *
  * @defgroup	Containers Containers
  * @ingroup 	GWIN
diff --git a/docs/src/widgets.dox b/docs/src/widgets.dox
index 24be391d..4626508c 100644
--- a/docs/src/widgets.dox
+++ b/docs/src/widgets.dox
@@ -6,7 +6,7 @@
  */
 
 /**
- * @file    	src/gwin/sys_defs.h
+ * @file    	src/gwin/gwin.h
  *
  * @defgroup 	Widgets Widgets
  * @ingroup 	GWIN
diff --git a/docs/src/windows.dox b/docs/src/windows.dox
index 699281a2..c5acc31f 100644
--- a/docs/src/windows.dox
+++ b/docs/src/windows.dox
@@ -6,7 +6,7 @@
  */
 
 /**
- * @file		src/gwin/sys_defs.h
+ * @file		src/gwin/gwin.h
  *
  * @defgroup	Windows Windows
  * @ingroup		GWIN
diff --git a/drivers/gadc/AT91SAM7/gadc_lld.c b/drivers/gadc/AT91SAM7/gadc_lld.c
index b01fdd6c..fa1870b0 100644
--- a/drivers/gadc/AT91SAM7/gadc_lld.c
+++ b/drivers/gadc/AT91SAM7/gadc_lld.c
@@ -14,7 +14,7 @@
 
 #if GFX_USE_GADC
 
-#include "src/gadc/driver.h"
+#include "src/gadc/gadc_driver.h"
 
 static uint32_t		nextfreq;
 
diff --git a/drivers/gaudio/Win32/gaudio_play_lld.c b/drivers/gaudio/Win32/gaudio_play_lld.c
index c0adf03e..cdc9a62a 100644
--- a/drivers/gaudio/Win32/gaudio_play_lld.c
+++ b/drivers/gaudio/Win32/gaudio_play_lld.c
@@ -10,7 +10,7 @@
 #if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY
 
 /* Include the driver defines */
-#include "src/gaudio/driver_play.h"
+#include "src/gaudio/gaudio_driver_play.h"
 
 #undef Red
 #undef Green
diff --git a/drivers/gaudio/Win32/gaudio_record_lld.c b/drivers/gaudio/Win32/gaudio_record_lld.c
index c9ac8187..cfe8edf5 100644
--- a/drivers/gaudio/Win32/gaudio_record_lld.c
+++ b/drivers/gaudio/Win32/gaudio_record_lld.c
@@ -10,7 +10,7 @@
 #if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD
 
 /* Include the driver defines */
-#include "src/gaudio/driver_record.h"
+#include "src/gaudio/gaudio_driver_record.h"
 
 #undef Red
 #undef Green
diff --git a/drivers/gaudio/gadc/gaudio_record_lld.c b/drivers/gaudio/gadc/gaudio_record_lld.c
index 1d70a259..6495309a 100644
--- a/drivers/gaudio/gadc/gaudio_record_lld.c
+++ b/drivers/gaudio/gadc/gaudio_record_lld.c
@@ -16,7 +16,7 @@
 #endif
 
 /* Include the driver defines */
-#include "src/gaudio/driver_record.h"
+#include "src/gaudio/gaudio_driver_record.h"
 
 static void gadcCallbackI(void) {
 	GDataBuffer *pd;
diff --git a/drivers/gaudio/pwm/gaudio_play_lld.c b/drivers/gaudio/pwm/gaudio_play_lld.c
index 07fd14b2..d4d85c33 100644
--- a/drivers/gaudio/pwm/gaudio_play_lld.c
+++ b/drivers/gaudio/pwm/gaudio_play_lld.c
@@ -10,7 +10,7 @@
 #if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY
 
 /* Include the driver defines */
-#include "src/gaudio/driver_play.h"
+#include "src/gaudio/gaudio_driver_play.h"
 
 /* Forward definition */
 static void gaudio_play_pwm_timer_callbackI(void);
diff --git a/drivers/gaudio/vs1053/gaudio_play_lld.c b/drivers/gaudio/vs1053/gaudio_play_lld.c
index 8e7fb0a5..eaf677cb 100644
--- a/drivers/gaudio/vs1053/gaudio_play_lld.c
+++ b/drivers/gaudio/vs1053/gaudio_play_lld.c
@@ -10,7 +10,7 @@
 #if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY
 
 /* Include the driver defines */
-#include "src/gaudio/driver_play.h"
+#include "src/gaudio/gaudio_driver_play.h"
 
 /* Include the vs1053 registers */
 #include "drivers/gaudio/vs1053/vs1053.h"
diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c b/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c
index 789053c8..470c2768 100644
--- a/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c
+++ b/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_ED060SC4
 #include "drivers/gdisp/ED060SC4/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_ED060SC4.h"
 
diff --git a/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c b/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c
index 34051c22..9c1e7f66 100644
--- a/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c
+++ b/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_HX8347D
 #include "drivers/gdisp/HX8347D/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_HX8347D.h"
 
diff --git a/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c b/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c
index 87f29390..d3d1ca0e 100644
--- a/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c
+++ b/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c
@@ -21,7 +21,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_ILI9320
 #include "drivers/gdisp/ILI9320/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_ILI9320.h"
 
diff --git a/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c b/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c
index 118e5933..5637b0b2 100644
--- a/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c
+++ b/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c
@@ -21,7 +21,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_ILI9325
 #include "drivers/gdisp/ILI9325/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_ILI9325.h"
 
diff --git a/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c b/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c
index 20b1e270..6a9a929b 100644
--- a/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c
+++ b/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c
@@ -20,7 +20,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_ILI9341
 #include "drivers/gdisp/ILI9341/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_ILI9341.h"
 
diff --git a/drivers/gdisp/ILI93xx/gdisp_lld_ILI93xx.c b/drivers/gdisp/ILI93xx/gdisp_lld_ILI93xx.c
index 277d0aff..b883cee6 100644
--- a/drivers/gdisp/ILI93xx/gdisp_lld_ILI93xx.c
+++ b/drivers/gdisp/ILI93xx/gdisp_lld_ILI93xx.c
@@ -21,7 +21,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_ILI93xx
 #include "drivers/gdisp/ILI93xx/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_ILI93xx.h"
 
diff --git a/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c b/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c
index f0bc7355..dec1cc31 100644
--- a/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c
+++ b/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c
@@ -20,7 +20,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_ILI9481
 #include "drivers/gdisp/ILI9481/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_ILI9481.h"
 
diff --git a/drivers/gdisp/LGDP4532/gdisp_lld_LGDP4532.c b/drivers/gdisp/LGDP4532/gdisp_lld_LGDP4532.c
index ceeca05f..067851e6 100644
--- a/drivers/gdisp/LGDP4532/gdisp_lld_LGDP4532.c
+++ b/drivers/gdisp/LGDP4532/gdisp_lld_LGDP4532.c
@@ -21,7 +21,7 @@
 
 #define GDISP_DRIVER_VMT	GDISPVMT_LGDP4532
 #include "gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_LGDP4532.h"
 
diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c
index c6aa2a7c..6439b91e 100644
--- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c
+++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c
@@ -20,7 +20,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_Nokia6610GE12
 #include "drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_Nokia6610GE12.h"
 
diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c
index cd265e00..f419abf5 100644
--- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c
+++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c
@@ -52,7 +52,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_Nokia6610GE8
 #include "drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_Nokia6610GE8.h"
 
diff --git a/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c b/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c
index ee447202..531a5a42 100644
--- a/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c
+++ b/drivers/gdisp/PCD8544/gdisp_lld_PCD8544.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT		GDISPVMT_PCD8544
 #include "drivers/gdisp/PCD8544/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 #include "board_PCD8544.h"
 
 /*===========================================================================*/
diff --git a/drivers/gdisp/PCF8812/gdisp_lld_PCF8812.c b/drivers/gdisp/PCF8812/gdisp_lld_PCF8812.c
index 56d14f3e..cfb4ad83 100644
--- a/drivers/gdisp/PCF8812/gdisp_lld_PCF8812.c
+++ b/drivers/gdisp/PCF8812/gdisp_lld_PCF8812.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT		GDISPVMT_PCF8812
 #include "drivers/gdisp/PCF8812/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 #include "board_PCF8812.h"
 
 /*===========================================================================*/
diff --git a/drivers/gdisp/R61505U/gdisp_lld_R61505U.c b/drivers/gdisp/R61505U/gdisp_lld_R61505U.c
index dd966c03..94832248 100644
--- a/drivers/gdisp/R61505U/gdisp_lld_R61505U.c
+++ b/drivers/gdisp/R61505U/gdisp_lld_R61505U.c
@@ -21,7 +21,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_R61505U
 #include "drivers/gdisp/R61505U/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_R61505U.h"
 
diff --git a/drivers/gdisp/RA8875/gdisp_lld_RA8875.c b/drivers/gdisp/RA8875/gdisp_lld_RA8875.c
index 6b58868b..0da233db 100644
--- a/drivers/gdisp/RA8875/gdisp_lld_RA8875.c
+++ b/drivers/gdisp/RA8875/gdisp_lld_RA8875.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_RA8875
 #include "drivers/gdisp/RA8875/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 /* include the users board interface */
 #include "board_RA8875.h"
diff --git a/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c b/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c
index e3f1dd0c..0611ae1c 100644
--- a/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c
+++ b/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c
@@ -20,7 +20,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_S6D1121
 #include "drivers/gdisp/S6D1121/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_S6D1121.h"
 
diff --git a/drivers/gdisp/SPFD54124B/gdisp_lld_SPFD54124B.c b/drivers/gdisp/SPFD54124B/gdisp_lld_SPFD54124B.c
index 91298aff..f66d11d6 100644
--- a/drivers/gdisp/SPFD54124B/gdisp_lld_SPFD54124B.c
+++ b/drivers/gdisp/SPFD54124B/gdisp_lld_SPFD54124B.c
@@ -25,7 +25,7 @@
 #endif
 
 #include "drivers/gdisp/SPFD54124B/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_SPFD54124B.h"
 
diff --git a/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c b/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c
index 0af1339e..82ad57f0 100644
--- a/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c
+++ b/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_SSD1289
 #include "drivers/gdisp/SSD1289/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_SSD1289.h"
 
diff --git a/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c b/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c
index d2f2a872..898c6ece 100644
--- a/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c
+++ b/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_SSD1306
 #include "drivers/gdisp/SSD1306/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_SSD1306.h"
 #include <string.h>   // for memset
diff --git a/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c b/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c
index 5c20d3d6..4ffc9f3c 100644
--- a/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c
+++ b/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_SSD1963
 #include "drivers/gdisp/SSD1963/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #define CALC_PERIOD(w,b,f,p)				(p+b+w+f)
 #define CALC_FPR(w,h,hb,hf,hp,vb,vf,vp,fps)	((fps * CALC_PERIOD(w,hb,hf,hp) * CALC_PERIOD(h,vb,vf,vp) * 1048576)/100000000)
diff --git a/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c b/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c
index 5a789548..e32e2b12 100644
--- a/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c
+++ b/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_SSD2119
 #include "drivers/gdisp/SSD2119/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_SSD2119.h"
 
diff --git a/drivers/gdisp/ST7565/gdisp_lld_ST7565.c b/drivers/gdisp/ST7565/gdisp_lld_ST7565.c
index 8d331fbc..686d1aa2 100644
--- a/drivers/gdisp/ST7565/gdisp_lld_ST7565.c
+++ b/drivers/gdisp/ST7565/gdisp_lld_ST7565.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_ST7565
 #include "drivers/gdisp/ST7565/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "board_ST7565.h"
 
diff --git a/drivers/gdisp/STM32F429iDiscovery/gdisp_lld_STM32F429iDiscovery.c b/drivers/gdisp/STM32F429iDiscovery/gdisp_lld_STM32F429iDiscovery.c
index 65e582b2..6330c32a 100644
--- a/drivers/gdisp/STM32F429iDiscovery/gdisp_lld_STM32F429iDiscovery.c
+++ b/drivers/gdisp/STM32F429iDiscovery/gdisp_lld_STM32F429iDiscovery.c
@@ -20,7 +20,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_STM32F429iDiscovery
 #include "drivers/gdisp/STM32F429iDiscovery/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #include "stm32_ltdc.h"
 
diff --git a/drivers/gdisp/TestStub/gdisp_lld_TestStub.c b/drivers/gdisp/TestStub/gdisp_lld_TestStub.c
index 4051c818..1d21ab6f 100644
--- a/drivers/gdisp/TestStub/gdisp_lld_TestStub.c
+++ b/drivers/gdisp/TestStub/gdisp_lld_TestStub.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_TestStub
 #include "drivers/gdisp/TestStub/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 #ifndef GDISP_SCREEN_HEIGHT
 	#define GDISP_SCREEN_HEIGHT		128
diff --git a/drivers/gdisp/framebuffer/gdisp_lld_framebuffer.c b/drivers/gdisp/framebuffer/gdisp_lld_framebuffer.c
index 6e38b5f4..79432bcd 100644
--- a/drivers/gdisp/framebuffer/gdisp_lld_framebuffer.c
+++ b/drivers/gdisp/framebuffer/gdisp_lld_framebuffer.c
@@ -16,7 +16,7 @@ typedef struct fbInfo {
 
 #define GDISP_DRIVER_VMT			GDISPVMT_framebuffer
 #include "drivers/gdisp/framebuffer/gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 #include "board_framebuffer.h"
 
 typedef struct fbPriv {
diff --git a/drivers/ginput/dial/GADC/ginput_lld_dial.c b/drivers/ginput/dial/GADC/ginput_lld_dial.c
index c07419bc..9ad43748 100644
--- a/drivers/ginput/dial/GADC/ginput_lld_dial.c
+++ b/drivers/ginput/dial/GADC/ginput_lld_dial.c
@@ -9,7 +9,7 @@
 
 #if GFX_USE_GINPUT && GINPUT_NEED_DIAL
 
-#include "src/ginput/driver_dial.h"
+#include "src/ginput/ginput_driver_dial.h"
 
 #if GINPUT_DIAL_NUM_PORTS >= 5
 	#error "GINPUT: Dial - GADC driver currently only supports 4 devices"
diff --git a/drivers/ginput/toggle/Pal/ginput_lld_toggle.c b/drivers/ginput/toggle/Pal/ginput_lld_toggle.c
index f42d222f..96ef071e 100644
--- a/drivers/ginput/toggle/Pal/ginput_lld_toggle.c
+++ b/drivers/ginput/toggle/Pal/ginput_lld_toggle.c
@@ -9,7 +9,7 @@
 
 #if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) /*|| defined(__DOXYGEN__)*/
 
-#include "src/ginput/driver_toggle.h"
+#include "src/ginput/ginput_driver_toggle.h"
 
 GINPUT_TOGGLE_DECLARE_STRUCTURE();
 
diff --git a/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c b/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c
index 31443c45..e9492f55 100644
--- a/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c
+++ b/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c
@@ -10,7 +10,7 @@
 #if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) 
 
 #define GMOUSE_DRIVER_VMT		GMOUSEVMT_ADS7843
-#include "src/ginput/driver_mouse.h"
+#include "src/ginput/ginput_driver_mouse.h"
 
 // Get the hardware interface
 #include "gmouse_lld_ADS7843_board.h"
diff --git a/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c b/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c
index 6b0bcdb2..ba3db50b 100644
--- a/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c
+++ b/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c
@@ -10,7 +10,7 @@
 #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
 
 #define GMOUSE_DRIVER_VMT		GMOUSEVMT_FT5x06
-#include "src/ginput/driver_mouse.h"
+#include "src/ginput/ginput_driver_mouse.h"
 
 // Get the hardware interface
 #include "gmouse_lld_FT5x06_board.h"
diff --git a/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802.c b/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802.c
index 12f45645..713b9aad 100644
--- a/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802.c
+++ b/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802.c
@@ -10,7 +10,7 @@
 #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
 
 #define GMOUSE_DRIVER_VMT		GMOUSEVMT_MAX11802
-#include "src/ginput/driver_mouse.h"
+#include "src/ginput/ginput_driver_mouse.h"
 
 // Hardware definitions
 #include "drivers/ginput/touch/MAX11802/max11802.h"
diff --git a/drivers/ginput/touch/MCU/gmouse_lld_MCU.c b/drivers/ginput/touch/MCU/gmouse_lld_MCU.c
index babf8bc3..a69ae72e 100644
--- a/drivers/ginput/touch/MCU/gmouse_lld_MCU.c
+++ b/drivers/ginput/touch/MCU/gmouse_lld_MCU.c
@@ -10,7 +10,7 @@
 #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
 
 #define GMOUSE_DRIVER_VMT		GMOUSEVMT_MCU
-#include "src/ginput/driver_mouse.h"
+#include "src/ginput/ginput_driver_mouse.h"
 
 // Get the hardware interface
 #include "gmouse_lld_MCU_board.h"
diff --git a/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c
index 27bc280e..353539f9 100644
--- a/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c
+++ b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c
@@ -10,7 +10,7 @@
 #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
 
 #define GMOUSE_DRIVER_VMT		GMOUSEVMT_STMPE811
-#include "src/ginput/driver_mouse.h"
+#include "src/ginput/ginput_driver_mouse.h"
 
 // Hardware definitions
 #include "drivers/ginput/touch/STMPE811/stmpe811.h"
diff --git a/drivers/multiple/Win32/gdisp_lld_Win32.c b/drivers/multiple/Win32/gdisp_lld_Win32.c
index a85fae91..0335feee 100644
--- a/drivers/multiple/Win32/gdisp_lld_Win32.c
+++ b/drivers/multiple/Win32/gdisp_lld_Win32.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_Win32
 #include "gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 // Configuration parameters for this driver
 #ifndef GDISP_SCREEN_WIDTH
@@ -79,13 +79,13 @@
 
 #if GINPUT_NEED_TOGGLE
 	/* Include toggle support code */
-	#include "src/ginput/driver_toggle.h"
+	#include "src/ginput/ginput_driver_toggle.h"
 #endif
 
 #if GINPUT_NEED_MOUSE
 	// Include mouse support code
 	#define GMOUSE_DRIVER_VMT		GMOUSEVMT_Win32
-	#include "src/ginput/driver_mouse.h"
+	#include "src/ginput/ginput_driver_mouse.h"
 
 	// Forward definitions
 	static bool_t Win32MouseInit(GMouse *m, unsigned driverinstance);
@@ -126,14 +126,14 @@
 
 #if GINPUT_NEED_KEYBOARD
 	#define GKEYBOARD_DRIVER_VMT		GKEYBOARDVMT_Win32
-	#include "src/ginput/driver_keyboard.h"
+	#include "src/ginput/ginput_driver_keyboard.h"
 
 	#if !GKEYBOARD_WIN32_NO_LAYOUT
 		#if GKEYBOARD_LAYOUT_OFF
 			#error "The Win32 keyboard driver is using the layout engine. Please set GKEYBOARD_LAYOUT_OFF=FALSE or GKEYBOARD_WIN32_NO_LAYOUT=TRUE."
 		#endif
 
-		#include "src/ginput/keyboard_microcode.h"
+		#include "src/ginput/ginput_keyboard_microcode.h"
 
 		// Forward definitions
 		extern uint8_t	GKEYBOARD_WIN32_DEFAULT_LAYOUT[];
diff --git a/drivers/multiple/X/gdisp_lld_X.c b/drivers/multiple/X/gdisp_lld_X.c
index 8a29f033..265d03ee 100644
--- a/drivers/multiple/X/gdisp_lld_X.c
+++ b/drivers/multiple/X/gdisp_lld_X.c
@@ -17,7 +17,7 @@
 
 #define GDISP_DRIVER_VMT				GDISPVMT_X11
 #include "gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 
 // Configuration parameters for this driver
 #ifndef GDISP_FORCE_24BIT
@@ -53,7 +53,7 @@
 #if GINPUT_NEED_MOUSE
 	// Include mouse support code
 	#define GMOUSE_DRIVER_VMT		GMOUSEVMT_X11
-	#include "src/ginput/driver_mouse.h"
+	#include "src/ginput/ginput_driver_mouse.h"
 
 	// Forward definitions
 	static bool_t XMouseInit(GMouse *m, unsigned driverinstance);
@@ -95,7 +95,7 @@
 #if GINPUT_NEED_KEYBOARD
 	// Include mouse support code
 	#define GKEYBOARD_DRIVER_VMT		GKEYBOARDVMT_X
-	#include "src/ginput/driver_keyboard.h"
+	#include "src/ginput/ginput_driver_keyboard.h"
 
 	#if !GKEYBOARD_X_NO_LAYOUT
 		#if GKEYBOARD_LAYOUT_OFF
@@ -105,7 +105,7 @@
 		// Forward definitions
 		extern uint8_t	GKEYBOARD_X_DEFAULT_LAYOUT[];
 
-		#include "src/ginput/keyboard_microcode.h"
+		#include "src/ginput/ginput_keyboard_microcode.h"
 		#include <X11/keysym.h>
 
 		// This is the layout code for the English US keyboard.
diff --git a/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c b/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c
index 3b42bcda..fbc40916 100644
--- a/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c
+++ b/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c
@@ -11,7 +11,7 @@
 
 #define GDISP_DRIVER_VMT			GDISPVMT_uGFXnet
 #include "gdisp_lld_config.h"
-#include "src/gdisp/driver.h"
+#include "src/gdisp/gdisp_driver.h"
 #include "uGFXnetProtocol.h"
 
 #ifndef GDISP_SCREEN_WIDTH
@@ -36,7 +36,7 @@
 #if GINPUT_NEED_MOUSE
 	// Include mouse support code
 	#define GMOUSE_DRIVER_VMT		GMOUSEVMT_uGFXnet
-	#include "src/ginput/driver_mouse.h"
+	#include "src/ginput/ginput_driver_mouse.h"
 
 	// Forward definitions
 	static bool_t NMouseInit(GMouse *m, unsigned driverinstance);
diff --git a/gfx.h b/gfx.h
index dc7605e8..8be39815 100644
--- a/gfx.h
+++ b/gfx.h
@@ -161,18 +161,18 @@
  * Get all the options for each sub-system.
  *
  */
-#include "src/gos/sys_options.h"
-#include "src/gdriver/sys_options.h"
-#include "src/gfile/sys_options.h"
-#include "src/gmisc/sys_options.h"
-#include "src/gqueue/sys_options.h"
-#include "src/gevent/sys_options.h"
-#include "src/gtimer/sys_options.h"
-#include "src/gdisp/sys_options.h"
-#include "src/gwin/sys_options.h"
-#include "src/ginput/sys_options.h"
-#include "src/gadc/sys_options.h"
-#include "src/gaudio/sys_options.h"
+#include "src/gos/gos_options.h"
+#include "src/gdriver/gdriver_options.h"
+#include "src/gfile/gfile_options.h"
+#include "src/gmisc/gmisc_options.h"
+#include "src/gqueue/gqueue_options.h"
+#include "src/gevent/gevent_options.h"
+#include "src/gtimer/gtimer_options.h"
+#include "src/gdisp/gdisp_options.h"
+#include "src/gwin/gwin_options.h"
+#include "src/ginput/ginput_options.h"
+#include "src/gadc/gadc_options.h"
+#include "src/gaudio/gaudio_options.h"
 
 /**
  * Interdependency safety checks on the sub-systems.
@@ -182,34 +182,34 @@
 #ifndef GFX_DISPLAY_RULE_WARNINGS
 	#define GFX_DISPLAY_RULE_WARNINGS	FALSE
 #endif
-#include "src/gwin/sys_rules.h"
-#include "src/ginput/sys_rules.h"
-#include "src/gdisp/sys_rules.h"
-#include "src/gaudio/sys_rules.h"
-#include "src/gadc/sys_rules.h"
-#include "src/gevent/sys_rules.h"
-#include "src/gtimer/sys_rules.h"
-#include "src/gqueue/sys_rules.h"
-#include "src/gmisc/sys_rules.h"
-#include "src/gfile/sys_rules.h"
-#include "src/gdriver/sys_rules.h"
-#include "src/gos/sys_rules.h"
+#include "src/gwin/gwin_rules.h"
+#include "src/ginput/ginput_rules.h"
+#include "src/gdisp/gdisp_rules.h"
+#include "src/gaudio/gaudio_rules.h"
+#include "src/gadc/gadc_rules.h"
+#include "src/gevent/gevent_rules.h"
+#include "src/gtimer/gtimer_rules.h"
+#include "src/gqueue/gqueue_rules.h"
+#include "src/gmisc/gmisc_rules.h"
+#include "src/gfile/gfile_rules.h"
+#include "src/gdriver/gdriver_rules.h"
+#include "src/gos/gos_rules.h"
 
 /**
  *  Include the sub-system header files
  */
-#include "src/gos/sys_defs.h"
-//#include "src/gdriver/sys_defs.h"			// This module is only included by source that needs it.
-#include "src/gfile/sys_defs.h"
-#include "src/gmisc/sys_defs.h"
-#include "src/gqueue/sys_defs.h"
-#include "src/gevent/sys_defs.h"
-#include "src/gtimer/sys_defs.h"
-#include "src/gdisp/sys_defs.h"
-#include "src/gwin/sys_defs.h"
-#include "src/ginput/sys_defs.h"
-#include "src/gadc/sys_defs.h"
-#include "src/gaudio/sys_defs.h"
+#include "src/gos/gos.h"
+//#include "src/gdriver/gdriver.h"			// This module is only included by source that needs it.
+#include "src/gfile/gfile.h"
+#include "src/gmisc/gmisc.h"
+#include "src/gqueue/gqueue.h"
+#include "src/gevent/gevent.h"
+#include "src/gtimer/gtimer.h"
+#include "src/gdisp/gdisp.h"
+#include "src/gwin/gwin.h"
+#include "src/ginput/ginput.h"
+#include "src/gadc/gadc.h"
+#include "src/gaudio/gaudio.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/gfx.mk b/gfx.mk
index 89c3282a..765c02b1 100644
--- a/gfx.mk
+++ b/gfx.mk
@@ -1,18 +1,18 @@
 GFXINC +=   $(GFXLIB)
 GFXSRC +=	$(GFXLIB)/src/gfx.c
 
-include $(GFXLIB)/src/gos/sys_make.mk
-include $(GFXLIB)/src/gdriver/sys_make.mk
-include $(GFXLIB)/src/gqueue/sys_make.mk
-include $(GFXLIB)/src/gdisp/sys_make.mk
-include $(GFXLIB)/src/gevent/sys_make.mk
-include $(GFXLIB)/src/gtimer/sys_make.mk
-include $(GFXLIB)/src/gwin/sys_make.mk
-include $(GFXLIB)/src/ginput/sys_make.mk
-include $(GFXLIB)/src/gadc/sys_make.mk
-include $(GFXLIB)/src/gaudio/sys_make.mk
-include $(GFXLIB)/src/gmisc/sys_make.mk
-include $(GFXLIB)/src/gfile/sys_make.mk
+include $(GFXLIB)/src/gos/gos.mk
+include $(GFXLIB)/src/gdriver/gdriver.mk
+include $(GFXLIB)/src/gqueue/gqueue.mk
+include $(GFXLIB)/src/gdisp/gdisp.mk
+include $(GFXLIB)/src/gevent/gevent.mk
+include $(GFXLIB)/src/gtimer/gtimer.mk
+include $(GFXLIB)/src/gwin/gwin.mk
+include $(GFXLIB)/src/ginput/ginput.mk
+include $(GFXLIB)/src/gadc/gadc.mk
+include $(GFXLIB)/src/gaudio/gaudio.mk
+include $(GFXLIB)/src/gmisc/gmisc.mk
+include $(GFXLIB)/src/gfile/gfile.mk
 
 # Include the boards and drivers
 ifneq ($(GFXBOARD),)
diff --git a/src/gadc/driver.h b/src/gadc/driver.h
deleted file mode 100644
index 77604b9f..00000000
--- a/src/gadc/driver.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gadc/driver.h
- * @brief   GADC - Periodic ADC driver header file.
- *
- * @defgroup Driver Driver
- * @ingroup GADC
- * @{
- */
-
-#ifndef _GADC_LLD_H
-#define _GADC_LLD_H
-
-#include "gfx.h"
-
-#if GFX_USE_GADC || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-/**
- * @brief				The structure passed to start a timer conversion
- * @{
- */
-typedef struct GadcTimerJob_t {
-	uint32_t		physdev;					// @< The physical device/s. The exact meaning of physdev is hardware dependent.
-	uint32_t		frequency;					// @< The frequency to sample
-	adcsample_t		*buffer;					// @< Where to put the samples
-	size_t			todo;						// @< How many conversions to do
-	size_t			done;						// @< How many conversions have already been done
-} GadcTimerJob;
-/** @} */
-
-/**
- * @brief				The structure passed to do a single conversion
- * @{
- */
-typedef struct GadcNonTimerJob_t {
-	uint32_t				physdev;			// @< The physical device/s. The exact meaning of physdev is hardware dependent.
-	adcsample_t				*buffer;			// @< Where to put the samples.
-	} GadcNonTimerJob;
-/** @} */
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief				These routines are the callbacks that the driver uses.
- * @details				Defined in the high level GADC code.
- *
- * @notapi
- * @{
- */
-	/**
-	 * @brief	Indicate that some data has been placed into the buffer for the current job
-	 *
-	 * @param[in] n		The number of samples placed in the buffer
-	 *
-	 * @note		Calling this with n = 0 causes the current job to be terminated early or aborted.
-	 * 				It can be called in this mode on an ADC conversion error. Any job will then be
-	 * 				restarted by the high level code as appropriate.
-	 */
-	void gadcGotDataI(size_t n);
-/**
- * @}
- */
-
-/**
- * @brief				Initialise the driver
- *
- * @api
- */
-void gadc_lld_init(void);
-
-/**
- * @brief				Using the hardware dependant "physdev", return the number of samples for each conversion
- *
- * @param[in] physdev	The hardware dependent physical device descriptor
- *
- * @return				The number of samples per conversion
- *
- * @api
- */
-size_t gadc_lld_samplesperconversion(uint32_t physdev);
-
-/**
- * @brief				Start a periodic timer for high frequency conversions.
- *
- * @param[in] freq		The frequency for the timer
- *
- * @note				This will only be called if the timer is currently stopped.
- *
- * @api
- * @iclass
- */
-void gadc_lld_start_timerI(uint32_t freq);
-
-/**
- * @brief				Stop the periodic timer for high frequency conversions.
- *
- * @note				This will only be called if the timer is currently running and all timer jobs
- * 						have been completed/aborted.
- *
- * @api
- * @iclass
- */
-void gadc_lld_stop_timerI(void);
-
-/**
- * @brief				Start a set of high frequency conversions.
- *
- * @note				This will only be called if the timer is currently running and the ADC should be ready for
- * 						a new job.
- *
- * @param[in] pjob		The job to be started.
- *
- * @api
- * @iclass
- */
-void gadc_lld_timerjobI(GadcTimerJob *pjob);
-
-/**
- * @brief				Start a non-timer conversion.
- *
- * @note				This will only be called if the ADC should be ready for a new job.
- *
- * @param[in] pjob		The job to be started
- *
- * @api
- * @iclass
- */
-void gadc_lld_nontimerjobI(GadcNonTimerJob *pjob);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GADC */
-
-#endif /* _GADC_LLD_H */
-/** @} */
diff --git a/src/gadc/gadc.c b/src/gadc/gadc.c
new file mode 100644
index 00000000..ec0bc880
--- /dev/null
+++ b/src/gadc/gadc.c
@@ -0,0 +1,353 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GADC
+
+/* Include the driver defines */
+#include "gadc_driver.h"
+
+#if GADC_MAX_HIGH_SPEED_SAMPLERATE > GADC_MAX_SAMPLE_FREQUENCY/2
+	#error "GADC: GADC_MAX_HIGH_SPEED_SAMPLERATE has been set too high. It must be less than half the maximum CPU rate"
+#endif
+
+#define GADC_HSADC_GTIMER		0x8000
+#define GADC_ADC_RUNNING		0x4000
+#define GADC_HSADC_CONVERTION	0x2000
+
+typedef struct NonTimerData_t {
+	gfxQueueGSyncItem		next;
+	GADCCallbackFunction	callback;
+	union {
+		void				*param;
+		gfxSem				sigdone;
+	};
+	GadcNonTimerJob			job;
+	} NonTimerData;
+
+static volatile uint16_t		hsFlags;
+static size_t					hsBytesPerConv;
+static GadcTimerJob				hsJob;
+static GDataBuffer				*hsData;
+static gfxQueueGSync			hsListDone;
+static GADCISRCallbackFunction	hsISRcallback;
+#if GFX_USE_GEVENT
+	static GTimer				hsGTimer;
+#endif
+
+static GTimer					lsGTimer;
+static gfxQueueGSync			lsListToDo;
+static gfxQueueGSync			lsListDone;
+static NonTimerData				*lsData;
+
+void gadcGotDataI(size_t n) {
+	if ((hsFlags & GADC_HSADC_CONVERTION)) {
+
+		// A set of timer conversions is done - add them
+		hsJob.done += n;
+
+		// Are we finished yet? (or driver signalled complete now)
+		if (n && hsJob.done < hsJob.todo)
+			return;
+
+		// Clear event flags we might set
+		hsFlags &= ~(GADC_HSADC_GOTBUFFER|GADC_HSADC_STALL);
+
+		// Is there any data in it
+		if (!hsJob.done) {
+
+			// Oops - no data in this buffer. Just return it to the free-list
+			gfxBufferReleaseI(hsData);
+			goto starttimerjob;					// Restart the timer job
+		}
+
+		// Save the buffer on the hsListDone list
+		hsData->len = hsJob.done * hsBytesPerConv;
+		gfxQueueGSyncPutI(&hsListDone, (gfxQueueGSyncItem *)hsData);
+		hsFlags |= GADC_HSADC_GOTBUFFER;
+
+		/* Signal a buffer completion */
+		if (hsISRcallback)
+			hsISRcallback();
+		#if GFX_USE_GEVENT
+			if (hsFlags & GADC_HSADC_GTIMER)
+				gtimerJabI(&hsGTimer);
+		#endif
+
+		// Stop if we have been told to
+		if (!(hsFlags & GADC_HSADC_RUNNING)) {
+			gadc_lld_stop_timerI();
+
+		// Get the next free buffer
+		} else if (!(hsData = gfxBufferGetI())) {
+
+			// Oops - no free buffers. Stall
+			hsFlags &= ~GADC_HSADC_RUNNING;
+			hsFlags |= GADC_HSADC_STALL;
+			gadc_lld_stop_timerI();
+
+		// Prepare the next job
+		} else {
+
+			// Return this new job
+			#if GFX_USE_OS_CHIBIOS
+				// ChibiOS api bug - samples must be even
+				hsJob.todo = (hsData->size / hsBytesPerConv) & ~1;
+			#else
+				hsJob.todo = hsData->size / hsBytesPerConv;
+			#endif
+			hsJob.done = 0;
+			hsJob.buffer = (adcsample_t *)(hsData+1);
+		}
+
+		// Start a job preferring a non-timer job
+		if ((lsData = (NonTimerData *)gfxQueueGSyncGetI(&lsListToDo))) {
+			hsFlags &= ~GADC_HSADC_CONVERTION;
+			gadc_lld_nontimerjobI(&lsData->job);
+		} else if ((hsFlags & GADC_HSADC_RUNNING)) {
+			hsFlags |= GADC_HSADC_CONVERTION;
+			gadc_lld_timerjobI(&hsJob);
+		} else
+			hsFlags &= ~GADC_ADC_RUNNING;
+
+	} else {
+
+		// Did it fail
+		if (!n) {
+			// Push it back on the head of the queue - it didn't actually get done
+			gfxQueueGSyncPushI(&lsListToDo, (gfxQueueGSyncItem *)lsData);
+			lsData = 0;
+			goto starttimerjob;
+		}
+
+		// A non-timer job completed - signal
+		if (lsData->callback) {
+			// Put it on the completed list and signal the timer to do the call-backs
+			gfxQueueGSyncPutI(&lsListDone, (gfxQueueGSyncItem *)lsData);
+			gtimerJabI(&lsGTimer);
+		} else {
+			// Signal the thread directly
+			gfxSemSignalI(&lsData->sigdone);
+		}
+		lsData = 0;
+
+		// Start a job preferring a timer job
+starttimerjob:
+		if ((hsFlags & GADC_HSADC_RUNNING)) {
+			hsFlags |= GADC_HSADC_CONVERTION;
+			gadc_lld_timerjobI(&hsJob);
+		} else if ((lsData = (NonTimerData *)gfxQueueGSyncGetI(&lsListToDo))) {
+			hsFlags &= ~GADC_HSADC_CONVERTION;
+			gadc_lld_nontimerjobI(&lsData->job);
+		} else
+			hsFlags &= ~GADC_ADC_RUNNING;
+	}
+}
+
+/* Our module initialiser */
+void _gadcInit(void)
+{
+	gadc_lld_init();
+
+	gfxQueueGSyncInit(&hsListDone);
+	#if GFX_USE_GEVENT
+		gtimerInit(&hsGTimer);
+	#endif
+	gtimerInit(&lsGTimer);
+	gfxQueueGSyncInit(&lsListToDo);
+	gfxQueueGSyncInit(&lsListDone);
+}
+
+void _gadcDeinit(void)
+{
+	/* commented stuff is ToDo */
+
+	// gadc_lld_deinit();
+	gfxQueueGSyncDeinit(&hsListDone);
+	#if GFX_USE_GEVENT
+		gtimerDeinit(&hsGTimer);
+	#endif	
+	gtimerDeinit(&lsGTimer);
+	gfxQueueGSyncDeinit(&lsListToDo);
+	gfxQueueGSyncDeinit(&lsListDone);
+}
+
+#if GFX_USE_GEVENT
+	static void HighSpeedGTimerCallback(void *param) {
+		(void) param;
+		GSourceListener	*psl;
+		GEventADC		*pe;
+
+		psl = 0;
+		while ((psl = geventGetSourceListener((GSourceHandle)(&hsGTimer), psl))) {
+			if (!(pe = (GEventADC *)geventGetEventBuffer(psl))) {
+				// This listener is missing - save this.
+				psl->srcflags |= GADC_HSADC_LOSTEVENT;
+				continue;
+			}
+
+			pe->type = GEVENT_ADC;
+			pe->flags = (hsFlags & (GADC_HSADC_RUNNING|GADC_HSADC_GOTBUFFER|GADC_HSADC_STALL)) | psl->srcflags;
+			psl->srcflags = 0;
+			geventSendEvent(psl);
+		}
+	}
+#endif
+
+void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency)
+{
+	if ((hsFlags & GADC_HSADC_RUNNING))
+		gadcHighSpeedStop();
+
+	/* Just save the details and reset everything for now */
+	hsJob.physdev = physdev;
+	hsJob.frequency = frequency;
+	hsISRcallback = 0;
+	hsBytesPerConv = gadc_lld_samplesperconversion(physdev) * sizeof(adcsample_t);
+}
+
+#if GFX_USE_GEVENT
+	GSourceHandle gadcHighSpeedGetSource(void) {
+		if (!gtimerIsActive(&hsGTimer))
+			gtimerStart(&hsGTimer, HighSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
+		hsFlags |= GADC_HSADC_GTIMER;
+		return (GSourceHandle)&hsGTimer;
+	}
+#endif
+
+void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn) {
+	hsISRcallback = isrfn;
+}
+
+GDataBuffer *gadcHighSpeedGetData(delaytime_t ms) {
+	return (GDataBuffer *)gfxQueueGSyncGet(&hsListDone, ms);
+}
+
+GDataBuffer *gadcHighSpeedGetDataI(void) {
+	return (GDataBuffer *)gfxQueueGSyncGetI(&hsListDone);
+}
+
+void gadcHighSpeedStart(void) {
+	// Safety first
+	if (!hsJob.frequency || !hsBytesPerConv)
+		return;
+
+	gfxSystemLock();
+	if (!(hsFlags & GADC_HSADC_RUNNING)) {
+		if (!(hsData = gfxBufferGetI())) {
+			// Oops - no free buffers. Stall
+			hsFlags |= GADC_HSADC_STALL;
+			#if GFX_USE_GEVENT
+				if (hsFlags & GADC_HSADC_GTIMER)
+					gtimerJabI(&hsGTimer);
+			#endif
+
+		// Prepare the next job
+		} else {
+
+			#if GFX_USE_OS_CHIBIOS
+				// ChibiOS api bug - samples must be even
+				hsJob.todo = (hsData->size / hsBytesPerConv) & ~1;
+			#else
+				hsJob.todo = hsData->size / hsBytesPerConv;
+			#endif
+			hsJob.done = 0;
+			hsJob.buffer = (adcsample_t *)(hsData+1);
+			hsFlags |= GADC_HSADC_RUNNING;
+
+			// Start the timer
+			gadc_lld_start_timerI(hsJob.frequency);
+
+			// If nothing is running start the job
+			if (!(hsFlags & GADC_ADC_RUNNING)) {
+				hsFlags |= (GADC_HSADC_CONVERTION|GADC_ADC_RUNNING);
+				gadc_lld_timerjobI(&hsJob);
+			}
+		}
+	}
+	gfxSystemUnlock();
+}
+
+void gadcHighSpeedStop(void) {
+	// Stop it and wait for completion
+	hsFlags &= ~GADC_HSADC_RUNNING;
+	while ((hsFlags & GADC_HSADC_CONVERTION))
+		gfxYield();
+}
+
+static void LowSpeedGTimerCallback(void *param) {
+	(void) param;
+	NonTimerData		*pdata;
+
+	// Look for completed non-timer jobs and call the call-backs for each
+	while ((pdata = (NonTimerData *)gfxQueueGSyncGet(&lsListDone, TIME_IMMEDIATE))) {
+		pdata->callback(pdata->job.buffer, pdata->param);
+		gfxFree(pdata);
+	}
+}
+
+void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer) {
+	NonTimerData ndata;
+
+	// Prepare the job
+	gfxSemInit(&ndata.sigdone, 0, 1);
+	ndata.job.physdev = physdev;
+	ndata.job.buffer = buffer;
+	ndata.callback = 0;
+
+	// Activate it
+	gfxSystemLock();
+	if (!(hsFlags & GADC_ADC_RUNNING)) {
+		// Nothing is running - start the job
+		lsData = &ndata;
+		hsFlags |= GADC_ADC_RUNNING;
+		hsFlags &= ~GADC_HSADC_CONVERTION;
+		gadc_lld_nontimerjobI(&ndata.job);
+	} else {
+		// Just put it on the queue
+		gfxQueueGSyncPutI(&lsListToDo, (gfxQueueGSyncItem *)&ndata);
+	}
+	gfxSystemUnlock();
+
+	// Wait for it to complete
+	gfxSemWait(&ndata.sigdone, TIME_INFINITE);
+	gfxSemDestroy(&ndata.sigdone);
+}
+
+bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param) {
+	NonTimerData *pdata;
+
+	/* Start the Low Speed Timer */
+	if (!gtimerIsActive(&lsGTimer))
+		gtimerStart(&lsGTimer, LowSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
+
+	// Prepare the job
+	if (!(pdata = gfxAlloc(sizeof(NonTimerData))))
+		return FALSE;
+	pdata->job.physdev = physdev;
+	pdata->job.buffer = buffer;
+	pdata->callback = fn;
+	pdata->param = param;
+
+	// Activate it
+	gfxSystemLock();
+	if (!(hsFlags & GADC_ADC_RUNNING)) {
+		// Nothing is running - start the job
+		lsData = pdata;
+		hsFlags |= GADC_ADC_RUNNING;
+		hsFlags &= ~GADC_HSADC_CONVERTION;
+		gadc_lld_nontimerjobI(&pdata->job);
+	} else {
+		// Just put it on the queue
+		gfxQueueGSyncPutI(&lsListToDo, (gfxQueueGSyncItem *)pdata);
+	}
+	gfxSystemUnlock();
+	return TRUE;
+}
+
+#endif /* GFX_USE_GADC */
diff --git a/src/gadc/gadc.h b/src/gadc/gadc.h
new file mode 100644
index 00000000..461e490e
--- /dev/null
+++ b/src/gadc/gadc.h
@@ -0,0 +1,252 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gadc/gadc.h
+ *
+ * @addtogroup GADC
+ *
+ * @brief	Module to abstract the very variable ADC interfaces of the underlying systems
+ *
+ * @details	The reason why ChibiOS/GFX has it's own ADC abstraction is because
+ *			the Chibi-OS drivers are very CPU specific and do not
+ *			provide a way across all hardware platforms to create periodic
+ *			ADC conversions. There are also issues with devices with different
+ *			characteristics or periodic requirements on the same ADC
+ *			device (but different channels). This layer attempts to solve these
+ *			problems to provide a architecture neutral API. It also provides extra
+ *			features such as multi-buffer chaining for high speed ADC sources.
+ *			It provides one high speed virtual ADC device (eg a microphone) and
+ *			numerous low speed (less than 100Hz) virtual ADC devices (eg dials,
+ *			temperature sensors etc). The high speed device has timer based polling
+ *			to ensure exact conversion periods and a buffer management system.
+ *			The low speed devices are assumed to be non-critical timing devices
+ *			and do not have any buffer management.
+ *			Note that while only one high speed device has been provided it can
+ *			be used to read multiple physical ADC channels on the one physical
+ *			ADC device.
+ *			All callback routines are thread based unlike the Chibi-OS interrupt based
+ *			routines.
+ *
+ * @{
+ */
+
+#ifndef _GADC_H
+#define _GADC_H
+
+#include "gfx.h"
+
+#if GFX_USE_GADC || defined(__DOXYGEN__)
+
+/* Include the driver defines */
+#include "gadc_lld_config.h"
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+// Event types for GADC
+#define GEVENT_ADC			(GEVENT_GADC_FIRST+0)
+
+/**
+ * @brief   The High Speed ADC event structure.
+ * @{
+ */
+typedef struct GEventADC_t {
+	#if GFX_USE_GEVENT || defined(__DOXYGEN__)
+		/**
+		 * @brief The type of this event (GEVENT_ADC)
+		 */
+		GEventType		type;
+	#endif
+
+	/**
+	 * @brief The event flags
+	 */
+	uint16_t		flags;
+		/**
+		 * @brief   The event flag values.
+		 * @{
+		 */
+		#define	GADC_HSADC_LOSTEVENT		0x0001		/**< @brief The last GEVENT_HSDADC event was lost */
+		#define	GADC_HSADC_RUNNING			0x0002		/**< @brief The High Speed ADC is currently running */
+		#define	GADC_HSADC_GOTBUFFER		0x0004		/**< @brief A buffer is ready for processing */
+		#define	GADC_HSADC_STALL			0x0008		/**< @brief The High Speed ADC has stalled due to no free buffers */
+		/** @} */
+} GEventADC;
+/** @} */
+
+/**
+ * @brief A callback function (executed in a thread context) for a low speed conversion
+ */
+typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param);
+
+/**
+ * @brief A callback function (executed in an ISR context) for a high speed conversion
+ */
+typedef void (*GADCISRCallbackFunction)(void);
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief				Initialise the high speed ADC.
+ * @details				Initialises but does not start the conversions.
+ *
+ * @param[in] physdev			A value passed to describe which physical ADC devices/channels to use.
+ * @param[in] frequency			The frequency to create ADC conversions
+ *
+ * @note				If the high speed ADC is running it will be stopped. The Event subsystem is
+ * 						disconnected from the high speed ADC and any binary semaphore event is forgotten.
+ * @note				ChibiOS ONLY: Due to a bug in ChibiOS each buffer on the free-list must contain an even number of
+ * 						samples and for multi-channel devices it must hold a number of samples that is evenly divisible
+ * 						by 2 times the number of active channels.
+ * @note				The physdev parameter may be used to turn on more than one ADC channel.
+ * 						Each channel is then interleaved into the provided buffer. Make sure your buffers all hold
+ * 						a number of samples evenly divisible by the number of active channels.
+ * 						As an example, if physdev turns on 2 devices then the buffer contains
+ * 						alternate device samples and the buffer must contain multiples of 2 samples.
+ * 						The exact meaning of physdev is hardware dependent.
+ * @note				While the high speed ADC is running, low speed conversions can only occur at
+ * 						the frequency of the high speed events. Thus if high speed events are
+ * 						being created at 50Hz (eg 100 samples/buffer, frequency = 5kHz) then the maximum
+ * 						frequency for low speed conversions will be 50Hz.
+ * @note				Only a single sample format is supported - that provided by the GADC driver. That sample
+ * 						format applies to both high speed and low speed sampling.
+ *
+ * @api
+ */
+void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency);
+
+#if GFX_USE_GEVENT || defined(__DOXYGEN__)
+	/**
+	 * @brief   			Turn on sending results to the GEVENT sub-system.
+	 * @details				Returns a GSourceHandle to listen for GEVENT_ADC events.
+	 *
+	 * @note				The high speed ADC will not use the GEVENT system unless this is
+	 * 						called first. This saves processing time if the application does
+	 * 						not want to use the GEVENT sub-system for the high speed ADC.
+	 * 						Once turned on it can only be turned off by calling @p gadcHighSpeedInit() again.
+	 * @note				The high speed ADC is capable of signalling via this method, an ISR callback and a
+	 * 						binary semaphore at the same time.
+	 *
+	 * @return				The GSourceHandle
+	 *
+	 * @api
+	 */
+	GSourceHandle gadcHighSpeedGetSource(void);
+#endif
+
+/**
+ * @brief				Allow retrieving of results from the high speed ADC using an ISR callback.
+ *
+ * @param[in] isrfn			The callback function (called in an ISR context).
+ *
+ * @note				Passing a NULL for isrfn will turn off signalling via this method as will calling
+ * 						@p gadcHighSpeedInit().
+ * @note				The high speed ADC is capable of signalling via this method, a blocked thread and the GEVENT
+ * 						sub-system at the same time.
+ *
+ * @api
+ */
+void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn);
+
+/**
+ * @brief		Get a filled buffer from the ADC
+ * @return		A GDataBuffer pointer or NULL if the timeout is exceeded
+ *
+ * @param[in] ms	The maximum amount of time in milliseconds to wait for data if some is not currently available.
+ *
+ * @note		After processing the data, your application must return the buffer to the free-list so that
+ * 				it can be used again. This can be done using @p gfxBufferRelease().
+ * @note		A buffer may be returned to the free-list before you have finished processing it provided you finish
+ * 				processing it before GADC re-uses it. This is useful when RAM usage is critical to reduce the number
+ * 				of buffers required. It works before the free list is a FIFO queue and therefore buffers are kept
+ * 				in the queue as long as possible before they are re-used.
+ * @note		The function ending with "I" is the interrupt class function.
+ * @api
+ * @{
+ */
+GDataBuffer *gadcHighSpeedGetData(delaytime_t ms);
+GDataBuffer *gadcHighSpeedGetDataI(void);
+/** @} */
+
+/**
+ * @brief   Start the high speed ADC conversions.
+ * @pre		It must have been initialised first with @p gadcHighSpeedInit()
+ *
+ * @api
+ */
+void gadcHighSpeedStart(void);
+
+/**
+ * @brief   Stop the high speed ADC conversions.
+ *
+ * @api
+ */
+void gadcHighSpeedStop(void);
+
+/**
+ * @brief	Perform a single low speed ADC conversion
+ * @details	Blocks until the conversion is complete
+ * @pre		This should not be called from within a GTimer callback as this routine
+ * 			blocks until the conversion is ready.
+ *
+ * @param[in] physdev		A value passed to describe which physical ADC devices/channels to use.
+ * @param[in] buffer		The static buffer to put the ADC samples into.
+ *
+ * @note	This may take a while to complete if the high speed ADC is running as the
+ * 			conversion is interleaved with the high speed ADC conversions on a buffer
+ * 			completion.
+ * @note	The result buffer must be large enough to store one sample per device
+ * 			described by the 'physdev' parameter.
+ * @note	Specifying more than one device in physdev is possible but discouraged as the
+ * 			calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
+ * 			from over-running the high speed ADC include high speed device stalling or samples being lost.
+ *
+ * @api
+ */
+void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer);
+
+/**
+ * @brief	Perform a low speed ADC conversion with callback (in a thread context)
+ * @details	Returns FALSE if internal memory allocation fails
+ *
+ * @param[in] physdev		A value passed to describe which physical ADC devices/channels to use.
+ * @param[in] buffer		The static buffer to put the ADC samples into.
+ * @param[in] fn			The callback function to call when the conversion is complete.
+ * @param[in] param			A parameter to pass to the callback function.
+ *
+ * @return					FALSE if no free low speed ADC slots.
+ *
+ * @note	This may be safely called from within a GTimer callback.
+ * @note	The callback may take a while to occur if the high speed ADC is running as the
+ * 			conversion is interleaved with the high speed ADC conversions on a buffer
+ * 			completion.
+ * @note	The result buffer must be large enough to store one sample per device
+ * 			described by the 'physdev' parameter.
+ * @note	Specifying more than one device in physdev is possible but discouraged as the
+ * 			calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
+ * 			from over-running the high speed ADC include high speed samples being lost.
+ *
+ * @api
+ */
+bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GADC */
+
+#endif /* _GADC_H */
+/** @} */
diff --git a/src/gadc/gadc.mk b/src/gadc/gadc.mk
new file mode 100644
index 00000000..05b1e9cc
--- /dev/null
+++ b/src/gadc/gadc.mk
@@ -0,0 +1 @@
+GFXSRC +=   $(GFXLIB)/src/gadc/gadc.c
diff --git a/src/gadc/gadc_driver.h b/src/gadc/gadc_driver.h
new file mode 100644
index 00000000..7c72dfd4
--- /dev/null
+++ b/src/gadc/gadc_driver.h
@@ -0,0 +1,153 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gadc/gadc_driver.h
+ * @brief   GADC - Periodic ADC driver header file.
+ *
+ * @defgroup Driver Driver
+ * @ingroup GADC
+ * @{
+ */
+
+#ifndef _GADC_LLD_H
+#define _GADC_LLD_H
+
+#include "gfx.h"
+
+#if GFX_USE_GADC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+/**
+ * @brief				The structure passed to start a timer conversion
+ * @{
+ */
+typedef struct GadcTimerJob_t {
+	uint32_t		physdev;					// @< The physical device/s. The exact meaning of physdev is hardware dependent.
+	uint32_t		frequency;					// @< The frequency to sample
+	adcsample_t		*buffer;					// @< Where to put the samples
+	size_t			todo;						// @< How many conversions to do
+	size_t			done;						// @< How many conversions have already been done
+} GadcTimerJob;
+/** @} */
+
+/**
+ * @brief				The structure passed to do a single conversion
+ * @{
+ */
+typedef struct GadcNonTimerJob_t {
+	uint32_t				physdev;			// @< The physical device/s. The exact meaning of physdev is hardware dependent.
+	adcsample_t				*buffer;			// @< Where to put the samples.
+	} GadcNonTimerJob;
+/** @} */
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief				These routines are the callbacks that the driver uses.
+ * @details				Defined in the high level GADC code.
+ *
+ * @notapi
+ * @{
+ */
+	/**
+	 * @brief	Indicate that some data has been placed into the buffer for the current job
+	 *
+	 * @param[in] n		The number of samples placed in the buffer
+	 *
+	 * @note		Calling this with n = 0 causes the current job to be terminated early or aborted.
+	 * 				It can be called in this mode on an ADC conversion error. Any job will then be
+	 * 				restarted by the high level code as appropriate.
+	 */
+	void gadcGotDataI(size_t n);
+/**
+ * @}
+ */
+
+/**
+ * @brief				Initialise the driver
+ *
+ * @api
+ */
+void gadc_lld_init(void);
+
+/**
+ * @brief				Using the hardware dependant "physdev", return the number of samples for each conversion
+ *
+ * @param[in] physdev	The hardware dependent physical device descriptor
+ *
+ * @return				The number of samples per conversion
+ *
+ * @api
+ */
+size_t gadc_lld_samplesperconversion(uint32_t physdev);
+
+/**
+ * @brief				Start a periodic timer for high frequency conversions.
+ *
+ * @param[in] freq		The frequency for the timer
+ *
+ * @note				This will only be called if the timer is currently stopped.
+ *
+ * @api
+ * @iclass
+ */
+void gadc_lld_start_timerI(uint32_t freq);
+
+/**
+ * @brief				Stop the periodic timer for high frequency conversions.
+ *
+ * @note				This will only be called if the timer is currently running and all timer jobs
+ * 						have been completed/aborted.
+ *
+ * @api
+ * @iclass
+ */
+void gadc_lld_stop_timerI(void);
+
+/**
+ * @brief				Start a set of high frequency conversions.
+ *
+ * @note				This will only be called if the timer is currently running and the ADC should be ready for
+ * 						a new job.
+ *
+ * @param[in] pjob		The job to be started.
+ *
+ * @api
+ * @iclass
+ */
+void gadc_lld_timerjobI(GadcTimerJob *pjob);
+
+/**
+ * @brief				Start a non-timer conversion.
+ *
+ * @note				This will only be called if the ADC should be ready for a new job.
+ *
+ * @param[in] pjob		The job to be started
+ *
+ * @api
+ * @iclass
+ */
+void gadc_lld_nontimerjobI(GadcNonTimerJob *pjob);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GADC */
+
+#endif /* _GADC_LLD_H */
+/** @} */
diff --git a/src/gadc/gadc_gadc.c b/src/gadc/gadc_gadc.c
deleted file mode 100644
index 5ac8e53c..00000000
--- a/src/gadc/gadc_gadc.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gadc/gadc_gadc.c
- * @brief   GADC sub-system code.
- *
- * @addtogroup GADC
- * @{
- */
-#include "gfx.h"
-
-#if GFX_USE_GADC
-
-/* Include the driver defines */
-#include "driver.h"
-
-#if GADC_MAX_HIGH_SPEED_SAMPLERATE > GADC_MAX_SAMPLE_FREQUENCY/2
-	#error "GADC: GADC_MAX_HIGH_SPEED_SAMPLERATE has been set too high. It must be less than half the maximum CPU rate"
-#endif
-
-#define GADC_HSADC_GTIMER		0x8000
-#define GADC_ADC_RUNNING		0x4000
-#define GADC_HSADC_CONVERTION	0x2000
-
-typedef struct NonTimerData_t {
-	gfxQueueGSyncItem		next;
-	GADCCallbackFunction	callback;
-	union {
-		void				*param;
-		gfxSem				sigdone;
-	};
-	GadcNonTimerJob			job;
-	} NonTimerData;
-
-static volatile uint16_t		hsFlags;
-static size_t					hsBytesPerConv;
-static GadcTimerJob				hsJob;
-static GDataBuffer				*hsData;
-static gfxQueueGSync			hsListDone;
-static GADCISRCallbackFunction	hsISRcallback;
-#if GFX_USE_GEVENT
-	static GTimer				hsGTimer;
-#endif
-
-static GTimer					lsGTimer;
-static gfxQueueGSync			lsListToDo;
-static gfxQueueGSync			lsListDone;
-static NonTimerData				*lsData;
-
-void gadcGotDataI(size_t n) {
-	if ((hsFlags & GADC_HSADC_CONVERTION)) {
-
-		// A set of timer conversions is done - add them
-		hsJob.done += n;
-
-		// Are we finished yet? (or driver signalled complete now)
-		if (n && hsJob.done < hsJob.todo)
-			return;
-
-		// Clear event flags we might set
-		hsFlags &= ~(GADC_HSADC_GOTBUFFER|GADC_HSADC_STALL);
-
-		// Is there any data in it
-		if (!hsJob.done) {
-
-			// Oops - no data in this buffer. Just return it to the free-list
-			gfxBufferReleaseI(hsData);
-			goto starttimerjob;					// Restart the timer job
-		}
-
-		// Save the buffer on the hsListDone list
-		hsData->len = hsJob.done * hsBytesPerConv;
-		gfxQueueGSyncPutI(&hsListDone, (gfxQueueGSyncItem *)hsData);
-		hsFlags |= GADC_HSADC_GOTBUFFER;
-
-		/* Signal a buffer completion */
-		if (hsISRcallback)
-			hsISRcallback();
-		#if GFX_USE_GEVENT
-			if (hsFlags & GADC_HSADC_GTIMER)
-				gtimerJabI(&hsGTimer);
-		#endif
-
-		// Stop if we have been told to
-		if (!(hsFlags & GADC_HSADC_RUNNING)) {
-			gadc_lld_stop_timerI();
-
-		// Get the next free buffer
-		} else if (!(hsData = gfxBufferGetI())) {
-
-			// Oops - no free buffers. Stall
-			hsFlags &= ~GADC_HSADC_RUNNING;
-			hsFlags |= GADC_HSADC_STALL;
-			gadc_lld_stop_timerI();
-
-		// Prepare the next job
-		} else {
-
-			// Return this new job
-			#if GFX_USE_OS_CHIBIOS
-				// ChibiOS api bug - samples must be even
-				hsJob.todo = (hsData->size / hsBytesPerConv) & ~1;
-			#else
-				hsJob.todo = hsData->size / hsBytesPerConv;
-			#endif
-			hsJob.done = 0;
-			hsJob.buffer = (adcsample_t *)(hsData+1);
-		}
-
-		// Start a job preferring a non-timer job
-		if ((lsData = (NonTimerData *)gfxQueueGSyncGetI(&lsListToDo))) {
-			hsFlags &= ~GADC_HSADC_CONVERTION;
-			gadc_lld_nontimerjobI(&lsData->job);
-		} else if ((hsFlags & GADC_HSADC_RUNNING)) {
-			hsFlags |= GADC_HSADC_CONVERTION;
-			gadc_lld_timerjobI(&hsJob);
-		} else
-			hsFlags &= ~GADC_ADC_RUNNING;
-
-	} else {
-
-		// Did it fail
-		if (!n) {
-			// Push it back on the head of the queue - it didn't actually get done
-			gfxQueueGSyncPushI(&lsListToDo, (gfxQueueGSyncItem *)lsData);
-			lsData = 0;
-			goto starttimerjob;
-		}
-
-		// A non-timer job completed - signal
-		if (lsData->callback) {
-			// Put it on the completed list and signal the timer to do the call-backs
-			gfxQueueGSyncPutI(&lsListDone, (gfxQueueGSyncItem *)lsData);
-			gtimerJabI(&lsGTimer);
-		} else {
-			// Signal the thread directly
-			gfxSemSignalI(&lsData->sigdone);
-		}
-		lsData = 0;
-
-		// Start a job preferring a timer job
-starttimerjob:
-		if ((hsFlags & GADC_HSADC_RUNNING)) {
-			hsFlags |= GADC_HSADC_CONVERTION;
-			gadc_lld_timerjobI(&hsJob);
-		} else if ((lsData = (NonTimerData *)gfxQueueGSyncGetI(&lsListToDo))) {
-			hsFlags &= ~GADC_HSADC_CONVERTION;
-			gadc_lld_nontimerjobI(&lsData->job);
-		} else
-			hsFlags &= ~GADC_ADC_RUNNING;
-	}
-}
-
-/* Our module initialiser */
-void _gadcInit(void)
-{
-	gadc_lld_init();
-
-	gfxQueueGSyncInit(&hsListDone);
-	#if GFX_USE_GEVENT
-		gtimerInit(&hsGTimer);
-	#endif
-	gtimerInit(&lsGTimer);
-	gfxQueueGSyncInit(&lsListToDo);
-	gfxQueueGSyncInit(&lsListDone);
-}
-
-void _gadcDeinit(void)
-{
-	/* commented stuff is ToDo */
-
-	// gadc_lld_deinit();
-	gfxQueueGSyncDeinit(&hsListDone);
-	#if GFX_USE_GEVENT
-		gtimerDeinit(&hsGTimer);
-	#endif	
-	gtimerDeinit(&lsGTimer);
-	gfxQueueGSyncDeinit(&lsListToDo);
-	gfxQueueGSyncDeinit(&lsListDone);
-}
-
-#if GFX_USE_GEVENT
-	static void HighSpeedGTimerCallback(void *param) {
-		(void) param;
-		GSourceListener	*psl;
-		GEventADC		*pe;
-
-		psl = 0;
-		while ((psl = geventGetSourceListener((GSourceHandle)(&hsGTimer), psl))) {
-			if (!(pe = (GEventADC *)geventGetEventBuffer(psl))) {
-				// This listener is missing - save this.
-				psl->srcflags |= GADC_HSADC_LOSTEVENT;
-				continue;
-			}
-
-			pe->type = GEVENT_ADC;
-			pe->flags = (hsFlags & (GADC_HSADC_RUNNING|GADC_HSADC_GOTBUFFER|GADC_HSADC_STALL)) | psl->srcflags;
-			psl->srcflags = 0;
-			geventSendEvent(psl);
-		}
-	}
-#endif
-
-void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency)
-{
-	if ((hsFlags & GADC_HSADC_RUNNING))
-		gadcHighSpeedStop();
-
-	/* Just save the details and reset everything for now */
-	hsJob.physdev = physdev;
-	hsJob.frequency = frequency;
-	hsISRcallback = 0;
-	hsBytesPerConv = gadc_lld_samplesperconversion(physdev) * sizeof(adcsample_t);
-}
-
-#if GFX_USE_GEVENT
-	GSourceHandle gadcHighSpeedGetSource(void) {
-		if (!gtimerIsActive(&hsGTimer))
-			gtimerStart(&hsGTimer, HighSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
-		hsFlags |= GADC_HSADC_GTIMER;
-		return (GSourceHandle)&hsGTimer;
-	}
-#endif
-
-void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn) {
-	hsISRcallback = isrfn;
-}
-
-GDataBuffer *gadcHighSpeedGetData(delaytime_t ms) {
-	return (GDataBuffer *)gfxQueueGSyncGet(&hsListDone, ms);
-}
-
-GDataBuffer *gadcHighSpeedGetDataI(void) {
-	return (GDataBuffer *)gfxQueueGSyncGetI(&hsListDone);
-}
-
-void gadcHighSpeedStart(void) {
-	// Safety first
-	if (!hsJob.frequency || !hsBytesPerConv)
-		return;
-
-	gfxSystemLock();
-	if (!(hsFlags & GADC_HSADC_RUNNING)) {
-		if (!(hsData = gfxBufferGetI())) {
-			// Oops - no free buffers. Stall
-			hsFlags |= GADC_HSADC_STALL;
-			#if GFX_USE_GEVENT
-				if (hsFlags & GADC_HSADC_GTIMER)
-					gtimerJabI(&hsGTimer);
-			#endif
-
-		// Prepare the next job
-		} else {
-
-			#if GFX_USE_OS_CHIBIOS
-				// ChibiOS api bug - samples must be even
-				hsJob.todo = (hsData->size / hsBytesPerConv) & ~1;
-			#else
-				hsJob.todo = hsData->size / hsBytesPerConv;
-			#endif
-			hsJob.done = 0;
-			hsJob.buffer = (adcsample_t *)(hsData+1);
-			hsFlags |= GADC_HSADC_RUNNING;
-
-			// Start the timer
-			gadc_lld_start_timerI(hsJob.frequency);
-
-			// If nothing is running start the job
-			if (!(hsFlags & GADC_ADC_RUNNING)) {
-				hsFlags |= (GADC_HSADC_CONVERTION|GADC_ADC_RUNNING);
-				gadc_lld_timerjobI(&hsJob);
-			}
-		}
-	}
-	gfxSystemUnlock();
-}
-
-void gadcHighSpeedStop(void) {
-	// Stop it and wait for completion
-	hsFlags &= ~GADC_HSADC_RUNNING;
-	while ((hsFlags & GADC_HSADC_CONVERTION))
-		gfxYield();
-}
-
-static void LowSpeedGTimerCallback(void *param) {
-	(void) param;
-	NonTimerData		*pdata;
-
-	// Look for completed non-timer jobs and call the call-backs for each
-	while ((pdata = (NonTimerData *)gfxQueueGSyncGet(&lsListDone, TIME_IMMEDIATE))) {
-		pdata->callback(pdata->job.buffer, pdata->param);
-		gfxFree(pdata);
-	}
-}
-
-void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer) {
-	NonTimerData ndata;
-
-	// Prepare the job
-	gfxSemInit(&ndata.sigdone, 0, 1);
-	ndata.job.physdev = physdev;
-	ndata.job.buffer = buffer;
-	ndata.callback = 0;
-
-	// Activate it
-	gfxSystemLock();
-	if (!(hsFlags & GADC_ADC_RUNNING)) {
-		// Nothing is running - start the job
-		lsData = &ndata;
-		hsFlags |= GADC_ADC_RUNNING;
-		hsFlags &= ~GADC_HSADC_CONVERTION;
-		gadc_lld_nontimerjobI(&ndata.job);
-	} else {
-		// Just put it on the queue
-		gfxQueueGSyncPutI(&lsListToDo, (gfxQueueGSyncItem *)&ndata);
-	}
-	gfxSystemUnlock();
-
-	// Wait for it to complete
-	gfxSemWait(&ndata.sigdone, TIME_INFINITE);
-	gfxSemDestroy(&ndata.sigdone);
-}
-
-bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param) {
-	NonTimerData *pdata;
-
-	/* Start the Low Speed Timer */
-	if (!gtimerIsActive(&lsGTimer))
-		gtimerStart(&lsGTimer, LowSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
-
-	// Prepare the job
-	if (!(pdata = gfxAlloc(sizeof(NonTimerData))))
-		return FALSE;
-	pdata->job.physdev = physdev;
-	pdata->job.buffer = buffer;
-	pdata->callback = fn;
-	pdata->param = param;
-
-	// Activate it
-	gfxSystemLock();
-	if (!(hsFlags & GADC_ADC_RUNNING)) {
-		// Nothing is running - start the job
-		lsData = pdata;
-		hsFlags |= GADC_ADC_RUNNING;
-		hsFlags &= ~GADC_HSADC_CONVERTION;
-		gadc_lld_nontimerjobI(&pdata->job);
-	} else {
-		// Just put it on the queue
-		gfxQueueGSyncPutI(&lsListToDo, (gfxQueueGSyncItem *)pdata);
-	}
-	gfxSystemUnlock();
-	return TRUE;
-}
-
-#endif /* GFX_USE_GADC */
-/** @} */
-
diff --git a/src/gadc/gadc_options.h b/src/gadc/gadc_options.h
new file mode 100644
index 00000000..18c5038c
--- /dev/null
+++ b/src/gadc/gadc_options.h
@@ -0,0 +1,42 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gadc/gadc_options.h
+ * @brief   GADC - Periodic ADC subsystem options header file.
+ *
+ * @addtogroup GADC
+ * @{
+ */
+
+#ifndef _GADC_OPTIONS_H
+#define _GADC_OPTIONS_H
+
+/**
+ * @name    GADC Functionality to be included
+ * @{
+ */
+/**
+ * @}
+ *
+ * @name    GADC Optional Sizing Parameters
+ * @{
+ */
+	/**
+	 * @brief   The maximum GADC sample rate
+	 * @details	Defaults to 44000
+	 * @note	This value must be less than half the maximum sample rate allowed by the CPU.
+	 * 			This is to ensure there is time between high speed samples to perform low
+	 * 			speed device sampling.
+	 */
+	#ifndef GADC_MAX_HIGH_SPEED_SAMPLERATE
+		#define GADC_MAX_HIGH_SPEED_SAMPLERATE	44000
+	#endif
+/** @} */
+
+#endif /* _GADC_OPTIONS_H */
+/** @} */
diff --git a/src/gadc/gadc_rules.h b/src/gadc/gadc_rules.h
new file mode 100644
index 00000000..d6c6e5ee
--- /dev/null
+++ b/src/gadc/gadc_rules.h
@@ -0,0 +1,41 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gadc/gadc_rules.h
+ * @brief   GADC safety rules header file.
+ *
+ * @addtogroup GADC
+ * @{
+ */
+
+#ifndef _GADC_RULES_H
+#define _GADC_RULES_H
+
+#if GFX_USE_GADC
+	#if !GFX_USE_GTIMER
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GADC: GFX_USE_GTIMER is required if GFX_USE_GADC is TRUE. It has been turned on for you."
+		#endif
+		#undef GFX_USE_GTIMER
+		#define	GFX_USE_GTIMER		TRUE
+	#endif
+	#if !GFX_USE_GQUEUE || !GQUEUE_NEED_GSYNC || !GQUEUE_NEED_BUFFERS
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GADC: GFX_USE_GQUEUE, GQUEUE_NEED_BUFFERS and GQUEUE_NEED_GSYNC are required if GFX_USE_GADC is TRUE. They have been turned on for you."
+		#endif
+		#undef GFX_USE_GQUEUE
+		#define	GFX_USE_GQUEUE		TRUE
+		#undef GQUEUE_NEED_BUFFERS
+		#define	GQUEUE_NEED_BUFFERS		TRUE
+		#undef GQUEUE_NEED_GSYNC
+		#define	GQUEUE_NEED_GSYNC		TRUE
+	#endif
+#endif
+
+#endif /* _GADC_RULES_H */
+/** @} */
diff --git a/src/gadc/sys_defs.h b/src/gadc/sys_defs.h
deleted file mode 100644
index 1f40f6df..00000000
--- a/src/gadc/sys_defs.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gadc/sys_defs.h
- *
- * @addtogroup GADC
- *
- * @brief	Module to abstract the very variable ADC interfaces of the underlying systems
- *
- * @details	The reason why ChibiOS/GFX has it's own ADC abstraction is because
- *			the Chibi-OS drivers are very CPU specific and do not
- *			provide a way across all hardware platforms to create periodic
- *			ADC conversions. There are also issues with devices with different
- *			characteristics or periodic requirements on the same ADC
- *			device (but different channels). This layer attempts to solve these
- *			problems to provide a architecture neutral API. It also provides extra
- *			features such as multi-buffer chaining for high speed ADC sources.
- *			It provides one high speed virtual ADC device (eg a microphone) and
- *			numerous low speed (less than 100Hz) virtual ADC devices (eg dials,
- *			temperature sensors etc). The high speed device has timer based polling
- *			to ensure exact conversion periods and a buffer management system.
- *			The low speed devices are assumed to be non-critical timing devices
- *			and do not have any buffer management.
- *			Note that while only one high speed device has been provided it can
- *			be used to read multiple physical ADC channels on the one physical
- *			ADC device.
- *			All callback routines are thread based unlike the Chibi-OS interrupt based
- *			routines.
- *
- * @{
- */
-
-#ifndef _GADC_H
-#define _GADC_H
-
-#include "gfx.h"
-
-#if GFX_USE_GADC || defined(__DOXYGEN__)
-
-/* Include the driver defines */
-#include "gadc_lld_config.h"
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-// Event types for GADC
-#define GEVENT_ADC			(GEVENT_GADC_FIRST+0)
-
-/**
- * @brief   The High Speed ADC event structure.
- * @{
- */
-typedef struct GEventADC_t {
-	#if GFX_USE_GEVENT || defined(__DOXYGEN__)
-		/**
-		 * @brief The type of this event (GEVENT_ADC)
-		 */
-		GEventType		type;
-	#endif
-
-	/**
-	 * @brief The event flags
-	 */
-	uint16_t		flags;
-		/**
-		 * @brief   The event flag values.
-		 * @{
-		 */
-		#define	GADC_HSADC_LOSTEVENT		0x0001		/**< @brief The last GEVENT_HSDADC event was lost */
-		#define	GADC_HSADC_RUNNING			0x0002		/**< @brief The High Speed ADC is currently running */
-		#define	GADC_HSADC_GOTBUFFER		0x0004		/**< @brief A buffer is ready for processing */
-		#define	GADC_HSADC_STALL			0x0008		/**< @brief The High Speed ADC has stalled due to no free buffers */
-		/** @} */
-} GEventADC;
-/** @} */
-
-/**
- * @brief A callback function (executed in a thread context) for a low speed conversion
- */
-typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param);
-
-/**
- * @brief A callback function (executed in an ISR context) for a high speed conversion
- */
-typedef void (*GADCISRCallbackFunction)(void);
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief				Initialise the high speed ADC.
- * @details				Initialises but does not start the conversions.
- *
- * @param[in] physdev			A value passed to describe which physical ADC devices/channels to use.
- * @param[in] frequency			The frequency to create ADC conversions
- *
- * @note				If the high speed ADC is running it will be stopped. The Event subsystem is
- * 						disconnected from the high speed ADC and any binary semaphore event is forgotten.
- * @note				ChibiOS ONLY: Due to a bug in ChibiOS each buffer on the free-list must contain an even number of
- * 						samples and for multi-channel devices it must hold a number of samples that is evenly divisible
- * 						by 2 times the number of active channels.
- * @note				The physdev parameter may be used to turn on more than one ADC channel.
- * 						Each channel is then interleaved into the provided buffer. Make sure your buffers all hold
- * 						a number of samples evenly divisible by the number of active channels.
- * 						As an example, if physdev turns on 2 devices then the buffer contains
- * 						alternate device samples and the buffer must contain multiples of 2 samples.
- * 						The exact meaning of physdev is hardware dependent.
- * @note				While the high speed ADC is running, low speed conversions can only occur at
- * 						the frequency of the high speed events. Thus if high speed events are
- * 						being created at 50Hz (eg 100 samples/buffer, frequency = 5kHz) then the maximum
- * 						frequency for low speed conversions will be 50Hz.
- * @note				Only a single sample format is supported - that provided by the GADC driver. That sample
- * 						format applies to both high speed and low speed sampling.
- *
- * @api
- */
-void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency);
-
-#if GFX_USE_GEVENT || defined(__DOXYGEN__)
-	/**
-	 * @brief   			Turn on sending results to the GEVENT sub-system.
-	 * @details				Returns a GSourceHandle to listen for GEVENT_ADC events.
-	 *
-	 * @note				The high speed ADC will not use the GEVENT system unless this is
-	 * 						called first. This saves processing time if the application does
-	 * 						not want to use the GEVENT sub-system for the high speed ADC.
-	 * 						Once turned on it can only be turned off by calling @p gadcHighSpeedInit() again.
-	 * @note				The high speed ADC is capable of signalling via this method, an ISR callback and a
-	 * 						binary semaphore at the same time.
-	 *
-	 * @return				The GSourceHandle
-	 *
-	 * @api
-	 */
-	GSourceHandle gadcHighSpeedGetSource(void);
-#endif
-
-/**
- * @brief				Allow retrieving of results from the high speed ADC using an ISR callback.
- *
- * @param[in] isrfn			The callback function (called in an ISR context).
- *
- * @note				Passing a NULL for isrfn will turn off signalling via this method as will calling
- * 						@p gadcHighSpeedInit().
- * @note				The high speed ADC is capable of signalling via this method, a blocked thread and the GEVENT
- * 						sub-system at the same time.
- *
- * @api
- */
-void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn);
-
-/**
- * @brief		Get a filled buffer from the ADC
- * @return		A GDataBuffer pointer or NULL if the timeout is exceeded
- *
- * @param[in] ms	The maximum amount of time in milliseconds to wait for data if some is not currently available.
- *
- * @note		After processing the data, your application must return the buffer to the free-list so that
- * 				it can be used again. This can be done using @p gfxBufferRelease().
- * @note		A buffer may be returned to the free-list before you have finished processing it provided you finish
- * 				processing it before GADC re-uses it. This is useful when RAM usage is critical to reduce the number
- * 				of buffers required. It works before the free list is a FIFO queue and therefore buffers are kept
- * 				in the queue as long as possible before they are re-used.
- * @note		The function ending with "I" is the interrupt class function.
- * @api
- * @{
- */
-GDataBuffer *gadcHighSpeedGetData(delaytime_t ms);
-GDataBuffer *gadcHighSpeedGetDataI(void);
-/** @} */
-
-/**
- * @brief   Start the high speed ADC conversions.
- * @pre		It must have been initialised first with @p gadcHighSpeedInit()
- *
- * @api
- */
-void gadcHighSpeedStart(void);
-
-/**
- * @brief   Stop the high speed ADC conversions.
- *
- * @api
- */
-void gadcHighSpeedStop(void);
-
-/**
- * @brief	Perform a single low speed ADC conversion
- * @details	Blocks until the conversion is complete
- * @pre		This should not be called from within a GTimer callback as this routine
- * 			blocks until the conversion is ready.
- *
- * @param[in] physdev		A value passed to describe which physical ADC devices/channels to use.
- * @param[in] buffer		The static buffer to put the ADC samples into.
- *
- * @note	This may take a while to complete if the high speed ADC is running as the
- * 			conversion is interleaved with the high speed ADC conversions on a buffer
- * 			completion.
- * @note	The result buffer must be large enough to store one sample per device
- * 			described by the 'physdev' parameter.
- * @note	Specifying more than one device in physdev is possible but discouraged as the
- * 			calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
- * 			from over-running the high speed ADC include high speed device stalling or samples being lost.
- *
- * @api
- */
-void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer);
-
-/**
- * @brief	Perform a low speed ADC conversion with callback (in a thread context)
- * @details	Returns FALSE if internal memory allocation fails
- *
- * @param[in] physdev		A value passed to describe which physical ADC devices/channels to use.
- * @param[in] buffer		The static buffer to put the ADC samples into.
- * @param[in] fn			The callback function to call when the conversion is complete.
- * @param[in] param			A parameter to pass to the callback function.
- *
- * @return					FALSE if no free low speed ADC slots.
- *
- * @note	This may be safely called from within a GTimer callback.
- * @note	The callback may take a while to occur if the high speed ADC is running as the
- * 			conversion is interleaved with the high speed ADC conversions on a buffer
- * 			completion.
- * @note	The result buffer must be large enough to store one sample per device
- * 			described by the 'physdev' parameter.
- * @note	Specifying more than one device in physdev is possible but discouraged as the
- * 			calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
- * 			from over-running the high speed ADC include high speed samples being lost.
- *
- * @api
- */
-bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GADC */
-
-#endif /* _GADC_H */
-/** @} */
diff --git a/src/gadc/sys_make.mk b/src/gadc/sys_make.mk
deleted file mode 100644
index 21a07dbe..00000000
--- a/src/gadc/sys_make.mk
+++ /dev/null
@@ -1 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gadc/gadc_gadc.c
diff --git a/src/gadc/sys_options.h b/src/gadc/sys_options.h
deleted file mode 100644
index d9519c39..00000000
--- a/src/gadc/sys_options.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gadc/sys_options.h
- * @brief   GADC - Periodic ADC subsystem options header file.
- *
- * @addtogroup GADC
- * @{
- */
-
-#ifndef _GADC_OPTIONS_H
-#define _GADC_OPTIONS_H
-
-/**
- * @name    GADC Functionality to be included
- * @{
- */
-/**
- * @}
- *
- * @name    GADC Optional Sizing Parameters
- * @{
- */
-	/**
-	 * @brief   The maximum GADC sample rate
-	 * @details	Defaults to 44000
-	 * @note	This value must be less than half the maximum sample rate allowed by the CPU.
-	 * 			This is to ensure there is time between high speed samples to perform low
-	 * 			speed device sampling.
-	 */
-	#ifndef GADC_MAX_HIGH_SPEED_SAMPLERATE
-		#define GADC_MAX_HIGH_SPEED_SAMPLERATE	44000
-	#endif
-/** @} */
-
-#endif /* _GADC_OPTIONS_H */
-/** @} */
diff --git a/src/gadc/sys_rules.h b/src/gadc/sys_rules.h
deleted file mode 100644
index 363b2434..00000000
--- a/src/gadc/sys_rules.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gadc/sys_rules.h
- * @brief   GADC safety rules header file.
- *
- * @addtogroup GADC
- * @{
- */
-
-#ifndef _GADC_RULES_H
-#define _GADC_RULES_H
-
-#if GFX_USE_GADC
-	#if !GFX_USE_GTIMER
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GADC: GFX_USE_GTIMER is required if GFX_USE_GADC is TRUE. It has been turned on for you."
-		#endif
-		#undef GFX_USE_GTIMER
-		#define	GFX_USE_GTIMER		TRUE
-	#endif
-	#if !GFX_USE_GQUEUE || !GQUEUE_NEED_GSYNC || !GQUEUE_NEED_BUFFERS
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GADC: GFX_USE_GQUEUE, GQUEUE_NEED_BUFFERS and GQUEUE_NEED_GSYNC are required if GFX_USE_GADC is TRUE. They have been turned on for you."
-		#endif
-		#undef GFX_USE_GQUEUE
-		#define	GFX_USE_GQUEUE		TRUE
-		#undef GQUEUE_NEED_BUFFERS
-		#define	GQUEUE_NEED_BUFFERS		TRUE
-		#undef GQUEUE_NEED_GSYNC
-		#define	GQUEUE_NEED_GSYNC		TRUE
-	#endif
-#endif
-
-#endif /* _GADC_RULES_H */
-/** @} */
diff --git a/src/gaudio/driver_play.h b/src/gaudio/driver_play.h
deleted file mode 100644
index 343a0fed..00000000
--- a/src/gaudio/driver_play.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gaudio/driver_play.h
- * @brief   GAUDIO - Audio play driver header file.
- *
- * @defgroup Driver Driver
- * @ingroup GAUDIO
- * @{
- */
-
-#ifndef _GAUDIO_PLAY_LLD_H
-#define _GAUDIO_PLAY_LLD_H
-
-#include "gfx.h"
-
-#if (GFX_USE_GAUDIO && GAUDIO_NEED_PLAY) || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief				Get a block of audio data to play
- * @return				A pointer to the GAaudioData structure or NULL if none is currently available
- *
- * @note				Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
- *
- * @iclass
- * @notapi
- */
-GDataBuffer *gaudioPlayGetDataBlockI(void);
-
-/**
- * @brief				Release a block of audio data to the free list
- *
- * @param[in] paud		The GDataBuffer block to be released.
- *
- * @note				Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
- *
- * @iclass
- * @notapi
- */
-void gaudioPlayReleaseDataBlockI(GDataBuffer *paud);
-
-/**
- * @brief				Signal that all playing has now stopped
- *
- * @note				Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
- *
- * @iclass
- * @notapi
- */
-void gaudioPlayDoneI(void);
-
-/**
- * @brief				Initialise the play driver
- * @return				TRUE if the channel, frequency and format are valid.
- *
- * @param[in] channel	The channel to use (see the driver for the available channels provided)
- * @param[in] frequency	The sample frequency to use
- * @param[in] format	The sample format
- *
- * @note				The driver will always have been stopped and de-init before this is called.
- *
- * @api
- */
-bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
-
-/**
- * @brief				Start the audio output playing
- *
- * @note				This may be called at any stage including while the driver
- * 						is already playing. The driver should check for data blocks
- * 						to play using @p gaudioPlayGetDataBlockI().
- *
- * @api
- */
-void gaudio_play_lld_start(void);
-
-/**
- * @brief				Stop the audio output playing.
- *
- * @note				Some drivers may only stop playing at a data block boundary.
- * @note				It is possible but unlikely for it to be called when playing has already stopped.
- * @note				It should not return until all active buffers (currently in use by the driver)
- * 						have been returned to the free-list and @p gaudioPlayDoneI() has been called.
- *
- * @api
- */
-void gaudio_play_lld_stop(void);
-
-/**
- * @brief				Set the output volume.
- * @return				TRUE if successful.
- *
- * @param[in] vol		0->255 (0 = muted)
- *
- * @note				Some drivers may not support this. They will return FALSE.
- * @note				For stereo devices, both channels are set to the same volume.
- *
- * @api
- */
-bool_t gaudio_play_lld_set_volume(uint8_t vol);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */
-
-#endif /* _GAUDIO_PLAY_LLD_H */
-/** @} */
diff --git a/src/gaudio/driver_record.h b/src/gaudio/driver_record.h
deleted file mode 100644
index 20136dd7..00000000
--- a/src/gaudio/driver_record.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gaudio/driver_record.h
- * @brief   GAUDIO - Audio Recording driver header file.
- *
- * @defgroup Driver Driver
- * @ingroup GAUDIO
- * @{
- */
-
-#ifndef _GAUDIO_RECORD_LLD_H
-#define _GAUDIO_RECORD_LLD_H
-
-#include "gfx.h"
-
-#if (GFX_USE_GAUDIO && GAUDIO_NEED_RECORD) || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-/**
- * @brief				Get a free block of audio data that we can record into
- * @return				A pointer to the GAaudioData structure or NULL if none is currently available
- *
- * @note				Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
- *
- * @iclass
- * @notapi
- */
-#define gaudioRecordGetFreeBlockI()		gfxBufferGetI()
-
-/**
- * @brief				Save a block of recorded audio data ready for the application
- *
- * @param[in] paud		The GDataBuffer block with data.
- *
- * @note				Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
- *
- * @iclass
- * @notapi
- */
-void gaudioRecordSaveDataBlockI(GDataBuffer *paud);
-
-/**
- * @brief				Signal that all recording has now stopped
- *
- * @note				Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
- *
- * @iclass
- * @notapi
- */
-void gaudioRecordDoneI(void);
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief				Initialise the record driver
- * @return				TRUE if the channel, frequency and format are valid.
- *
- * @param[in] channel	The channel to use (see the driver for the available channels provided)
- * @param[in] frequency	The sample frequency to use
- * @param[in] format	The sample format
- *
- * @note				The driver will always have been stopped and de-init before this is called.
- *
- * @api
- */
-bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
-
-/**
- * @brief				Start the audio recording
- *
- * @api
- */
-void gaudio_record_lld_start(void);
-
-/**
- * @brief				Stop the audio recording.
- *
- * @note				Some drivers may only stop recording at a data block boundary.
- * @note				This routine should not return until any currently active buffers have been
- * 						saved (even if with zero length) and @p gaudioRecordDoneI() has been called.
- *
- * @api
- */
-void gaudio_record_lld_stop(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */
-
-#endif /* _GAUDIO_RECORD_LLD_H */
-/** @} */
diff --git a/src/gaudio/gaudio.c b/src/gaudio/gaudio.c
new file mode 100644
index 00000000..0abc9382
--- /dev/null
+++ b/src/gaudio/gaudio.c
@@ -0,0 +1,275 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GAUDIO
+
+#if GAUDIO_NEED_PLAY
+	#include "gaudio_driver_play.h"
+
+	static gfxQueueASync	playList;
+	static gfxSem			playComplete;
+	static uint16_t			playFlags;
+		#define PLAYFLG_USEEVENTS	0x0001
+		#define PLAYFLG_PLAYING		0x0002
+		#define PLAYFLG_ISINIT		0x0004
+	#if GFX_USE_GEVENT
+		static GTimer playTimer;
+		static void PlayTimerCallback(void *param);
+	#endif
+#endif
+
+#if GAUDIO_NEED_RECORD
+	#include "gaudio_driver_record.h"
+
+	static gfxQueueGSync	recordList;
+	static uint16_t			recordFlags;
+		#define RECORDFLG_USEEVENTS		0x0001
+		#define RECORDFLG_RECORDING		0x0002
+		#define RECORDFLG_STALLED		0x0004
+		#define RECORDFLG_ISINIT		0x0008
+	#if GFX_USE_GEVENT
+		static GTimer recordTimer;
+		static void RecordTimerCallback(void *param);
+	#endif
+#endif
+
+
+void _gaudioInit(void)
+{
+	#if GAUDIO_NEED_PLAY
+		gfxQueueASyncInit(&playList);
+		#if GFX_USE_GEVENT
+			gtimerInit(&playTimer);
+		#endif
+		gfxSemInit(&playComplete, 0, 0);
+	#endif
+	#if GAUDIO_NEED_RECORD
+		gfxQueueGSyncInit(&recordList);
+		#if GFX_USE_GEVENT
+			gtimerInit(&recordTimer);
+		#endif
+	#endif
+}
+
+void _gaudioDeinit(void)
+{
+	#if GAUDIO_NEED_PLAY
+		gfxQueueASyncDeinit(&playList);
+		#if GFX_USE_GEVENT
+			gtimerDeinit(&playTimer);
+		#endif
+		gfxSemDestroy(&playComplete);
+	#endif
+	#if GAUDIO_NEED_RECORD
+		gfxQueueGSyncDeinit(&recordList);
+		#if GFX_USE_GEVENT
+			gtimerDeinit(&recordTimer);
+		#endif
+	#endif
+}
+
+#if GAUDIO_NEED_PLAY
+
+	bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
+		gaudioPlayStop();
+		playFlags &= ~PLAYFLG_ISINIT;
+		if (!gaudio_play_lld_init(channel, frequency, format))
+			return FALSE;
+		playFlags |= PLAYFLG_ISINIT;
+		return TRUE;
+	}
+
+	void gaudioPlay(GDataBuffer *pd) {
+		if (!(playFlags & PLAYFLG_ISINIT)) {
+			// Oops - init failed - return it directly to the free-list
+			if (pd) {
+				gfxBufferRelease(pd);
+				gfxYield();				// Make sure we get no endless cpu hogging loops
+			}
+			return;
+		}
+
+		if (pd)
+			gfxQueueASyncPut(&playList, (gfxQueueASyncItem *)pd);
+		playFlags |= PLAYFLG_PLAYING;
+		gaudio_play_lld_start();
+	}
+
+	void gaudioPlayPause(void) {
+		if ((playFlags & (PLAYFLG_ISINIT|PLAYFLG_PLAYING)) == (PLAYFLG_ISINIT|PLAYFLG_PLAYING))
+			gaudio_play_lld_stop();
+	}
+
+	void gaudioPlayStop(void) {
+		GDataBuffer	*pd;
+
+		if (playFlags & PLAYFLG_PLAYING)
+			gaudio_play_lld_stop();
+		while((pd = (GDataBuffer *)gfxQueueASyncGet(&playList)))
+			gfxBufferRelease(pd);
+	}
+
+	bool_t gaudioPlaySetVolume(uint8_t vol) {
+		return gaudio_play_lld_set_volume(vol);
+	}
+
+	bool_t gaudioPlayWait(delaytime_t ms) {
+		if (!(playFlags & PLAYFLG_PLAYING))
+			return TRUE;
+		return gfxSemWait(&playComplete, ms);
+	}
+
+	#if GFX_USE_GEVENT
+		static void PlayTimerCallback(void *param) {
+			(void) param;
+			GSourceListener	*psl;
+			GEventAudioPlay	*pe;
+
+			psl = 0;
+			while ((psl = geventGetSourceListener((GSourceHandle)&playTimer, psl))) {
+				if (!(pe = (GEventAudioPlay *)geventGetEventBuffer(psl))) {
+					// This listener is missing - save this.
+					psl->srcflags |= GAUDIO_PLAY_LOSTEVENT;
+					continue;
+				}
+
+				pe->type = GEVENT_AUDIO_PLAY;
+				pe->flags = psl->srcflags;
+				psl->srcflags = 0;
+				if ((playFlags & PLAYFLG_PLAYING))
+					pe->flags |= GAUDIO_PLAY_PLAYING;
+				if (gfxBufferIsAvailable())
+					pe->flags |= GAUDIO_PLAY_FREEBLOCK;
+				geventSendEvent(psl);
+			}
+		}
+
+		GSourceHandle gaudioPlayGetSource(void) {
+			if (!gtimerIsActive(&playTimer))
+				gtimerStart(&playTimer, PlayTimerCallback, 0, TRUE, TIME_INFINITE);
+			playFlags |= PLAYFLG_USEEVENTS;
+			return (GSourceHandle)&playTimer;
+		}
+	#endif
+
+	/**
+	 * Routines provided for use by drivers.
+	 */
+
+	GDataBuffer *gaudioPlayGetDataBlockI(void) {
+		return (GDataBuffer *)gfxQueueASyncGetI(&playList);
+	}
+
+	void gaudioPlayReleaseDataBlockI(GDataBuffer *pd) {
+		gfxBufferReleaseI(pd);
+		#if GFX_USE_GEVENT
+			if (playFlags & PLAYFLG_USEEVENTS)
+				gtimerJabI(&playTimer);
+		#endif
+	}
+
+	void gaudioPlayDoneI(void) {
+		playFlags &= ~PLAYFLG_PLAYING;
+		#if GFX_USE_GEVENT
+			if (playFlags & PLAYFLG_USEEVENTS)
+				gtimerJabI(&playTimer);
+		#endif
+		gfxSemSignalI(&playComplete);			// This should really be gfxSemSignalAllI(&playComplete);
+	}
+#endif
+
+#if GAUDIO_NEED_RECORD
+	bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
+		gaudioRecordStop();
+		recordFlags &= ~RECORDFLG_ISINIT;
+		if (!gaudio_record_lld_init(channel, frequency, format))
+			return FALSE;
+		recordFlags |= RECORDFLG_ISINIT;
+		return TRUE;
+	}
+
+	void gaudioRecordStart(void) {
+		if (!(recordFlags & RECORDFLG_ISINIT))
+			return;							// Oops - init failed
+
+		recordFlags |= RECORDFLG_RECORDING;
+		recordFlags &= ~RECORDFLG_STALLED;
+		gaudio_record_lld_start();
+	}
+
+	void gaudioRecordStop(void) {
+		GDataBuffer	*pd;
+
+		if ((recordFlags & (RECORDFLG_RECORDING|RECORDFLG_STALLED)) == RECORDFLG_RECORDING)
+			gaudio_record_lld_stop();
+		recordFlags &= ~(RECORDFLG_RECORDING|RECORDFLG_STALLED);
+		while((pd = (GDataBuffer *)gfxQueueGSyncGet(&recordList, TIME_IMMEDIATE)))
+			gfxBufferRelease(pd);
+	}
+
+	GDataBuffer *gaudioRecordGetData(delaytime_t ms) {
+		return (GDataBuffer *)gfxQueueGSyncGet(&recordList, ms);
+	}
+
+	#if GFX_USE_GEVENT
+		static void RecordTimerCallback(void *param) {
+			(void) param;
+			GSourceListener		*psl;
+			GEventAudioRecord	*pe;
+
+			psl = 0;
+			while ((psl = geventGetSourceListener((GSourceHandle)&recordTimer, psl))) {
+				if (!(pe = (GEventAudioRecord *)geventGetEventBuffer(psl))) {
+					// This listener is missing - save this.
+					psl->srcflags |= GAUDIO_RECORD_LOSTEVENT;
+					continue;
+				}
+				pe->type = GEVENT_AUDIO_RECORD;
+				pe->flags = psl->srcflags;
+				psl->srcflags = 0;
+				if ((recordFlags & RECORDFLG_RECORDING))
+					pe->flags |= GAUDIO_RECORD_RECORDING;
+				if ((recordFlags & RECORDFLG_STALLED))
+					pe->flags |= GAUDIO_RECORD_STALL;
+				if (!gfxQueueGSyncIsEmpty(&recordList))
+					pe->flags |= GAUDIO_RECORD_GOTBUFFER;
+				geventSendEvent(psl);
+			}
+		}
+
+		GSourceHandle gaudioRecordGetSource(void) {
+			if (!gtimerIsActive(&recordTimer))
+				gtimerStart(&recordTimer, RecordTimerCallback, 0, TRUE, TIME_INFINITE);
+			recordFlags |= RECORDFLG_USEEVENTS;
+			return (GSourceHandle)&recordTimer;
+		}
+	#endif
+
+	/**
+	 * Routines provided for use by drivers.
+	 */
+
+	void gaudioRecordSaveDataBlockI(GDataBuffer *paud) {
+		gfxQueueGSyncPutI(&recordList, (gfxQueueGSyncItem *)paud);
+		#if GFX_USE_GEVENT
+			if (recordFlags & RECORDFLG_USEEVENTS)
+				gtimerJabI(&recordTimer);
+		#endif
+	}
+
+	void gaudioRecordDoneI(void) {
+		recordFlags |= RECORDFLG_STALLED;
+		#if GFX_USE_GEVENT
+			if (recordFlags & RECORDFLG_USEEVENTS)
+				gtimerJabI(&recordTimer);
+		#endif
+	}
+#endif
+
+#endif /* GFX_USE_GAUDIO */
diff --git a/src/gaudio/gaudio.h b/src/gaudio/gaudio.h
new file mode 100644
index 00000000..23403b15
--- /dev/null
+++ b/src/gaudio/gaudio.h
@@ -0,0 +1,297 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gaudio/gaudio.h
+ *
+ * @addtogroup GAUDIO
+ *
+ * @brief	Module to handle audio recording and play-back
+ *
+ * @{
+ */
+
+#ifndef _GAUDIO_H
+#define _GAUDIO_H
+
+#include "gfx.h"
+
+#if GFX_USE_GAUDIO || defined(__DOXYGEN__)
+
+/* Include the driver defines */
+#if GAUDIO_NEED_PLAY
+	#include "gaudio_play_config.h"
+#endif
+#if GAUDIO_NEED_RECORD
+	#include "gaudio_record_config.h"
+#endif
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+// Event types for GAUDIO
+#define GEVENT_AUDIO_PLAY			(GEVENT_GAUDIO_FIRST+0)
+#define GEVENT_AUDIO_RECORD			(GEVENT_GAUDIO_FIRST+1)
+
+#if GFX_USE_GEVENT || defined(__DOXYGEN__)
+	/**
+	 * @brief   The Audio play event structure.
+	 * @{
+	 */
+	typedef struct GEventAudioPlay_t {
+		/**
+		 * @brief The type of this event (GEVENT_AUDIO_PLAY)
+		 */
+		GEventType				type;
+		/**
+		 * @brief The event flags
+		 */
+		uint16_t				flags;
+			/**
+			 * @brief   The event flag values.
+			 * @{
+			 */
+			#define	GAUDIO_PLAY_LOSTEVENT		0x0001		/**< @brief The last GEVENT_AUDIO_PLAY event was lost */
+			#define	GAUDIO_PLAY_PLAYING			0x0002		/**< @brief The audio out system is currently playing */
+			#define	GAUDIO_PLAY_FREEBLOCK		0x0004		/**< @brief An audio buffer has been freed */
+			/** @} */
+	} GEventAudioPlay;
+	/** @} */
+
+	/**
+	 * @brief   The Audio record event structure.
+	 * @{
+	 */
+	typedef struct GEventAudioRecord_t {
+		/**
+		 * @brief The type of this event (GEVENT_AUDIO_RECORD)
+		 */
+		GEventType				type;
+		/**
+		 * @brief The event flags
+		 */
+		uint16_t				flags;
+			/**
+			 * @brief   The event flag values.
+			 * @{
+			 */
+			#define	GAUDIO_RECORD_LOSTEVENT		0x0001		/**< @brief The last GEVENT_AUDIO_IN event was lost */
+			#define	GAUDIO_RECORD_RECORDING		0x0002		/**< @brief The audio recording system is currently recording */
+			#define	GAUDIO_RECORD_GOTBUFFER		0x0004		/**< @brief An audio buffer is ready for processing */
+			#define	GAUDIO_RECORD_STALL			0x0008		/**< @brief The recording process has stalled due to no free buffers */
+			/** @} */
+	} GEventAudioRecord;
+	/** @} */
+#endif
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if GAUDIO_NEED_PLAY || defined(__DOXYGEN__)
+	/**
+	 * @brief		Set the audio device to play on the specified channel and with the specified
+	 * 				sample frequency.
+	 * @return		TRUE is successful, FALSE if the driver doesn't accept those parameters.
+	 *
+	 * @param[in] channel	The audio output channel to use. Can be set from 0 to GAUDIO_PLAY_NUM_CHANNELS - 1
+	 * @param[in] frequency	The audio sample rate in samples per second
+	 * @param[in] format	The audio sample format
+	 *
+	 * @note		Some channels are mono, and some are stereo. See your driver config file
+	 * 				to determine which channels to use and whether they are stereo or not.
+	 * @note		Only one channel can be playing at a time. Calling this will stop any
+	 * 				currently playing channel.
+	 *
+	 * @api
+	 */
+	bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
+
+	/**
+	 * @brief		Play the specified sample data.
+	 * @details		The sample data is output to the audio channel. On completion the buffer is returned to the free-list.
+	 * @pre			@p gaudioPlayInit must have been called first to set the channel and sample frequency.
+	 *
+	 * @param[in] paud	The audio sample buffer to play. It can be NULL (used to restart paused audio)
+	 *
+	 * @note		Calling this will cancel any pause.
+	 * @note		Before calling this function the len field of the GDataBuffer structure must be
+	 * 				specified (in bytes).
+	 * @note		For stereo channels the sample data is interleaved in the buffer.
+	 * @note		This call returns before the data has completed playing. Subject to available buffers (which
+	 * 				can be obtained from the free-list), any number of buffers may be played. They will be queued
+	 * 				for playing in the order they are supplied to this routine and played when previous buffers are
+	 * 				complete. In this way continuous playing can be obtained without audio gaps.
+	 *
+	 * @api
+	 */
+	void gaudioPlay(GDataBuffer *paud);
+
+	/**
+	 * @brief		Pause any currently playing sounds.
+	 *
+	 * @note		If nothing is currently playing this routine does nothing. To restart playing call @p gaudioPlay()
+	 * 				with or without a new sample buffer.
+	 * @note		Some drivers will not respond until a buffer boundary.
+	 *
+	 * @api
+	 */
+	void gaudioPlayPause(void);
+
+	/**
+	 * @brief		Stop any currently playing sounds.
+	 *
+	 * @note		This stops any playing sounds and returns any currently queued buffers back to the free-list.
+	 * @note		Some drivers will not respond until a buffer boundary.
+	 *
+	 * @api
+	 */
+	void gaudioPlayStop(void);
+
+	/**
+	 * @brief				Set the output volume.
+	 * @return				TRUE if successful.
+	 *
+	 * @param[in] vol		0->255 (0 = muted)
+	 *
+	 * @note				Some drivers may not support this. They will return FALSE.
+	 * @note				For stereo devices, both channels are set to the same volume.
+	 *
+	 * @api
+	 */
+	bool_t gaudioPlaySetVolume(uint8_t vol);
+
+	#if GFX_USE_GEVENT || defined(__DOXYGEN__)
+		/**
+		 * @brief   			Turn on sending results to the GEVENT sub-system.
+		 * @details				Returns a GSourceHandle to listen for GEVENT_AUDIO_OUT events.
+		 *
+		 * @note				The audio output will not use the GEVENT system unless this is
+		 * 						called first. This saves processing time if the application does
+		 * 						not want to use the GEVENT sub-system for audio output.
+		 * 						Once turned on it can only be turned off by calling @p gaudioPlayInit() again.
+		 * @note				The audio output is capable of signaling via this method and other methods
+		 * 						at the same time.
+		 *
+		 * @return				The GSourceHandle
+		 *
+		 * @api
+		 */
+		GSourceHandle gaudioPlayGetSource(void);
+	#endif
+
+	/**
+	 * @brief		Wait for any currently playing sounds to complete
+	 * @return		TRUE if there is now nothing playing or FALSE if the timeout is exceeded
+	 *
+	 * @param[in] ms	The maximum amount of time in milliseconds to wait for playing to complete.
+	 *
+	 * @api
+	 */
+	bool_t gaudioPlayWait(delaytime_t ms);
+#endif
+
+#if GAUDIO_NEED_RECORD || defined(__DOXYGEN__)
+	/**
+	 * @brief		Initialise (but not start) the Audio Recording sub-system.
+	 * @details		Returns FALSE for an invalid channel or other invalid parameter.
+	 *
+	 * @param[in] channel		The channel to convert. Can be set from 0 to GAUDIO_RECORD_NUM_CHANNELS - 1
+	 * @param[in] frequency		The sample frequency
+	 * @param[in] format		The audio sample format requested
+	 *
+	 * @note				Only one channel is active at a time. If an audio input is running it will be stopped.
+	 * 						The Event subsystem is disconnected from the audio subsystem and any binary semaphore
+	 * 						event is forgotten.
+	 * @note				Some channels may be stereo channels which return twice as much sample data with
+	 * 						the left and right channel data interleaved. Other channels may be mono channels.
+	 * 						Where stereo channels exist the low level driver may also
+	 * 						offer the left and right channels separately.
+	 * @note				Due to a bug in Chibi-OS each buffer on the free-list must contain an even number of
+	 * 						samples and for stereo devices it must hold a number of samples that is evenly divisible by 4.
+	 * 						This requirement applies only to ChibiOS where the audio driver uses
+	 * 						a ChibiOS hal driver like the cpu ADC driver. This applies even it is used indirectly via
+	 * 						the uGFX GADC driver.
+	 * @note				The number of samples for stereo devices will be double the number of conversions.
+	 * 						Make sure you allocate your buffers large enough. Each channel is then interleaved
+	 * 						into the provided buffer.
+	 *
+	 * @return				FALSE if invalid channel or parameter
+	 *
+	 * @api
+	 */
+	bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
+
+	/**
+	 * @brief   Start the audio recording.
+	 * @pre		It must have been initialised first with @p gaudioRecordInit()
+	 *
+	 * @api
+	 */
+	void gaudioRecordStart(void);
+
+	/**
+	 * @brief   Stop the audio recording.
+	 *
+	 * @note	All audio recording data that has not yet been retrieved is automatically
+	 * 			returned to the free-list.
+	 * @api
+	 */
+	void gaudioRecordStop(void);
+
+	/**
+	 * @brief		Get a filled audio buffer from the recording list
+	 * @return		A GDataBuffer pointer or NULL if the timeout is exceeded
+	 *
+	 * @param[in] ms	The maximum amount of time in milliseconds to wait for data if some is not currently available.
+	 *
+	 * @note		After processing the audio data, your application must return the buffer to the free-list so that
+	 * 				it can be used to record more audio into. This can be done via the play list using @p gaudioPlay() or
+	 * 				directly using @p gfxBufferRelease().
+	 * @note		A buffer may be returned to the free-list before you have finished processing it provided you finish
+	 * 				processing it before GADC re-uses it. This is useful when RAM usage is critical to reduce the number
+	 * 				of buffers required. It works before the free list is a FIFO queue and therefore buffers are kept
+	 * 				in the queue as long as possible before they are re-used.
+	 *
+	 * @api
+	 */
+	GDataBuffer *gaudioRecordGetData(delaytime_t ms);
+
+	#if GFX_USE_GEVENT || defined(__DOXYGEN__)
+		/**
+		 * @brief   			Turn on sending results to the GEVENT sub-system.
+		 * @details				Returns a GSourceHandle to listen for GEVENT_AUDIO_RECORD events.
+		 *
+		 * @note				Audio recording will not use the GEVENT system unless this is
+		 * 						called first. This saves processing time if the application does
+		 * 						not want to use the GEVENT sub-system for audio recording.
+		 * 						Once turned on it can only be turned off by calling @p gaudioRecordInit() again.
+		 * @note				The audio input is capable of signaling via this and other methods
+		 * 						at the same time.
+		 *
+		 * @return				The GSourceHandle
+		 *
+		 * @api
+		 */
+		GSourceHandle gaudioRecordGetSource(void);
+	#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GAUDIO */
+
+#endif /* _GAUDIO_H */
+/** @} */
+
diff --git a/src/gaudio/gaudio.mk b/src/gaudio/gaudio.mk
new file mode 100644
index 00000000..438892c0
--- /dev/null
+++ b/src/gaudio/gaudio.mk
@@ -0,0 +1 @@
+GFXSRC +=   $(GFXLIB)/src/gaudio/gaudio.c
diff --git a/src/gaudio/gaudio_driver_play.h b/src/gaudio/gaudio_driver_play.h
new file mode 100644
index 00000000..fced1210
--- /dev/null
+++ b/src/gaudio/gaudio_driver_play.h
@@ -0,0 +1,126 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gaudio/gaudio_driver_play.h
+ * @brief   GAUDIO - Audio play driver header file.
+ *
+ * @defgroup Driver Driver
+ * @ingroup GAUDIO
+ * @{
+ */
+
+#ifndef _GAUDIO_PLAY_LLD_H
+#define _GAUDIO_PLAY_LLD_H
+
+#include "gfx.h"
+
+#if (GFX_USE_GAUDIO && GAUDIO_NEED_PLAY) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief				Get a block of audio data to play
+ * @return				A pointer to the GAaudioData structure or NULL if none is currently available
+ *
+ * @note				Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+GDataBuffer *gaudioPlayGetDataBlockI(void);
+
+/**
+ * @brief				Release a block of audio data to the free list
+ *
+ * @param[in] paud		The GDataBuffer block to be released.
+ *
+ * @note				Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudioPlayReleaseDataBlockI(GDataBuffer *paud);
+
+/**
+ * @brief				Signal that all playing has now stopped
+ *
+ * @note				Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudioPlayDoneI(void);
+
+/**
+ * @brief				Initialise the play driver
+ * @return				TRUE if the channel, frequency and format are valid.
+ *
+ * @param[in] channel	The channel to use (see the driver for the available channels provided)
+ * @param[in] frequency	The sample frequency to use
+ * @param[in] format	The sample format
+ *
+ * @note				The driver will always have been stopped and de-init before this is called.
+ *
+ * @api
+ */
+bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
+
+/**
+ * @brief				Start the audio output playing
+ *
+ * @note				This may be called at any stage including while the driver
+ * 						is already playing. The driver should check for data blocks
+ * 						to play using @p gaudioPlayGetDataBlockI().
+ *
+ * @api
+ */
+void gaudio_play_lld_start(void);
+
+/**
+ * @brief				Stop the audio output playing.
+ *
+ * @note				Some drivers may only stop playing at a data block boundary.
+ * @note				It is possible but unlikely for it to be called when playing has already stopped.
+ * @note				It should not return until all active buffers (currently in use by the driver)
+ * 						have been returned to the free-list and @p gaudioPlayDoneI() has been called.
+ *
+ * @api
+ */
+void gaudio_play_lld_stop(void);
+
+/**
+ * @brief				Set the output volume.
+ * @return				TRUE if successful.
+ *
+ * @param[in] vol		0->255 (0 = muted)
+ *
+ * @note				Some drivers may not support this. They will return FALSE.
+ * @note				For stereo devices, both channels are set to the same volume.
+ *
+ * @api
+ */
+bool_t gaudio_play_lld_set_volume(uint8_t vol);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */
+
+#endif /* _GAUDIO_PLAY_LLD_H */
+/** @} */
diff --git a/src/gaudio/gaudio_driver_record.h b/src/gaudio/gaudio_driver_record.h
new file mode 100644
index 00000000..280be5d1
--- /dev/null
+++ b/src/gaudio/gaudio_driver_record.h
@@ -0,0 +1,108 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gaudio/gaudio_driver_record.h
+ * @brief   GAUDIO - Audio Recording driver header file.
+ *
+ * @defgroup Driver Driver
+ * @ingroup GAUDIO
+ * @{
+ */
+
+#ifndef _GAUDIO_RECORD_LLD_H
+#define _GAUDIO_RECORD_LLD_H
+
+#include "gfx.h"
+
+#if (GFX_USE_GAUDIO && GAUDIO_NEED_RECORD) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+/**
+ * @brief				Get a free block of audio data that we can record into
+ * @return				A pointer to the GAaudioData structure or NULL if none is currently available
+ *
+ * @note				Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+#define gaudioRecordGetFreeBlockI()		gfxBufferGetI()
+
+/**
+ * @brief				Save a block of recorded audio data ready for the application
+ *
+ * @param[in] paud		The GDataBuffer block with data.
+ *
+ * @note				Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudioRecordSaveDataBlockI(GDataBuffer *paud);
+
+/**
+ * @brief				Signal that all recording has now stopped
+ *
+ * @note				Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
+ *
+ * @iclass
+ * @notapi
+ */
+void gaudioRecordDoneI(void);
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief				Initialise the record driver
+ * @return				TRUE if the channel, frequency and format are valid.
+ *
+ * @param[in] channel	The channel to use (see the driver for the available channels provided)
+ * @param[in] frequency	The sample frequency to use
+ * @param[in] format	The sample format
+ *
+ * @note				The driver will always have been stopped and de-init before this is called.
+ *
+ * @api
+ */
+bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
+
+/**
+ * @brief				Start the audio recording
+ *
+ * @api
+ */
+void gaudio_record_lld_start(void);
+
+/**
+ * @brief				Stop the audio recording.
+ *
+ * @note				Some drivers may only stop recording at a data block boundary.
+ * @note				This routine should not return until any currently active buffers have been
+ * 						saved (even if with zero length) and @p gaudioRecordDoneI() has been called.
+ *
+ * @api
+ */
+void gaudio_record_lld_stop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */
+
+#endif /* _GAUDIO_RECORD_LLD_H */
+/** @} */
diff --git a/src/gaudio/gaudio_gaudio.c b/src/gaudio/gaudio_gaudio.c
deleted file mode 100644
index bb12e6d2..00000000
--- a/src/gaudio/gaudio_gaudio.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gaudio/gaudio_gaudio.c
- * @brief   GAUDIO sub-system code.
- *
- * @addtogroup GAUDIO
- * @{
- */
-#include "gfx.h"
-
-#if GFX_USE_GAUDIO
-
-#if GAUDIO_NEED_PLAY
-	#include "driver_play.h"
-
-	static gfxQueueASync	playList;
-	static gfxSem			playComplete;
-	static uint16_t			playFlags;
-		#define PLAYFLG_USEEVENTS	0x0001
-		#define PLAYFLG_PLAYING		0x0002
-		#define PLAYFLG_ISINIT		0x0004
-	#if GFX_USE_GEVENT
-		static GTimer playTimer;
-		static void PlayTimerCallback(void *param);
-	#endif
-#endif
-
-#if GAUDIO_NEED_RECORD
-	#include "driver_record.h"
-
-	static gfxQueueGSync	recordList;
-	static uint16_t			recordFlags;
-		#define RECORDFLG_USEEVENTS		0x0001
-		#define RECORDFLG_RECORDING		0x0002
-		#define RECORDFLG_STALLED		0x0004
-		#define RECORDFLG_ISINIT		0x0008
-	#if GFX_USE_GEVENT
-		static GTimer recordTimer;
-		static void RecordTimerCallback(void *param);
-	#endif
-#endif
-
-
-void _gaudioInit(void)
-{
-	#if GAUDIO_NEED_PLAY
-		gfxQueueASyncInit(&playList);
-		#if GFX_USE_GEVENT
-			gtimerInit(&playTimer);
-		#endif
-		gfxSemInit(&playComplete, 0, 0);
-	#endif
-	#if GAUDIO_NEED_RECORD
-		gfxQueueGSyncInit(&recordList);
-		#if GFX_USE_GEVENT
-			gtimerInit(&recordTimer);
-		#endif
-	#endif
-}
-
-void _gaudioDeinit(void)
-{
-	#if GAUDIO_NEED_PLAY
-		gfxQueueASyncDeinit(&playList);
-		#if GFX_USE_GEVENT
-			gtimerDeinit(&playTimer);
-		#endif
-		gfxSemDestroy(&playComplete);
-	#endif
-	#if GAUDIO_NEED_RECORD
-		gfxQueueGSyncDeinit(&recordList);
-		#if GFX_USE_GEVENT
-			gtimerDeinit(&recordTimer);
-		#endif
-	#endif
-}
-
-#if GAUDIO_NEED_PLAY
-
-	bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
-		gaudioPlayStop();
-		playFlags &= ~PLAYFLG_ISINIT;
-		if (!gaudio_play_lld_init(channel, frequency, format))
-			return FALSE;
-		playFlags |= PLAYFLG_ISINIT;
-		return TRUE;
-	}
-
-	void gaudioPlay(GDataBuffer *pd) {
-		if (!(playFlags & PLAYFLG_ISINIT)) {
-			// Oops - init failed - return it directly to the free-list
-			if (pd) {
-				gfxBufferRelease(pd);
-				gfxYield();				// Make sure we get no endless cpu hogging loops
-			}
-			return;
-		}
-
-		if (pd)
-			gfxQueueASyncPut(&playList, (gfxQueueASyncItem *)pd);
-		playFlags |= PLAYFLG_PLAYING;
-		gaudio_play_lld_start();
-	}
-
-	void gaudioPlayPause(void) {
-		if ((playFlags & (PLAYFLG_ISINIT|PLAYFLG_PLAYING)) == (PLAYFLG_ISINIT|PLAYFLG_PLAYING))
-			gaudio_play_lld_stop();
-	}
-
-	void gaudioPlayStop(void) {
-		GDataBuffer	*pd;
-
-		if (playFlags & PLAYFLG_PLAYING)
-			gaudio_play_lld_stop();
-		while((pd = (GDataBuffer *)gfxQueueASyncGet(&playList)))
-			gfxBufferRelease(pd);
-	}
-
-	bool_t gaudioPlaySetVolume(uint8_t vol) {
-		return gaudio_play_lld_set_volume(vol);
-	}
-
-	bool_t gaudioPlayWait(delaytime_t ms) {
-		if (!(playFlags & PLAYFLG_PLAYING))
-			return TRUE;
-		return gfxSemWait(&playComplete, ms);
-	}
-
-	#if GFX_USE_GEVENT
-		static void PlayTimerCallback(void *param) {
-			(void) param;
-			GSourceListener	*psl;
-			GEventAudioPlay	*pe;
-
-			psl = 0;
-			while ((psl = geventGetSourceListener((GSourceHandle)&playTimer, psl))) {
-				if (!(pe = (GEventAudioPlay *)geventGetEventBuffer(psl))) {
-					// This listener is missing - save this.
-					psl->srcflags |= GAUDIO_PLAY_LOSTEVENT;
-					continue;
-				}
-
-				pe->type = GEVENT_AUDIO_PLAY;
-				pe->flags = psl->srcflags;
-				psl->srcflags = 0;
-				if ((playFlags & PLAYFLG_PLAYING))
-					pe->flags |= GAUDIO_PLAY_PLAYING;
-				if (gfxBufferIsAvailable())
-					pe->flags |= GAUDIO_PLAY_FREEBLOCK;
-				geventSendEvent(psl);
-			}
-		}
-
-		GSourceHandle gaudioPlayGetSource(void) {
-			if (!gtimerIsActive(&playTimer))
-				gtimerStart(&playTimer, PlayTimerCallback, 0, TRUE, TIME_INFINITE);
-			playFlags |= PLAYFLG_USEEVENTS;
-			return (GSourceHandle)&playTimer;
-		}
-	#endif
-
-	/**
-	 * Routines provided for use by drivers.
-	 */
-
-	GDataBuffer *gaudioPlayGetDataBlockI(void) {
-		return (GDataBuffer *)gfxQueueASyncGetI(&playList);
-	}
-
-	void gaudioPlayReleaseDataBlockI(GDataBuffer *pd) {
-		gfxBufferReleaseI(pd);
-		#if GFX_USE_GEVENT
-			if (playFlags & PLAYFLG_USEEVENTS)
-				gtimerJabI(&playTimer);
-		#endif
-	}
-
-	void gaudioPlayDoneI(void) {
-		playFlags &= ~PLAYFLG_PLAYING;
-		#if GFX_USE_GEVENT
-			if (playFlags & PLAYFLG_USEEVENTS)
-				gtimerJabI(&playTimer);
-		#endif
-		gfxSemSignalI(&playComplete);			// This should really be gfxSemSignalAllI(&playComplete);
-	}
-#endif
-
-#if GAUDIO_NEED_RECORD
-	bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
-		gaudioRecordStop();
-		recordFlags &= ~RECORDFLG_ISINIT;
-		if (!gaudio_record_lld_init(channel, frequency, format))
-			return FALSE;
-		recordFlags |= RECORDFLG_ISINIT;
-		return TRUE;
-	}
-
-	void gaudioRecordStart(void) {
-		if (!(recordFlags & RECORDFLG_ISINIT))
-			return;							// Oops - init failed
-
-		recordFlags |= RECORDFLG_RECORDING;
-		recordFlags &= ~RECORDFLG_STALLED;
-		gaudio_record_lld_start();
-	}
-
-	void gaudioRecordStop(void) {
-		GDataBuffer	*pd;
-
-		if ((recordFlags & (RECORDFLG_RECORDING|RECORDFLG_STALLED)) == RECORDFLG_RECORDING)
-			gaudio_record_lld_stop();
-		recordFlags &= ~(RECORDFLG_RECORDING|RECORDFLG_STALLED);
-		while((pd = (GDataBuffer *)gfxQueueGSyncGet(&recordList, TIME_IMMEDIATE)))
-			gfxBufferRelease(pd);
-	}
-
-	GDataBuffer *gaudioRecordGetData(delaytime_t ms) {
-		return (GDataBuffer *)gfxQueueGSyncGet(&recordList, ms);
-	}
-
-	#if GFX_USE_GEVENT
-		static void RecordTimerCallback(void *param) {
-			(void) param;
-			GSourceListener		*psl;
-			GEventAudioRecord	*pe;
-
-			psl = 0;
-			while ((psl = geventGetSourceListener((GSourceHandle)&recordTimer, psl))) {
-				if (!(pe = (GEventAudioRecord *)geventGetEventBuffer(psl))) {
-					// This listener is missing - save this.
-					psl->srcflags |= GAUDIO_RECORD_LOSTEVENT;
-					continue;
-				}
-				pe->type = GEVENT_AUDIO_RECORD;
-				pe->flags = psl->srcflags;
-				psl->srcflags = 0;
-				if ((recordFlags & RECORDFLG_RECORDING))
-					pe->flags |= GAUDIO_RECORD_RECORDING;
-				if ((recordFlags & RECORDFLG_STALLED))
-					pe->flags |= GAUDIO_RECORD_STALL;
-				if (!gfxQueueGSyncIsEmpty(&recordList))
-					pe->flags |= GAUDIO_RECORD_GOTBUFFER;
-				geventSendEvent(psl);
-			}
-		}
-
-		GSourceHandle gaudioRecordGetSource(void) {
-			if (!gtimerIsActive(&recordTimer))
-				gtimerStart(&recordTimer, RecordTimerCallback, 0, TRUE, TIME_INFINITE);
-			recordFlags |= RECORDFLG_USEEVENTS;
-			return (GSourceHandle)&recordTimer;
-		}
-	#endif
-
-	/**
-	 * Routines provided for use by drivers.
-	 */
-
-	void gaudioRecordSaveDataBlockI(GDataBuffer *paud) {
-		gfxQueueGSyncPutI(&recordList, (gfxQueueGSyncItem *)paud);
-		#if GFX_USE_GEVENT
-			if (recordFlags & RECORDFLG_USEEVENTS)
-				gtimerJabI(&recordTimer);
-		#endif
-	}
-
-	void gaudioRecordDoneI(void) {
-		recordFlags |= RECORDFLG_STALLED;
-		#if GFX_USE_GEVENT
-			if (recordFlags & RECORDFLG_USEEVENTS)
-				gtimerJabI(&recordTimer);
-		#endif
-	}
-#endif
-
-#endif /* GFX_USE_GAUDIO */
-/** @} */
diff --git a/src/gaudio/gaudio_options.h b/src/gaudio/gaudio_options.h
new file mode 100644
index 00000000..d6dfb105
--- /dev/null
+++ b/src/gaudio/gaudio_options.h
@@ -0,0 +1,44 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gaudio/gaudio_options.h
+ * @brief   GAUDIO - Audio subsystem options header file.
+ *
+ * @addtogroup GAUDIO
+ * @{
+ */
+
+#ifndef _GAUDIO_OPTIONS_H
+#define _GAUDIO_OPTIONS_H
+
+/**
+ * @name    GAUDIO Functionality to be included
+ * @{
+ */
+	/**
+	 * @brief	Audio Play capability is needed
+	 */
+	#ifndef GAUDIO_NEED_PLAY
+		#define GAUDIO_NEED_PLAY			FALSE
+	#endif
+	/**
+	 * @brief	Audio Recording capability is needed
+	 */
+	#ifndef GAUDIO_NEED_RECORD
+		#define GAUDIO_NEED_RECORD			FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GAUDIO Optional Sizing Parameters
+ * @{
+ */
+/** @} */
+
+#endif /* _GAUDIO_OPTIONS_H */
+/** @} */
diff --git a/src/gaudio/gaudio_rules.h b/src/gaudio/gaudio_rules.h
new file mode 100644
index 00000000..2dbad17d
--- /dev/null
+++ b/src/gaudio/gaudio_rules.h
@@ -0,0 +1,56 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gaudio/gaudio_rules.h
+ * @brief   GAUDIO safety rules header file.
+ *
+ * @addtogroup GAUDIO
+ * @{
+ */
+
+#ifndef _GAUDIO_RULES_H
+#define _GAUDIO_RULES_H
+
+#if GFX_USE_GAUDIO
+	#if !GAUDIO_NEED_PLAY && !GAUDIO_NEED_RECORD
+		#error "GAUDIO: GAUDIO_NEED_PLAY and/or GAUDIO_NEED_RECORD is required if GFX_USE_GAUDIO is TRUE"
+	#endif
+	#if !GFX_USE_GQUEUE
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GAUDIO: GFX_USE_GQUEUE is required if GFX_USE_GAUDIO is TRUE. It has been turned on for you."
+		#endif
+		#undef GFX_USE_GQUEUE
+		#define	GFX_USE_GQUEUE		TRUE
+	#endif
+	#if GAUDIO_NEED_PLAY && !GQUEUE_NEED_ASYNC
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GAUDIO: GQUEUE_NEED_ASYNC is required if GAUDIO_NEED_PLAY is TRUE. It has been turned on for you."
+		#endif
+		#undef GQUEUE_NEED_ASYNC
+		#define	GQUEUE_NEED_ASYNC		TRUE
+	#endif
+	#if !GQUEUE_NEED_GSYNC || !GQUEUE_NEED_BUFFERS
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GAUDIO: GQUEUE_NEED_BUFFERS and GQUEUE_NEED_GSYNC are required if GFX_USE_GAUDIO is TRUE. They have been turned on for you."
+		#endif
+		#undef GQUEUE_NEED_BUFFERS
+		#define	GQUEUE_NEED_BUFFERS		TRUE
+		#undef GQUEUE_NEED_GSYNC
+		#define	GQUEUE_NEED_GSYNC		TRUE
+	#endif
+	#if GFX_USE_GEVENT && !GFX_USE_GTIMER
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GAUDIO: GFX_USE_GTIMER is required if GFX_USE_GAUDIO and GFX_USE_GEVENT are TRUE. It has been turned on for you."
+		#endif
+		#undef GFX_USE_GTIMER
+		#define	GFX_USE_GTIMER		TRUE
+	#endif
+#endif
+
+#endif /* _GAUDIO_RULES_H */
+/** @} */
diff --git a/src/gaudio/sys_defs.h b/src/gaudio/sys_defs.h
deleted file mode 100644
index 5a43af18..00000000
--- a/src/gaudio/sys_defs.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gaudio/sys_defs.h
- *
- * @addtogroup GAUDIO
- *
- * @brief	Module to handle audio recording and play-back
- *
- * @{
- */
-
-#ifndef _GAUDIO_H
-#define _GAUDIO_H
-
-#include "gfx.h"
-
-#if GFX_USE_GAUDIO || defined(__DOXYGEN__)
-
-/* Include the driver defines */
-#if GAUDIO_NEED_PLAY
-	#include "gaudio_play_config.h"
-#endif
-#if GAUDIO_NEED_RECORD
-	#include "gaudio_record_config.h"
-#endif
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-// Event types for GAUDIO
-#define GEVENT_AUDIO_PLAY			(GEVENT_GAUDIO_FIRST+0)
-#define GEVENT_AUDIO_RECORD			(GEVENT_GAUDIO_FIRST+1)
-
-#if GFX_USE_GEVENT || defined(__DOXYGEN__)
-	/**
-	 * @brief   The Audio play event structure.
-	 * @{
-	 */
-	typedef struct GEventAudioPlay_t {
-		/**
-		 * @brief The type of this event (GEVENT_AUDIO_PLAY)
-		 */
-		GEventType				type;
-		/**
-		 * @brief The event flags
-		 */
-		uint16_t				flags;
-			/**
-			 * @brief   The event flag values.
-			 * @{
-			 */
-			#define	GAUDIO_PLAY_LOSTEVENT		0x0001		/**< @brief The last GEVENT_AUDIO_PLAY event was lost */
-			#define	GAUDIO_PLAY_PLAYING			0x0002		/**< @brief The audio out system is currently playing */
-			#define	GAUDIO_PLAY_FREEBLOCK		0x0004		/**< @brief An audio buffer has been freed */
-			/** @} */
-	} GEventAudioPlay;
-	/** @} */
-
-	/**
-	 * @brief   The Audio record event structure.
-	 * @{
-	 */
-	typedef struct GEventAudioRecord_t {
-		/**
-		 * @brief The type of this event (GEVENT_AUDIO_RECORD)
-		 */
-		GEventType				type;
-		/**
-		 * @brief The event flags
-		 */
-		uint16_t				flags;
-			/**
-			 * @brief   The event flag values.
-			 * @{
-			 */
-			#define	GAUDIO_RECORD_LOSTEVENT		0x0001		/**< @brief The last GEVENT_AUDIO_IN event was lost */
-			#define	GAUDIO_RECORD_RECORDING		0x0002		/**< @brief The audio recording system is currently recording */
-			#define	GAUDIO_RECORD_GOTBUFFER		0x0004		/**< @brief An audio buffer is ready for processing */
-			#define	GAUDIO_RECORD_STALL			0x0008		/**< @brief The recording process has stalled due to no free buffers */
-			/** @} */
-	} GEventAudioRecord;
-	/** @} */
-#endif
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if GAUDIO_NEED_PLAY || defined(__DOXYGEN__)
-	/**
-	 * @brief		Set the audio device to play on the specified channel and with the specified
-	 * 				sample frequency.
-	 * @return		TRUE is successful, FALSE if the driver doesn't accept those parameters.
-	 *
-	 * @param[in] channel	The audio output channel to use. Can be set from 0 to GAUDIO_PLAY_NUM_CHANNELS - 1
-	 * @param[in] frequency	The audio sample rate in samples per second
-	 * @param[in] format	The audio sample format
-	 *
-	 * @note		Some channels are mono, and some are stereo. See your driver config file
-	 * 				to determine which channels to use and whether they are stereo or not.
-	 * @note		Only one channel can be playing at a time. Calling this will stop any
-	 * 				currently playing channel.
-	 *
-	 * @api
-	 */
-	bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
-
-	/**
-	 * @brief		Play the specified sample data.
-	 * @details		The sample data is output to the audio channel. On completion the buffer is returned to the free-list.
-	 * @pre			@p gaudioPlayInit must have been called first to set the channel and sample frequency.
-	 *
-	 * @param[in] paud	The audio sample buffer to play. It can be NULL (used to restart paused audio)
-	 *
-	 * @note		Calling this will cancel any pause.
-	 * @note		Before calling this function the len field of the GDataBuffer structure must be
-	 * 				specified (in bytes).
-	 * @note		For stereo channels the sample data is interleaved in the buffer.
-	 * @note		This call returns before the data has completed playing. Subject to available buffers (which
-	 * 				can be obtained from the free-list), any number of buffers may be played. They will be queued
-	 * 				for playing in the order they are supplied to this routine and played when previous buffers are
-	 * 				complete. In this way continuous playing can be obtained without audio gaps.
-	 *
-	 * @api
-	 */
-	void gaudioPlay(GDataBuffer *paud);
-
-	/**
-	 * @brief		Pause any currently playing sounds.
-	 *
-	 * @note		If nothing is currently playing this routine does nothing. To restart playing call @p gaudioPlay()
-	 * 				with or without a new sample buffer.
-	 * @note		Some drivers will not respond until a buffer boundary.
-	 *
-	 * @api
-	 */
-	void gaudioPlayPause(void);
-
-	/**
-	 * @brief		Stop any currently playing sounds.
-	 *
-	 * @note		This stops any playing sounds and returns any currently queued buffers back to the free-list.
-	 * @note		Some drivers will not respond until a buffer boundary.
-	 *
-	 * @api
-	 */
-	void gaudioPlayStop(void);
-
-	/**
-	 * @brief				Set the output volume.
-	 * @return				TRUE if successful.
-	 *
-	 * @param[in] vol		0->255 (0 = muted)
-	 *
-	 * @note				Some drivers may not support this. They will return FALSE.
-	 * @note				For stereo devices, both channels are set to the same volume.
-	 *
-	 * @api
-	 */
-	bool_t gaudioPlaySetVolume(uint8_t vol);
-
-	#if GFX_USE_GEVENT || defined(__DOXYGEN__)
-		/**
-		 * @brief   			Turn on sending results to the GEVENT sub-system.
-		 * @details				Returns a GSourceHandle to listen for GEVENT_AUDIO_OUT events.
-		 *
-		 * @note				The audio output will not use the GEVENT system unless this is
-		 * 						called first. This saves processing time if the application does
-		 * 						not want to use the GEVENT sub-system for audio output.
-		 * 						Once turned on it can only be turned off by calling @p gaudioPlayInit() again.
-		 * @note				The audio output is capable of signaling via this method and other methods
-		 * 						at the same time.
-		 *
-		 * @return				The GSourceHandle
-		 *
-		 * @api
-		 */
-		GSourceHandle gaudioPlayGetSource(void);
-	#endif
-
-	/**
-	 * @brief		Wait for any currently playing sounds to complete
-	 * @return		TRUE if there is now nothing playing or FALSE if the timeout is exceeded
-	 *
-	 * @param[in] ms	The maximum amount of time in milliseconds to wait for playing to complete.
-	 *
-	 * @api
-	 */
-	bool_t gaudioPlayWait(delaytime_t ms);
-#endif
-
-#if GAUDIO_NEED_RECORD || defined(__DOXYGEN__)
-	/**
-	 * @brief		Initialise (but not start) the Audio Recording sub-system.
-	 * @details		Returns FALSE for an invalid channel or other invalid parameter.
-	 *
-	 * @param[in] channel		The channel to convert. Can be set from 0 to GAUDIO_RECORD_NUM_CHANNELS - 1
-	 * @param[in] frequency		The sample frequency
-	 * @param[in] format		The audio sample format requested
-	 *
-	 * @note				Only one channel is active at a time. If an audio input is running it will be stopped.
-	 * 						The Event subsystem is disconnected from the audio subsystem and any binary semaphore
-	 * 						event is forgotten.
-	 * @note				Some channels may be stereo channels which return twice as much sample data with
-	 * 						the left and right channel data interleaved. Other channels may be mono channels.
-	 * 						Where stereo channels exist the low level driver may also
-	 * 						offer the left and right channels separately.
-	 * @note				Due to a bug in Chibi-OS each buffer on the free-list must contain an even number of
-	 * 						samples and for stereo devices it must hold a number of samples that is evenly divisible by 4.
-	 * 						This requirement applies only to ChibiOS where the audio driver uses
-	 * 						a ChibiOS hal driver like the cpu ADC driver. This applies even it is used indirectly via
-	 * 						the uGFX GADC driver.
-	 * @note				The number of samples for stereo devices will be double the number of conversions.
-	 * 						Make sure you allocate your buffers large enough. Each channel is then interleaved
-	 * 						into the provided buffer.
-	 *
-	 * @return				FALSE if invalid channel or parameter
-	 *
-	 * @api
-	 */
-	bool_t gaudioRecordInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format);
-
-	/**
-	 * @brief   Start the audio recording.
-	 * @pre		It must have been initialised first with @p gaudioRecordInit()
-	 *
-	 * @api
-	 */
-	void gaudioRecordStart(void);
-
-	/**
-	 * @brief   Stop the audio recording.
-	 *
-	 * @note	All audio recording data that has not yet been retrieved is automatically
-	 * 			returned to the free-list.
-	 * @api
-	 */
-	void gaudioRecordStop(void);
-
-	/**
-	 * @brief		Get a filled audio buffer from the recording list
-	 * @return		A GDataBuffer pointer or NULL if the timeout is exceeded
-	 *
-	 * @param[in] ms	The maximum amount of time in milliseconds to wait for data if some is not currently available.
-	 *
-	 * @note		After processing the audio data, your application must return the buffer to the free-list so that
-	 * 				it can be used to record more audio into. This can be done via the play list using @p gaudioPlay() or
-	 * 				directly using @p gfxBufferRelease().
-	 * @note		A buffer may be returned to the free-list before you have finished processing it provided you finish
-	 * 				processing it before GADC re-uses it. This is useful when RAM usage is critical to reduce the number
-	 * 				of buffers required. It works before the free list is a FIFO queue and therefore buffers are kept
-	 * 				in the queue as long as possible before they are re-used.
-	 *
-	 * @api
-	 */
-	GDataBuffer *gaudioRecordGetData(delaytime_t ms);
-
-	#if GFX_USE_GEVENT || defined(__DOXYGEN__)
-		/**
-		 * @brief   			Turn on sending results to the GEVENT sub-system.
-		 * @details				Returns a GSourceHandle to listen for GEVENT_AUDIO_RECORD events.
-		 *
-		 * @note				Audio recording will not use the GEVENT system unless this is
-		 * 						called first. This saves processing time if the application does
-		 * 						not want to use the GEVENT sub-system for audio recording.
-		 * 						Once turned on it can only be turned off by calling @p gaudioRecordInit() again.
-		 * @note				The audio input is capable of signaling via this and other methods
-		 * 						at the same time.
-		 *
-		 * @return				The GSourceHandle
-		 *
-		 * @api
-		 */
-		GSourceHandle gaudioRecordGetSource(void);
-	#endif
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GAUDIO */
-
-#endif /* _GAUDIO_H */
-/** @} */
-
diff --git a/src/gaudio/sys_make.mk b/src/gaudio/sys_make.mk
deleted file mode 100644
index ea02e010..00000000
--- a/src/gaudio/sys_make.mk
+++ /dev/null
@@ -1 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gaudio/gaudio_gaudio.c
diff --git a/src/gaudio/sys_options.h b/src/gaudio/sys_options.h
deleted file mode 100644
index eb903424..00000000
--- a/src/gaudio/sys_options.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gaudio/sys_options.h
- * @brief   GAUDIO - Audio subsystem options header file.
- *
- * @addtogroup GAUDIO
- * @{
- */
-
-#ifndef _GAUDIO_OPTIONS_H
-#define _GAUDIO_OPTIONS_H
-
-/**
- * @name    GAUDIO Functionality to be included
- * @{
- */
-	/**
-	 * @brief	Audio Play capability is needed
-	 */
-	#ifndef GAUDIO_NEED_PLAY
-		#define GAUDIO_NEED_PLAY			FALSE
-	#endif
-	/**
-	 * @brief	Audio Recording capability is needed
-	 */
-	#ifndef GAUDIO_NEED_RECORD
-		#define GAUDIO_NEED_RECORD			FALSE
-	#endif
-/**
- * @}
- *
- * @name    GAUDIO Optional Sizing Parameters
- * @{
- */
-/** @} */
-
-#endif /* _GAUDIO_OPTIONS_H */
-/** @} */
diff --git a/src/gaudio/sys_rules.h b/src/gaudio/sys_rules.h
deleted file mode 100644
index 4786fa5f..00000000
--- a/src/gaudio/sys_rules.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gaudio/sys_rules.h
- * @brief   GAUDIO safety rules header file.
- *
- * @addtogroup GAUDIO
- * @{
- */
-
-#ifndef _GAUDIO_RULES_H
-#define _GAUDIO_RULES_H
-
-#if GFX_USE_GAUDIO
-	#if !GAUDIO_NEED_PLAY && !GAUDIO_NEED_RECORD
-		#error "GAUDIO: GAUDIO_NEED_PLAY and/or GAUDIO_NEED_RECORD is required if GFX_USE_GAUDIO is TRUE"
-	#endif
-	#if !GFX_USE_GQUEUE
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GAUDIO: GFX_USE_GQUEUE is required if GFX_USE_GAUDIO is TRUE. It has been turned on for you."
-		#endif
-		#undef GFX_USE_GQUEUE
-		#define	GFX_USE_GQUEUE		TRUE
-	#endif
-	#if GAUDIO_NEED_PLAY && !GQUEUE_NEED_ASYNC
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GAUDIO: GQUEUE_NEED_ASYNC is required if GAUDIO_NEED_PLAY is TRUE. It has been turned on for you."
-		#endif
-		#undef GQUEUE_NEED_ASYNC
-		#define	GQUEUE_NEED_ASYNC		TRUE
-	#endif
-	#if !GQUEUE_NEED_GSYNC || !GQUEUE_NEED_BUFFERS
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GAUDIO: GQUEUE_NEED_BUFFERS and GQUEUE_NEED_GSYNC are required if GFX_USE_GAUDIO is TRUE. They have been turned on for you."
-		#endif
-		#undef GQUEUE_NEED_BUFFERS
-		#define	GQUEUE_NEED_BUFFERS		TRUE
-		#undef GQUEUE_NEED_GSYNC
-		#define	GQUEUE_NEED_GSYNC		TRUE
-	#endif
-	#if GFX_USE_GEVENT && !GFX_USE_GTIMER
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GAUDIO: GFX_USE_GTIMER is required if GFX_USE_GAUDIO and GFX_USE_GEVENT are TRUE. It has been turned on for you."
-		#endif
-		#undef GFX_USE_GTIMER
-		#define	GFX_USE_GTIMER		TRUE
-	#endif
-#endif
-
-#endif /* _GAUDIO_RULES_H */
-/** @} */
diff --git a/src/gdisp/driver.h b/src/gdisp/driver.h
deleted file mode 100644
index efcb2872..00000000
--- a/src/gdisp/driver.h
+++ /dev/null
@@ -1,1070 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gdisp/driver.h
- * @brief   GDISP Graphic Driver subsystem low level driver header.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#ifndef _GDISP_LLD_H
-#define _GDISP_LLD_H
-
-#if GFX_USE_GDISP
-
-// Include the GDRIVER infrastructure
-#include "src/gdriver/sys_defs.h"
-
-// Are we currently compiling the driver itself?
-#if defined(GDISP_DRIVER_VMT)
-	#define	IN_DRIVER			TRUE
-#else
-	#define	IN_DRIVER			FALSE
-#endif
-
-// Is this a multiple driver situation?
-#if defined(GDISP_DRIVER_LIST)
-	#define IS_MULTIPLE			TRUE
-#else
-	#define IS_MULTIPLE			FALSE
-#endif
-
-// Do we need to use VMT calling rather than direct calls to the driver?
-#if IS_MULTIPLE || GDISP_NEED_PIXMAP
-	#define USE_VMT				TRUE
-#else
-	#define USE_VMT				FALSE
-#endif
-
-// Are we in the pixmap virtual driver
-#ifndef IN_PIXMAP_DRIVER
-	#define IN_PIXMAP_DRIVER	FALSE
-#endif
-
-//------------------------------------------------------------------------------------------------------------
-
-// Our special auto-detect hardware code which uses the VMT.
-#define HARDWARE_AUTODETECT		2
-
-#if USE_VMT && !IN_DRIVER
-	// Multiple controllers the default is to hardware detect
-	#define HARDWARE_DEFAULT		HARDWARE_AUTODETECT
-#else
-	// The default is not to include code functions that aren't needed
-	#define HARDWARE_DEFAULT		FALSE
-#endif
-
-//------------------------------------------------------------------------------------------------------------
-
-/**
- * @name    GDISP hardware accelerated support
- * @{
- */
-	/**
-	 * @brief   The display hardware can benefit from being de-initialized when usage is complete.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 * @note	This is most useful for displays such as remote network displays.
-	 */
-	#ifndef GDISP_HARDWARE_DEINIT
-		#define GDISP_HARDWARE_DEINIT		HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   The display hardware can benefit from being flushed.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 * @note	Some controllers ** require ** the application to flush
-	 */
-	#ifndef GDISP_HARDWARE_FLUSH
-		#define GDISP_HARDWARE_FLUSH		HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Hardware streaming writing is supported.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 * @note	Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by each driver
-	 */
-	#ifndef GDISP_HARDWARE_STREAM_WRITE
-		#define GDISP_HARDWARE_STREAM_WRITE		HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Hardware streaming reading of the display surface is supported.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 *
-	 */
-	#ifndef GDISP_HARDWARE_STREAM_READ
-		#define GDISP_HARDWARE_STREAM_READ		HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Hardware supports setting the cursor position within the stream window.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 * @note	This is used to optimise setting of individual pixels within a stream window.
-	 * 			It should therefore not be implemented unless it is cheaper than just setting
-	 * 			a new window.
-	 */
-	#ifndef GDISP_HARDWARE_STREAM_POS
-		#define GDISP_HARDWARE_STREAM_POS		HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated draw pixel.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 * @note	Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver
-	 */
-	#ifndef GDISP_HARDWARE_DRAWPIXEL
-		#define GDISP_HARDWARE_DRAWPIXEL		HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated screen clears.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 * @note	This clears the entire display surface regardless of the clipping area currently set
-	 */
-	#ifndef GDISP_HARDWARE_CLEARS
-		#define GDISP_HARDWARE_CLEARS			HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated rectangular fills.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 */
-	#ifndef GDISP_HARDWARE_FILLS
-		#define GDISP_HARDWARE_FILLS			HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated fills from an image.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 */
-	#ifndef GDISP_HARDWARE_BITFILLS
-		#define GDISP_HARDWARE_BITFILLS			HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Hardware accelerated scrolling.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 */
-	#ifndef GDISP_HARDWARE_SCROLL
-		#define GDISP_HARDWARE_SCROLL			HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   Reading back of pixel values.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 */
-	#ifndef GDISP_HARDWARE_PIXELREAD
-		#define GDISP_HARDWARE_PIXELREAD		HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   The driver supports one or more control commands.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 */
-	#ifndef GDISP_HARDWARE_CONTROL
-		#define GDISP_HARDWARE_CONTROL			HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   The driver supports a non-standard query.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 */
-	#ifndef GDISP_HARDWARE_QUERY
-		#define GDISP_HARDWARE_QUERY			HARDWARE_DEFAULT
-	#endif
-
-	/**
-	 * @brief   The driver supports a clipping in hardware.
-	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
-	 *
-	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
-	 * @note	If this is defined the driver must perform its own clipping on all calls to
-	 * 			the driver and respond appropriately if a parameter is outside the display area.
-	 * @note	If this is not defined then the software ensures that all calls to the
-	 * 			driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION
-	 * 			has been set).
-	 */
-	#ifndef GDISP_HARDWARE_CLIP
-		#define GDISP_HARDWARE_CLIP				HARDWARE_DEFAULT
-	#endif
-/** @} */
-
-//------------------------------------------------------------------------------------------------------------
-
-// For pixmaps certain routines MUST not be FALSE as they are needed for pixmap drawing
-//	Similarly some routines MUST not be TRUE as pixmap's don't provide them.
-#if GDISP_NEED_PIXMAP && !IN_DRIVER
-	#if !GDISP_HARDWARE_DEINIT
-		#undef GDISP_HARDWARE_DEINIT
-		#define GDISP_HARDWARE_DEINIT		HARDWARE_AUTODETECT
-	#endif
-	#if !GDISP_HARDWARE_DRAWPIXEL
-		#undef GDISP_HARDWARE_DRAWPIXEL
-		#define GDISP_HARDWARE_DRAWPIXEL	HARDWARE_AUTODETECT
-	#endif
-	#if !GDISP_HARDWARE_PIXELREAD
-		#undef GDISP_HARDWARE_PIXELREAD
-		#define GDISP_HARDWARE_PIXELREAD	HARDWARE_AUTODETECT
-	#endif
-	#if !GDISP_HARDWARE_CONTROL
-		#undef GDISP_HARDWARE_CONTROL
-		#define GDISP_HARDWARE_CONTROL		HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_FLUSH == TRUE
-		#undef GDISP_HARDWARE_FLUSH
-		#define GDISP_HARDWARE_FLUSH		HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_STREAM_WRITE == TRUE
-		#undef GDISP_HARDWARE_STREAM_WRITE
-		#define GDISP_HARDWARE_STREAM_WRITE	HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_STREAM_READ == TRUE
-		#undef GDISP_HARDWARE_STREAM_READ
-		#define GDISP_HARDWARE_STREAM_READ	HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_CLEARS == TRUE
-		#undef GDISP_HARDWARE_CLEARS
-		#define GDISP_HARDWARE_CLEARS		HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_FILLS == TRUE
-		#undef GDISP_HARDWARE_FILLS
-		#define GDISP_HARDWARE_FILLS		HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_BITFILLS == TRUE
-		#undef GDISP_HARDWARE_BITFILLS
-		#define GDISP_HARDWARE_BITFILLS		HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_SCROLL == TRUE
-		#undef GDISP_HARDWARE_SCROLL
-		#define GDISP_HARDWARE_SCROLL		HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_QUERY == TRUE
-		#undef GDISP_HARDWARE_QUERY
-		#define GDISP_HARDWARE_QUERY		HARDWARE_AUTODETECT
-	#endif
-	#if GDISP_HARDWARE_CLIP == TRUE
-		#undef GDISP_HARDWARE_CLIP
-		#define GDISP_HARDWARE_CLIP			HARDWARE_AUTODETECT
-	#endif
-#endif
-
-//------------------------------------------------------------------------------------------------------------
-
-/* Verify information for packed pixels and define a non-packed pixel macro */
-#if !GDISP_PACKED_PIXELS
-	#define gdispPackPixels(buf,cx,x,y,c)	{ ((color_t *)(buf))[(y)*(cx)+(x)] = (c); }
-#elif !GDISP_HARDWARE_BITFILLS
-	#error "GDISP: packed pixel formats are only supported for hardware accelerated drivers."
-#elif GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 \
-		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB444 \
-		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB666 \
-		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_CUSTOM
-	#error "GDISP: A packed pixel format has been specified for an unsupported pixel format."
-#endif
-
-/* Support routine for packed pixel formats */
-#if !defined(gdispPackPixels) || defined(__DOXYGEN__)
-	/**
-	 * @brief   Pack a pixel into a pixel buffer.
-	 * @note    This function performs no buffer boundary checking
-	 *			regardless of whether GDISP_NEED_CLIP has been specified.
-	 *
-	 * @param[in] buf		The buffer to put the pixel in
-	 * @param[in] cx		The width of a pixel line
-	 * @param[in] x, y		The location of the pixel to place
-	 * @param[in] color		The color to put into the buffer
-	 *
-	 * @api
-	 */
-	void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color);
-#endif
-
-//------------------------------------------------------------------------------------------------------------
-
-struct GDisplay {
-	struct GDriver				d;					// This must be the first element
-		#define gvmt(g)		((const GDISPVMT const *)((g)->d.vmt))	// For ease of access to the vmt member
-
-	struct GDISPControl {
-		coord_t					Width;
-		coord_t					Height;
-		orientation_t			Orientation;
-		powermode_t				Powermode;
-		uint8_t					Backlight;
-		uint8_t					Contrast;
-	} g;
-
-	void *						priv;				// A private area just for the drivers use.
-	void *						board;				// A private area just for the board interfaces use.
-
-	uint8_t						systemdisplay;
-	uint8_t						controllerdisplay;
-	uint16_t					flags;
-		#define GDISP_FLG_INSTREAM		0x0001		// We are in a user based stream operation
-		#define GDISP_FLG_SCRSTREAM		0x0002		// The stream area currently covers the whole screen
-		#define GDISP_FLG_DRIVER		0x0004		// This flags and above are for use by the driver
-
-	// Multithread Mutex
-	#if GDISP_NEED_MULTITHREAD
-		gfxMutex				mutex;
-	#endif
-
-	// Software clipping
-	#if GDISP_HARDWARE_CLIP != TRUE && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)
-		coord_t					clipx0, clipy0;
-		coord_t					clipx1, clipy1;		/* not inclusive */
-	#endif
-
-	// Driver call parameters
-	struct {
-		coord_t			x, y;
-		coord_t			cx, cy;
-		coord_t			x1, y1;
-		coord_t			x2, y2;
-		color_t			color;
-		void			*ptr;
-	} p;
-
-	// In call working buffers
-
-	#if GDISP_NEED_TEXT
-		// Text rendering parameters
-		struct {
-			font_t		font;
-			color_t		color;
-			color_t		bgcolor;
-			coord_t		clipx0, clipy0;
-			coord_t		clipx1, clipy1;
-		} t;
-	#endif
-	#if GDISP_LINEBUF_SIZE != 0 && ((GDISP_NEED_SCROLL && !GDISP_HARDWARE_SCROLL) || (!GDISP_HARDWARE_STREAM_WRITE && GDISP_HARDWARE_BITFILLS))
-		// A pixel line buffer
-		color_t		linebuf[GDISP_LINEBUF_SIZE];
-	#endif
-};
-
-typedef struct GDISPVMT {
-	GDriverVMT	d;
-		#define GDISP_VFLG_DYNAMICONLY		0x0001		// This display should never be statically initialised
-		#define GDISP_VFLG_PIXMAP			0x0002		// This is a pixmap display
-	bool_t (*init)(GDisplay *g);
-	void (*deinit)(GDisplay *g);
-	void (*writestart)(GDisplay *g);				// Uses p.x,p.y  p.cx,p.cy
-	void (*writepos)(GDisplay *g);					// Uses p.x,p.y
-	void (*writecolor)(GDisplay *g);				// Uses p.color
-	void (*writestop)(GDisplay *g);					// Uses no parameters
-	void (*readstart)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy
-	color_t (*readcolor)(GDisplay *g);				// Uses no parameters
-	void (*readstop)(GDisplay *g);					// Uses no parameters
-	void (*pixel)(GDisplay *g);						// Uses p.x,p.y  p.color
-	void (*clear)(GDisplay *g);						// Uses p.color
-	void (*fill)(GDisplay *g);						// Uses p.x,p.y  p.cx,p.cy  p.color
-	void (*blit)(GDisplay *g);						// Uses p.x,p.y  p.cx,p.cy  p.x1,p.y1 (=srcx,srcy)  p.x2 (=srccx), p.ptr (=buffer)
-	color_t (*get)(GDisplay *g);					// Uses p.x,p.y
-	void (*vscroll)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy, p.y1 (=lines) p.color
-	void (*control)(GDisplay *g);					// Uses p.x (=what)  p.ptr (=value)
-	void *(*query)(GDisplay *g);					// Uses p.x (=what);
-	void (*setclip)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy
-	void (*flush)(GDisplay *g);						// Uses no parameters
-} GDISPVMT;
-
-//------------------------------------------------------------------------------------------------------------
-
-// Do we need function definitions or macro's (via the VMT)
-#if IN_DRIVER || !USE_VMT || defined(__DOXYGEN__)
-	#ifdef __cplusplus
-	extern "C" {
-	#endif
-
-	// Should the driver routines should be static or not
-	#if USE_VMT
-		#define LLDSPEC         static
-	#else
-		#define LLDSPEC
-	#endif
-
-	/**
-	 * @brief   Initialize the driver.
-	 * @return	TRUE if successful.
-	 * @param[in]	g					The driver structure
-	 * @param[out]	g->g				The driver must fill in the GDISPControl structure
-	 */
-	LLDSPEC	bool_t gdisp_lld_init(GDisplay *g);
-
-	#if GDISP_HARDWARE_DEINIT || defined(__DOXYGEN__)
-		/**
-		 * @brief   The driver is being de-initialized
-		 * @pre		GDISP_HARDWARE_FLUSH is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 *
-		 */
-		LLDSPEC	void gdisp_lld_deinit(GDisplay *g);
-	#endif
-
-	#if GDISP_HARDWARE_FLUSH || defined(__DOXYGEN__)
-		/**
-		 * @brief   Flush the current drawing operations to the display
-		 * @pre		GDISP_HARDWARE_FLUSH is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_flush(GDisplay *g);
-	#endif
-
-	#if GDISP_HARDWARE_STREAM_WRITE || defined(__DOXYGEN__)
-		/**
-		 * @brief   Start a streamed write operation
-		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 *
-		 * @note		g->p.x,g->p.y	The window position
-		 * @note		g->p.cx,g->p.cy	The window size
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 * @note		Streaming operations that wrap the defined window have
-		 * 				undefined results.
-		 * @note		This must be followed by a call to @p gdisp_lld_write_pos() if GDISP_HARDWARE_STREAM_POS is TRUE.
-		 */
-		LLDSPEC	void gdisp_lld_write_start(GDisplay *g);
-
-		/**
-		 * @brief   Send a pixel to the current streaming position and then increment that position
-		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 *
-		 * @note		g->p.color		The color to display at the curent position
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_write_color(GDisplay *g);
-
-		/**
-		 * @brief   End the current streaming write operation
-		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_write_stop(GDisplay *g);
-
-		#if GDISP_HARDWARE_STREAM_POS || defined(__DOXYGEN__)
-			/**
-			 * @brief   Change the current position within the current streaming window
-			 * @pre		GDISP_HARDWARE_STREAM_POS is TRUE and GDISP_HARDWARE_STREAM_WRITE is TRUE
-			 *
-			 * @param[in]	g				The driver structure
-			 * @param[in]	g->p.x,g->p.y	The new position (which will always be within the existing stream window)
-			 *
-			 * @note		The parameter variables must not be altered by the driver.
-			 */
-			LLDSPEC	void gdisp_lld_write_pos(GDisplay *g);
-		#endif
-	#endif
-
-	#if GDISP_HARDWARE_STREAM_READ || defined(__DOXYGEN__)
-		/**
-		 * @brief   Start a streamed read operation
-		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x,g->p.y	The window position
-		 * @param[in]	g->p.cx,g->p.cy	The window size
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 * @note		Streaming operations that wrap the defined window have
-		 * 				undefined results.
-		 */
-		LLDSPEC	void gdisp_lld_read_start(GDisplay *g);
-
-		/**
-		 * @brief   Read a pixel from the current streaming position and then increment that position
-		 * @return	The color at the current position
-		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	color_t gdisp_lld_read_color(GDisplay *g);
-
-		/**
-		 * @brief   End the current streaming operation
-		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_read_stop(GDisplay *g);
-	#endif
-
-	#if GDISP_HARDWARE_DRAWPIXEL || defined(__DOXYGEN__)
-		/**
-		 * @brief   Draw a pixel
-		 * @pre		GDISP_HARDWARE_DRAWPIXEL is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x,g->p.y	The pixel position
-		 * @param[in]	g->p.color		The color to set
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_draw_pixel(GDisplay *g);
-	#endif
-
-	#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__)
-		/**
-		 * @brief   Clear the screen using the defined color
-		 * @pre		GDISP_HARDWARE_CLEARS is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.color		The color to set
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_clear(GDisplay *g);
-	#endif
-
-	#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__)
-		/**
-		 * @brief   Fill an area with a single color
-		 * @pre		GDISP_HARDWARE_FILLS is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x,g->p.y	The area position
-		 * @param[in]	g->p.cx,g->p.cy	The area size
-		 * @param[in]	g->p.color		The color to set
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_fill_area(GDisplay *g);
-	#endif
-
-	#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__)
-		/**
-		 * @brief   Fill an area using a bitmap
-		 * @pre		GDISP_HARDWARE_BITFILLS is TRUE
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x,g->p.y	The area position
-		 * @param[in]	g->p.cx,g->p.cy	The area size
-		 * @param[in]	g->p.x1,g->p.y1	The starting position in the bitmap
-		 * @param[in]	g->p.x2			The width of a bitmap line
-		 * @param[in]	g->p.ptr		The pointer to the bitmap
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_blit_area(GDisplay *g);
-	#endif
-
-	#if GDISP_HARDWARE_PIXELREAD || defined(__DOXYGEN__)
-		/**
-		 * @brief   Read a pixel from the display
-		 * @return	The color at the defined position
-		 * @pre		GDISP_HARDWARE_PIXELREAD is TRUE (and the application needs it)
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x,g->p.y	The pixel position
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	color_t gdisp_lld_get_pixel_color(GDisplay *g);
-	#endif
-
-	#if (GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL) || defined(__DOXYGEN__)
-		/**
-		 * @brief   Scroll an area of the screen
-		 * @pre		GDISP_HARDWARE_SCROLL is TRUE (and the application needs it)
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x,g->p.y	The area position
-		 * @param[in]	g->p.cx,g->p.cy	The area size
-		 * @param[in]	g->p.y1			The number of lines to scroll (positive or negative)
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 * @note		This can be easily implemented if the hardware supports
-		 * 				display area to display area copying.
-		 * @note		Clearing the exposed area on the scroll operation is not
-		 * 				needed as the high level code handles this.
-		 */
-		LLDSPEC	void gdisp_lld_vertical_scroll(GDisplay *g);
-	#endif
-
-	#if (GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL) || defined(__DOXYGEN__)
-		/**
-		 * @brief   Control some feature of the hardware
-		 * @pre		GDISP_HARDWARE_CONTROL is TRUE (and the application needs it)
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x			The operation to perform
-		 * @param[in]	g->p.ptr		The operation parameter
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_control(GDisplay *g);
-	#endif
-
-	#if (GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY) || defined(__DOXYGEN__)
-		/**
-		 * @brief   Query some feature of the hardware
-		 * @return	The information requested (typecast as void *)
-		 * @pre		GDISP_HARDWARE_QUERY is TRUE (and the application needs it)
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x			What to query
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void *gdisp_lld_query(GDisplay *g);				// Uses p.x (=what);
-	#endif
-
-	#if (GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)) || defined(__DOXYGEN__)
-		/**
-		 * @brief   Set the hardware clipping area
-		 * @pre		GDISP_HARDWARE_CLIP is TRUE (and the application needs it)
-		 *
-		 * @param[in]	g				The driver structure
-		 * @param[in]	g->p.x,g->p.y	The area position
-		 * @param[in]	g->p.cx,g->p.cy	The area size
-		 *
-		 * @note		The parameter variables must not be altered by the driver.
-		 */
-		LLDSPEC	void gdisp_lld_set_clip(GDisplay *g);
-	#endif
-
-	#ifdef __cplusplus
-	}
-	#endif
-
-#else
-	#define gdisp_lld_init(g)				gvmt(g)->init(g)
-	#define gdisp_lld_deinit(g)				gvmt(g)->deinit(g)
-	#define gdisp_lld_flush(g)				gvmt(g)->flush(g)
-	#define gdisp_lld_write_start(g)		gvmt(g)->writestart(g)
-	#define gdisp_lld_write_pos(g)			gvmt(g)->writepos(g)
-	#define gdisp_lld_write_color(g)		gvmt(g)->writecolor(g)
-	#define gdisp_lld_write_stop(g)			gvmt(g)->writestop(g)
-	#define gdisp_lld_read_start(g)			gvmt(g)->readstart(g)
-	#define gdisp_lld_read_color(g)			gvmt(g)->readcolor(g)
-	#define gdisp_lld_read_stop(g)			gvmt(g)->readstop(g)
-	#define gdisp_lld_draw_pixel(g)			gvmt(g)->pixel(g)
-	#define gdisp_lld_clear(g)				gvmt(g)->clear(g)
-	#define gdisp_lld_fill_area(g)			gvmt(g)->fill(g)
-	#define gdisp_lld_blit_area(g)			gvmt(g)->blit(g)
-	#define gdisp_lld_get_pixel_color(g)	gvmt(g)->get(g)
-	#define gdisp_lld_vertical_scroll(g)	gvmt(g)->vscroll(g)
-	#define gdisp_lld_control(g)			gvmt(g)->control(g)
-	#define gdisp_lld_query(g)				gvmt(g)->query(g)
-	#define gdisp_lld_set_clip(g)			gvmt(g)->setclip(g)
-#endif
-
-//------------------------------------------------------------------------------------------------------------
-
-// If compiling the driver then build the VMT and set the low level driver color macros.
-#if IN_DRIVER
-
-	// Make sure the driver has a valid model
-	#if !GDISP_HARDWARE_STREAM_WRITE && !GDISP_HARDWARE_DRAWPIXEL
-		#error "GDISP Driver: Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be TRUE"
-	#endif
-
-	// If we are not using multiple displays then hard-code the VMT name (except for the pixmap driver)
-	#if !IS_MULTIPLE && !IN_PIXMAP_DRIVER
-		#undef GDISP_DRIVER_VMT
-		#define GDISP_DRIVER_VMT		GDISPVMT_OnlyOne
-	#endif
-
-	// Default the flags if the driver doesn't specify any
-	#ifndef GDISP_DRIVER_VMT_FLAGS
-		#define GDISP_DRIVER_VMT_FLAGS		0
-	#endif
-
-	// Routines needed by the general driver VMT
-	#ifdef __cplusplus
-	extern "C" {
-	#endif
-		bool_t _gdispInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance);
-		void _gdispPostInitDriver(GDriver *g);
-		void _gdispDeInitDriver(GDriver *g);
-	#ifdef __cplusplus
-	}
-	#endif
-
-	// Build the VMT
-	const GDISPVMT const GDISP_DRIVER_VMT[1] = {{
-		{ GDRIVER_TYPE_DISPLAY, 0, sizeof(GDisplay), _gdispInitDriver, _gdispPostInitDriver, _gdispDeInitDriver },
-		gdisp_lld_init,
-		#if GDISP_HARDWARE_DEINIT
-			gdisp_lld_deinit,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_STREAM_WRITE
-			gdisp_lld_write_start,
-			#if GDISP_HARDWARE_STREAM_POS
-				gdisp_lld_write_pos,
-			#else
-				0,
-			#endif
-			gdisp_lld_write_color,
-			gdisp_lld_write_stop,
-		#else
-			0, 0, 0, 0,
-		#endif
-		#if GDISP_HARDWARE_STREAM_READ
-			gdisp_lld_read_start,
-			gdisp_lld_read_color,
-			gdisp_lld_read_stop,
-		#else
-			0, 0, 0,
-		#endif
-		#if GDISP_HARDWARE_DRAWPIXEL
-			gdisp_lld_draw_pixel,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_CLEARS
-			gdisp_lld_clear,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_FILLS
-			gdisp_lld_fill_area,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_BITFILLS
-			gdisp_lld_blit_area,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_PIXELREAD
-			gdisp_lld_get_pixel_color,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL
-			gdisp_lld_vertical_scroll,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL
-			gdisp_lld_control,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY
-			gdisp_lld_query,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)
-			gdisp_lld_set_clip,
-		#else
-			0,
-		#endif
-		#if GDISP_HARDWARE_FLUSH
-			gdisp_lld_flush,
-		#else
-			0,
-		#endif
-	}};
-
-	//--------------------------------------------------------------------------------------------------------
-
-	/* Low level driver pixel format information */
-	//-------------------------
-	//	True-Color color system
-	//-------------------------
-	#if GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_TRUECOLOR
-		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_TRUECOLOR
-
-		// Calculate the number of bits
-		#define LLDCOLOR_BITS_R			((GDISP_LLD_PIXELFORMAT>>8) & 0x0F)
-		#define LLDCOLOR_BITS_G			((GDISP_LLD_PIXELFORMAT>>4) & 0x0F)
-		#define LLDCOLOR_BITS_B			((GDISP_LLD_PIXELFORMAT>>0) & 0x0F)
-		#define LLDCOLOR_BITS			(LLDCOLOR_BITS_R + LLDCOLOR_BITS_G + LLDCOLOR_BITS_B)
-
-		// From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking
-		#if LLDCOLOR_BITS <= 8
-			#define LLDCOLOR_TYPE			uint8_t
-			#define LLDCOLOR_TYPE_BITS		8
-		#elif LLDCOLOR_BITS <= 16
-			#define LLDCOLOR_TYPE			uint16_t
-			#define LLDCOLOR_TYPE_BITS		16
-		#elif LLDCOLOR_BITS <= 32
-			#define LLDCOLOR_TYPE			uint32_t
-			#define LLDCOLOR_TYPE_BITS		32
-		#else
-			#error "GDISP: Cannot define low level driver color types with more than 32 bits"
-		#endif
-		#if LLDCOLOR_TYPE_BITS == LLDCOLOR_BITS
-			#define LLDCOLOR_NEEDS_MASK	FALSE
-		#else
-			#define LLDCOLOR_NEEDS_MASK	TRUE
-		#endif
-		#define LLDCOLOR_MASK()			((1 << LLDCOLOR_BITS)-1)
-
-		// Calculate the component bit shifts
-		#if (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_RGB
-			#define LLDCOLOR_SHIFT_R		(LLDCOLOR_BITS_B+LLDCOLOR_BITS_G)
-			#define LLDCOLOR_SHIFT_G		LLDCOLOR_BITS_B
-			#define LLDCOLOR_SHIFT_B		0
-		#else
-			#define LLDCOLOR_SHIFT_B		(LLDCOLOR_BITS_R+LLDCOLOR_BITS_G)
-			#define LLDCOLOR_SHIFT_G		LLDCOLOR_BITS_R
-			#define LLDCOLOR_SHIFT_R		0
-		#endif
-
-		// Calculate LLDRED_OF, LLDGREEN_OF, LLDBLUE_OF and LLDRGB2COLOR
-		#if LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R == 8
-			#define LLDRED_OF(c)			((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R))
-			#define LLDRGB2COLOR_R(r)		((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))))
-		#elif LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R > 8
-			#define LLDRED_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R)) >> (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-8))
-			#define LLDRGB2COLOR_R(r)		(((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1)))) << (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-8))
-		#else // LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R < 8
-			#define LLDRED_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R)) << (8-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
-			#define LLDRGB2COLOR_R(r)		(((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1)))) >> (8-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
-		#endif
-		#if LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G == 8
-			#define LLDGREEN_OF(c)			((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G))
-			#define LLDRGB2COLOR_G(g)		((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))))
-		#elif LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G > 8
-			#define LLDGREEN_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G)) >> (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-8))
-			#define LLDRGB2COLOR_G(g)		(((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1)))) << (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-8))
-		#else // LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G < 8
-			#define LLDGREEN_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G)) << (8-(LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G)))
-			#define LLDRGB2COLOR_G(g)		(((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1)))) >> (8-(LLDCOLOR_BITS_LLDG+COLOR_SHIFT_G)))
-		#endif
-		#if LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B == 8
-			#define LLDBLUE_OF(c)			((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B))
-			#define LLDRGB2COLOR_B(b)		((LLDCOLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))))
-		#elif LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B > 8
-			#define LLDBLUE_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B)) >> (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
-			#define LLDRGB2COLOR_B(b)		(((LLDCOLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))) << (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
-		#else // LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B < 8
-			#define LLDBLUE_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B)) << (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
-			#define LLDRGB2COLOR_B(b)		(((COLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))) >> (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
-		#endif
-		#define LLDLUMA_OF(c)				((LLDRED_OF(c)+((uint16_t)LLDGREEN_OF(c)<<1)+LLDBLUE_OF(c))>>2)
-		#define LLDEXACT_RED_OF(c)			(((uint16_t)(((c)>>LLDCOLOR_SHIFT_R)&((1<<LLDCOLOR_BITS_R)-1))*255)/((1<<LLDCOLOR_BITS_R)-1))
-		#define LLDEXACT_GREEN_OF(c)		(((uint16_t)(((c)>>LLDCOLOR_SHIFT_G)&((1<<LLDCOLOR_BITS_G)-1))*255)/((1<<LLDCOLOR_BITS_G)-1))
-		#define LLDEXACT_BLUE_OF(c)			(((uint16_t)(((c)>>LLDCOLOR_SHIFT_B)&((1<<LLDCOLOR_BITS_B)-1))*255)/((1<<LLDCOLOR_BITS_B)-1))
-		#define LLDEXACT_LUMA_OF(c)			((LLDEXACT_RED_OF(c)+((uint16_t)LLDEXACT_GREEN_OF(c)<<1)+LLDEXACT_BLUE_OF(c))>>2)
-		#define LLDLUMA2COLOR(l)			(LLDRGB2COLOR_R(l) | LLDRGB2COLOR_G(l) | LLDRGB2COLOR_B(l))
-		#define LLDRGB2COLOR(r,g,b)			(LLDRGB2COLOR_R(r) | LLDRGB2COLOR_G(g) | LLDRGB2COLOR_B(b))
-
-		// Calculate LLDHTML2COLOR
-		#if LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R == 24
-			#define LLDHTML2COLOR_R(h)		((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16))
-		#elif COLOR_BITS_R + COLOR_SHIFT_R > 24
-			#define LLDHTML2COLOR_R(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) << (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-24))
-		#else // COLOR_BITS_R + COLOR_SHIFT_R < 24
-			#define LLDHTML2COLOR_R(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) >> (24-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
-		#endif
-		#if LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G == 16
-			#define LLDHTML2COLOR_G(h)		((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8))
-		#elif LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G > 16
-			#define LLDHTML2COLOR_G(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) << (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-16))
-		#else // LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G < 16
-			#define LLDHTML2COLOR_G(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) >> (16-(LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G)))
-		#endif
-		#if LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B == 8
-			#define LLDHTML2COLOR_B(h)		((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))
-		#elif LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B > 8
-			#define LLDHTML2COLOR_B(h)		(((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) << (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
-		#else // LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B < 8
-			#define LLDHTML2COLOR_B(h)		(((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) >> (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
-		#endif
-		#define LLDHTML2COLOR(h)		((LLDCOLOR_TYPE)(LLDHTML2COLOR_R(h) | LLDHTML2COLOR_G(h) | LLDHTML2COLOR_B(h)))
-
-	//-------------------------
-	//	Gray-scale color system
-	//-------------------------
-	#elif (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_GRAYSCALE
-		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_GRAYSCALE
-
-		// Calculate the number of bits and shifts
-		#define LLDCOLOR_BITS			(GDISP_LLD_PIXELFORMAT & 0xFF)
-		#define LLDCOLOR_BITS_R			LLDCOLOR_BITS
-		#define LLDCOLOR_BITS_G			LLDCOLOR_BITS
-		#define LLDCOLOR_BITS_B			LLDCOLOR_BITS
-		#define LLDCOLOR_SHIFT_R		0
-		#define LLDCOLOR_SHIFT_G		0
-		#define LLDCOLOR_SHIFT_B		0
-
-		// From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking
-		#if LLDCOLOR_BITS <= 8
-			#define LLDCOLOR_TYPE		uint8_t
-			#define LLDCOLOR_TYPE_BITS	8
-		#else
-			#error "GDISP: Cannot define gray-scale low level driver color types with more than 8 bits"
-		#endif
-		#if LLDCOLOR_TYPE_BITS == LLDCOLOR_BITS
-			#define LLDCOLOR_NEEDS_MASK	FALSE
-		#else
-			#define LLDCOLOR_NEEDS_MASK	TRUE
-		#endif
-		#define LLDCOLOR_MASK()			((1 << LLDCOLOR_BITS)-1)
-
-		#if COLOR_BITS == 1
-			#define LLDRGB2COLOR(r,g,b)		(((r)|(g)|(b)) ? 1 : 0)
-			#define LLDLUMA2COLOR(l)		((l) ? 1 : 0)
-			#define LLDHTML2COLOR(h)		((h) ? 1 : 0)
-			#define LLDLUMA_OF(c)			((c) ? 255 : 0)
-			#define LLDEXACT_LUMA_OF(c)		LLDLUMA_OF(c)
-		#else
-			// They eye is more sensitive to green
-			#define LLDRGB2COLOR(r,g,b)		((LLDCOLOR_TYPE)(((uint16_t)(r)+(g)+(g)+(b)) >> (10-LLDCOLOR_BITS)))
-			#define LLDLUMA2COLOR(l)		((LLDCOLOR_TYPE)((l)>>(8-LLDCOLOR_BITS)))
-			#define LLDHTML2COLOR(h)		((LLDCOLOR_TYPE)(((((h)&0xFF0000)>>16)+(((h)&0x00FF00)>>7)+((h)&0x0000FF)) >> (10-LLDCOLOR_BITS)))
-			#define LLDLUMA_OF(c)			(((c) & ((1<<LLDCOLOR_BITS)-1)) << (8-LLDCOLOR_BITS))
-			#define LLDEXACT_LUMA_OF(c)		((((uint16_t)(c) & ((1<<LLDCOLOR_BITS)-1))*255)/((1<<LLDCOLOR_BITS)-1))
-		#endif
-
-		#define LLDRED_OF(c)			LLDLUMA_OF(c)
-		#define LLDGREEN_OF(c)			LLDLUMA_OF(c)
-		#define LLDBLUE_OF(c)			LLDLUMA_OF(c)
-		#define LLDEXACT_RED_OF(c)		LLDEXACT_LUMA_OF(c)
-		#define LLDEXACT_GREEN_OF(c)	LLDEXACT_LUMA_OF(c)
-		#define LLDEXACT_BLUE_OF(c)		LLDEXACT_LUMA_OF(c)
-
-	//-------------------------
-	//	Palette color system
-	//-------------------------
-	#elif (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_PALETTE
-		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_PALETTE
-
-		#error "GDISP: A palette color system for low level drivers is not currently supported"
-
-	//-------------------------
-	//	Some other color system
-	//-------------------------
-	#else
-		#error "GDISP: Unsupported color system for low level drivers"
-	#endif
-
-	/* Which is the larger color type */
-	#if COLOR_BITS > LLDCOLOR_BITS
-		#define LARGER_COLOR_BITS	COLOR_BITS
-		#define LARGER_COLOR_TYPE	COLOR_TYPE
-	#else
-		#define LARGER_COLOR_BITS	LLDCOLOR_BITS
-		#define LARGER_COLOR_TYPE	LLDCOLOR_TYPE
-	#endif
-
-	/**
-	 * @brief	Controls color conversion accuracy for a low level driver
-	 * @details	Should higher precision be used when converting colors.
-	 * @note	Color conversion is only necessary if GDISP_PIXELFORMAT != GDISP_LLD_PIXELFORMAT
-	 * @note	It only makes sense to turn this on if you have a high bit depth display but
-	 * 			are running the application in low bit depths.
-	 * @note	To achieve higher color accuracy bit shifting is replaced with multiplies and divides.
-	 */
-	#ifndef GDISP_HARDWARE_USE_EXACT_COLOR
-		#if LLDCOLOR_BITS_R - COLOR_BITS_R >= LLDCOLOR_BITS_R/2 || LLDCOLOR_BITS_G - COLOR_BITS_G >= LLDCOLOR_BITS_G/2 || LLDCOLOR_BITS_B - COLOR_BITS_B >= LLDCOLOR_BITS_B/2
-			#define GDISP_HARDWARE_USE_EXACT_COLOR	TRUE
-		#else
-			#define GDISP_HARDWARE_USE_EXACT_COLOR	FALSE
-		#endif
-	#endif
-
-	/* Low level driver pixel format conversion functions */
-	#if GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT || defined(__DOXYGEN__)
-		/**
-		 * @brief	Convert from a standard color format to the low level driver pixel format
-		 * @note	For use only by low level drivers
-		 */
-		#define gdispColor2Native(c)	(c)
-		/**
-		 * @brief	Convert from a low level driver pixel format to the standard color format
-		 * @note	For use only by low level drivers
-		 */
-		#define gdispNative2Color(c)	(c)
-	#else
-		static LLDCOLOR_TYPE gdispColor2Native(color_t c) {
-			#if COLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE || LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE
-				#if GDISP_HARDWARE_USE_EXACT_COLOR
-					return LLDLUMA2COLOR(EXACT_LUMA_OF(c));
-				#else
-					return LLDLUMA2COLOR(LUMA_OF(c));
-				#endif
-			#elif COLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR && LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR
-				#if GDISP_HARDWARE_USE_EXACT_COLOR
-					return LLDRGB2COLOR(EXACT_RED_OF(c), EXACT_GREEN_OF(c), EXACT_BLUE_OF(c));
-				#else
-					return LLDRGB2COLOR(RED_OF(c), GREEN_OF(c), BLUE_OF(c));
-				#endif
-			#else
-				#error "GDISP: This pixel format conversion is not supported yet"
-			#endif
-		}
-		static color_t gdispNative2Color(LLDCOLOR_TYPE c) {
-			#if COLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE || LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE
-				#if GDISP_HARDWARE_USE_EXACT_COLOR
-					return LUMA2COLOR(LLDEXACT_LUMA_OF(c));
-				#else
-					return LUMA2COLOR(LLDLUMA_OF(c));
-				#endif
-			#elif COLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR && LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR
-				#if GDISP_HARDWARE_USE_EXACT_COLOR
-					return RGB2COLOR(LLDEXACT_RED_OF(c), LLDEXACT_GREEN_OF(c), LLDEXACT_BLUE_OF(c));
-				#else
-					return RGB2COLOR(LLDRED_OF(c), LLDGREEN_OF(c), LLDBLUE_OF(c));
-				#endif
-			#else
-				#error "GDISP: This pixel format conversion is not supported yet"
-			#endif
-		}
-	#endif
-
-#endif
-
-//------------------------------------------------------------------------------------------------------------
-
-#undef IN_PIXMAP_DRIVER
-#undef IS_MULTIPLE
-#undef IN_DRIVER
-#undef USE_VMT
-#endif	/* GFX_USE_GDISP */
-
-#endif	/* _GDISP_LLD_H */
-/** @} */
diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c
new file mode 100644
index 00000000..cebed1ef
--- /dev/null
+++ b/src/gdisp/gdisp.c
@@ -0,0 +1,3370 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GDISP
+
+/* Include the low level driver information */
+#include "gdisp_driver.h"
+
+#if 1
+	#undef INLINE
+	#if defined(__KEIL__) || defined(__C51__)
+		#define INLINE	__inline
+	#else
+		#define INLINE	inline
+	#endif
+#else
+	#undef INLINE
+	#define INLINE
+#endif
+
+// Number of milliseconds for the startup logo - 0 means disabled.
+#if GDISP_NEED_STARTUP_LOGO
+	#define GDISP_STARTUP_LOGO_TIMEOUT		1000
+#else
+	#define GDISP_STARTUP_LOGO_TIMEOUT		0
+#endif
+
+/*===========================================================================*/
+/* Driver local variables.                                                   */
+/*===========================================================================*/
+
+#if GDISP_NEED_TIMERFLUSH
+	static GTimer	FlushTimer;
+#endif
+
+GDisplay	*GDISP;
+
+#if GDISP_NEED_MULTITHREAD
+	#define MUTEX_INIT(g)		gfxMutexInit(&(g)->mutex)
+	#define MUTEX_ENTER(g)		gfxMutexEnter(&(g)->mutex)
+	#define MUTEX_EXIT(g)		gfxMutexExit(&(g)->mutex)
+	#define MUTEX_DEINIT(g)		gfxMutexDestroy(&(g)->mutex)
+#else
+	#define MUTEX_INIT(g)
+	#define MUTEX_ENTER(g)
+	#define MUTEX_EXIT(g)
+	#define MUTEX_DEINIT(g)
+#endif
+
+#define NEED_CLIPPING	(GDISP_HARDWARE_CLIP != TRUE && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP))
+
+#if !NEED_CLIPPING
+	#define TEST_CLIP_AREA(g)
+#elif GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+	#define TEST_CLIP_AREA(g)																					\
+			if (!gvmt(g)->setclip) {																				\
+				if ((g)->p.x < (g)->clipx0) { (g)->p.cx -= (g)->clipx0 - (g)->p.x; (g)->p.x = (g)->clipx0; }	\
+				if ((g)->p.y < (g)->clipy0) { (g)->p.cy -= (g)->clipy0 - (g)->p.y; (g)->p.y = (g)->clipy0; }	\
+				if ((g)->p.x + (g)->p.cx > (g)->clipx1)	(g)->p.cx = (g)->clipx1 - (g)->p.x;						\
+				if ((g)->p.y + (g)->p.cy > (g)->clipy1)	(g)->p.cy = (g)->clipy1 - (g)->p.y;						\
+			}																									\
+			if ((g)->p.cx > 0 && (g)->p.cy > 0)
+#else
+	#define TEST_CLIP_AREA(g)																				\
+			if ((g)->p.x < (g)->clipx0) { (g)->p.cx -= (g)->clipx0 - (g)->p.x; (g)->p.x = (g)->clipx0; }	\
+			if ((g)->p.y < (g)->clipy0) { (g)->p.cy -= (g)->clipy0 - (g)->p.y; (g)->p.y = (g)->clipy0; }	\
+			if ((g)->p.x + (g)->p.cx > (g)->clipx1)	(g)->p.cx = (g)->clipx1 - (g)->p.x;						\
+			if ((g)->p.y + (g)->p.cy > (g)->clipy1)	(g)->p.cy = (g)->clipy1 - (g)->p.y;						\
+			if ((g)->p.cx > 0 && (g)->p.cy > 0)
+#endif
+
+/*==========================================================================*/
+/* Internal functions.														*/
+/*==========================================================================*/
+
+#if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE
+	static INLINE void setglobalwindow(GDisplay *g) {
+		coord_t	x, y;
+		x = g->p.x; y = g->p.y;
+		g->p.x = g->p.y = 0;
+		g->p.cx = g->g.Width; g->p.cy = g->g.Height;
+		gdisp_lld_write_start(g);
+		g->p.x = x; g->p.y = y;
+		g->flags |= GDISP_FLG_SCRSTREAM;
+	}
+#endif
+
+#if GDISP_NEED_AUTOFLUSH && GDISP_HARDWARE_FLUSH == HARDWARE_AUTODETECT
+	#define autoflush_stopdone(g)	if (gvmt(g)->flush) gdisp_lld_flush(g)
+#elif GDISP_NEED_AUTOFLUSH && GDISP_HARDWARE_FLUSH
+	#define autoflush_stopdone(g)	gdisp_lld_flush(g)
+#else
+	#define autoflush_stopdone(g)
+#endif
+
+#if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE
+	#define autoflush(g)									\
+			{												\
+				if ((g->flags & GDISP_FLG_SCRSTREAM)) {		\
+					gdisp_lld_write_stop(g);				\
+					g->flags &= ~GDISP_FLG_SCRSTREAM;		\
+				}											\
+				autoflush_stopdone(g);						\
+			}
+#else
+	#define autoflush(g)		autoflush_stopdone(g)
+#endif
+
+// drawpixel(g)
+// Parameters:	x,y
+// Alters:		cx, cy (if using streaming)
+// Does not clip
+static INLINE void drawpixel(GDisplay *g) {
+
+	// Best is hardware accelerated pixel draw
+	#if GDISP_HARDWARE_DRAWPIXEL
+		#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+			if (gvmt(g)->pixel)
+		#endif
+		{
+			gdisp_lld_draw_pixel(g);
+			return;
+		}
+	#endif
+
+	// Next best is cursor based streaming
+	#if GDISP_HARDWARE_DRAWPIXEL != TRUE && GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE
+		#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
+			if (gvmt(g)->writepos)
+		#endif
+		{
+			if (!(g->flags & GDISP_FLG_SCRSTREAM))
+				setglobalwindow(g);
+			gdisp_lld_write_pos(g);
+			gdisp_lld_write_color(g);
+			return;
+		}
+	#endif
+
+	// Worst is general streaming
+	#if GDISP_HARDWARE_DRAWPIXEL != TRUE && GDISP_HARDWARE_STREAM_POS != TRUE && GDISP_HARDWARE_STREAM_WRITE
+		// The following test is unneeded because we are guaranteed to have streaming if we don't have drawpixel
+		//#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+		//	if (gvmt(g)->writestart)
+		//#endif
+		{
+			g->p.cx = g->p.cy = 1;
+			gdisp_lld_write_start(g);
+			gdisp_lld_write_color(g);
+			gdisp_lld_write_stop(g);
+			return;
+		}
+	#endif
+}
+
+// drawpixel_clip(g)
+// Parameters:	x,y
+// Alters:		cx, cy (if using streaming)
+#if NEED_CLIPPING
+	static INLINE void drawpixel_clip(GDisplay *g) {
+		#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+			if (!gvmt(g)->setclip)
+		#endif
+		{
+			if (g->p.x < g->clipx0 || g->p.x >= g->clipx1 || g->p.y < g->clipy0 || g->p.y >= g->clipy1)
+				return;
+		}
+		drawpixel(g);
+	}
+#else
+	#define drawpixel_clip(g)		drawpixel(g)
+#endif
+
+// fillarea(g)
+// Parameters:	x,y cx,cy and color
+// Alters:		nothing
+// Note:		This is not clipped
+// Resets the streaming area if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set.
+static INLINE void fillarea(GDisplay *g) {
+
+	// Best is hardware accelerated area fill
+	#if GDISP_HARDWARE_FILLS
+		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+			if (gvmt(g)->fill)
+		#endif
+		{
+			gdisp_lld_fill_area(g);
+			return;
+		}
+	#endif
+
+	// Next best is hardware streaming
+	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
+		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+			if (gvmt(g)->writestart)
+		#endif
+		{
+			uint32_t	area;
+
+			#if GDISP_HARDWARE_STREAM_POS
+				if ((g->flags & GDISP_FLG_SCRSTREAM)) {
+					gdisp_lld_write_stop(g);
+					g->flags &= ~GDISP_FLG_SCRSTREAM;
+				}
+			#endif
+
+			area = (uint32_t)g->p.cx * g->p.cy;
+			gdisp_lld_write_start(g);
+			#if GDISP_HARDWARE_STREAM_POS
+				#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
+					if (gvmt(g)->writepos)
+				#endif
+				gdisp_lld_write_pos(g);
+			#endif
+			for(; area; area--)
+				gdisp_lld_write_color(g);
+			gdisp_lld_write_stop(g);
+			return;
+		}
+	#endif
+
+	// Worst is pixel drawing
+	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
+		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
+		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+		//	if (gvmt(g)->pixel)
+		//#endif
+		{
+			coord_t x0, y0, x1, y1;
+
+			x0 = g->p.x;
+			y0 = g->p.y;
+			x1 = g->p.x + g->p.cx;
+			y1 = g->p.y + g->p.cy;
+			for(; g->p.y < y1; g->p.y++, g->p.x = x0)
+				for(; g->p.x < x1; g->p.x++)
+					gdisp_lld_draw_pixel(g);
+			g->p.y = y0;
+			return;
+		}
+	#endif
+}
+
+// Parameters:	x,y and x1
+// Alters:		x,y x1,y1 cx,cy
+// Assumes the window covers the screen and a write_stop() will occur later
+//	if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set.
+static void hline_clip(GDisplay *g) {
+	// Swap the points if necessary so it always goes from x to x1
+	if (g->p.x1 < g->p.x) {
+		g->p.cx = g->p.x; g->p.x = g->p.x1; g->p.x1 = g->p.cx;
+	}
+
+	// Clipping
+	#if NEED_CLIPPING
+		#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+			if (!gvmt(g)->setclip)
+		#endif
+		{
+			if (g->p.y < g->clipy0 || g->p.y >= g->clipy1) return;
+			if (g->p.x < g->clipx0) g->p.x = g->clipx0;
+			if (g->p.x1 >= g->clipx1) g->p.x1 = g->clipx1 - 1;
+			if (g->p.x1 < g->p.x) return;
+		}
+	#endif
+
+	// This is an optimization for the point case. It is only worthwhile however if we
+	// have hardware fills or if we support both hardware pixel drawing and hardware streaming
+	#if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE)
+		// Is this a point
+		if (g->p.x == g->p.x1) {
+			drawpixel(g);
+			return;
+		}
+	#endif
+
+	// Best is hardware accelerated area fill
+	#if GDISP_HARDWARE_FILLS
+		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+			if (gvmt(g)->fill)
+		#endif
+		{
+			g->p.cx = g->p.x1 - g->p.x + 1;
+			g->p.cy = 1;
+			gdisp_lld_fill_area(g);
+			return;
+		}
+	#endif
+
+	// Next best is cursor based streaming
+	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE
+		#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
+			if (gvmt(g)->writepos)
+		#endif
+		{
+			if (!(g->flags & GDISP_FLG_SCRSTREAM))
+				setglobalwindow(g);
+			g->p.cx = g->p.x1 - g->p.x + 1;
+			gdisp_lld_write_pos(g);
+			do { gdisp_lld_write_color(g); } while(--g->p.cx);
+			return;
+		}
+	#endif
+
+	// Next best is streaming
+	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_POS != TRUE && GDISP_HARDWARE_STREAM_WRITE
+		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+			if (gvmt(g)->writestart)
+		#endif
+		{
+			g->p.cx = g->p.x1 - g->p.x + 1;
+			g->p.cy = 1;
+			gdisp_lld_write_start(g);
+			do { gdisp_lld_write_color(g); } while(--g->p.cx);
+			gdisp_lld_write_stop(g);
+			return;
+		}
+	#endif
+
+	// Worst is drawing pixels
+	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
+		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
+		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+		//	if (gvmt(g)->pixel)
+		//#endif
+		{
+			for(; g->p.x <= g->p.x1; g->p.x++)
+				gdisp_lld_draw_pixel(g);
+			return;
+		}
+	#endif
+}
+
+// Parameters:	x,y and y1
+// Alters:		x,y x1,y1 cx,cy
+static void vline_clip(GDisplay *g) {
+	// Swap the points if necessary so it always goes from y to y1
+	if (g->p.y1 < g->p.y) {
+		g->p.cy = g->p.y; g->p.y = g->p.y1; g->p.y1 = g->p.cy;
+	}
+
+	// Clipping
+	#if NEED_CLIPPING
+		#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+			if (!gvmt(g)->setclip)
+		#endif
+		{
+			if (g->p.x < g->clipx0 || g->p.x >= g->clipx1) return;
+			if (g->p.y < g->clipy0) g->p.y = g->clipy0;
+			if (g->p.y1 >= g->clipy1) g->p.y1 = g->clipy1 - 1;
+			if (g->p.y1 < g->p.y) return;
+		}
+	#endif
+
+	// This is an optimization for the point case. It is only worthwhile however if we
+	// have hardware fills or if we support both hardware pixel drawing and hardware streaming
+	#if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) || (GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE)
+		// Is this a point
+		if (g->p.y == g->p.y1) {
+			drawpixel(g);
+			return;
+		}
+	#endif
+
+	// Best is hardware accelerated area fill
+	#if GDISP_HARDWARE_FILLS
+		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+			if (gvmt(g)->fill)
+		#endif
+		{
+			g->p.cy = g->p.y1 - g->p.y + 1;
+			g->p.cx = 1;
+			gdisp_lld_fill_area(g);
+			return;
+		}
+	#endif
+
+	// Next best is streaming
+	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
+		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+			if (gvmt(g)->writestart)
+		#endif
+		{
+			#if GDISP_HARDWARE_STREAM_POS
+				if ((g->flags & GDISP_FLG_SCRSTREAM)) {
+					gdisp_lld_write_stop(g);
+					g->flags &= ~GDISP_FLG_SCRSTREAM;
+				}
+			#endif
+			g->p.cy = g->p.y1 - g->p.y + 1;
+			g->p.cx = 1;
+			gdisp_lld_write_start(g);
+			#if GDISP_HARDWARE_STREAM_POS
+				#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
+					if (gvmt(g)->writepos)
+				#endif
+				gdisp_lld_write_pos(g);
+			#endif
+			do { gdisp_lld_write_color(g); } while(--g->p.cy);
+			gdisp_lld_write_stop(g);
+			return;
+		}
+	#endif
+
+	// Worst is drawing pixels
+	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
+		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
+		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+		//	if (gvmt(g)->pixel)
+		//#endif
+		{
+			for(; g->p.y <= g->p.y1; g->p.y++)
+				gdisp_lld_draw_pixel(g);
+			return;
+		}
+	#endif
+}
+
+// Parameters:	x,y and x1,y1
+// Alters:		x,y x1,y1 cx,cy
+static void line_clip(GDisplay *g) {
+	int16_t dy, dx;
+	int16_t addx, addy;
+	int16_t P, diff, i;
+
+	// Is this a horizontal line (or a point)
+	if (g->p.y == g->p.y1) {
+		hline_clip(g);
+		return;
+	}
+
+	// Is this a vertical line (or a point)
+	if (g->p.x == g->p.x1) {
+		vline_clip(g);
+		return;
+	}
+
+	// Not horizontal or vertical
+
+	// Use Bresenham's line drawing algorithm.
+	//	This should be replaced with fixed point slope based line drawing
+	//	which is more efficient on modern processors as it branches less.
+	//	When clipping is needed, all the clipping could also be done up front
+	//	instead of on each pixel.
+
+	if (g->p.x1 >= g->p.x) {
+		dx = g->p.x1 - g->p.x;
+		addx = 1;
+	} else {
+		dx = g->p.x - g->p.x1;
+		addx = -1;
+	}
+	if (g->p.y1 >= g->p.y) {
+		dy = g->p.y1 - g->p.y;
+		addy = 1;
+	} else {
+		dy = g->p.y - g->p.y1;
+		addy = -1;
+	}
+
+	if (dx >= dy) {
+		dy <<= 1;
+		P = dy - dx;
+		diff = P - dx;
+
+		for(i=0; i<=dx; ++i) {
+			drawpixel_clip(g);
+			if (P < 0) {
+				P  += dy;
+				g->p.x += addx;
+			} else {
+				P  += diff;
+				g->p.x += addx;
+				g->p.y += addy;
+			}
+		}
+	} else {
+		dx <<= 1;
+		P = dx - dy;
+		diff = P - dy;
+
+		for(i=0; i<=dy; ++i) {
+			drawpixel_clip(g);
+			if (P < 0) {
+				P  += dx;
+				g->p.y += addy;
+			} else {
+				P  += diff;
+				g->p.x += addx;
+				g->p.y += addy;
+			}
+		}
+	}
+}
+
+#if GDISP_STARTUP_LOGO_TIMEOUT > 0
+	static bool_t	initDone;
+	static void StartupLogoDisplay(GDisplay *g) {
+		coord_t			x, y, w;
+		const coord_t *	p;
+		static const coord_t blks[] = {
+				// u
+				2, 6, 1, 10,
+				3, 11, 4, 1,
+				6, 6, 1, 6,
+				// G
+				8, 0, 1, 12,
+				9, 0, 6, 1,
+				9, 11, 6, 1,
+				14, 6, 1, 5,
+				12, 6, 2, 1,
+				// F
+				16, 0, 1, 12,
+				17, 0, 6, 1,
+				17, 6, 3, 1,
+				// X
+				22, 6, 7, 1,
+				24, 0, 1, 6,
+				22, 7, 1, 5,
+				28, 0, 1, 6,
+				26, 7, 1, 5,
+		};
+
+		// Get a starting position and a scale
+		// Work on a 8x16 grid for each char, 4 chars (uGFX) in 1 line, using half the screen
+		w = g->g.Width/(8*4*2);
+		if (!w) w = 1;
+		x = (g->g.Width - (8*4)*w)/2;
+		y = (g->g.Height - (16*1)*w)/2;
+
+		// Simple but crude!
+		for(p = blks; p < blks+sizeof(blks)/sizeof(blks[0]); p+=4)
+			gdispGFillArea(g, x+p[0]*w, y+p[1]*w, p[2]*w, p[3]*w, Blue);
+	}
+#endif
+
+#if GDISP_NEED_TIMERFLUSH
+	static void FlushTimerFn(void *param) {
+		GDisplay *	g;
+		(void)		param;
+
+		for(g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, 0); g; g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g))
+			gdispGFlush(g);
+	}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+typedef const GDISPVMT const GDISPVMTLIST[];
+
+void _gdispInit(void)
+{
+	// GDISP_DRIVER_LIST is defined - create each driver instance
+	#if defined(GDISP_DRIVER_LIST)
+		{
+			unsigned	i;
+
+			extern GDISPVMTLIST				GDISP_DRIVER_LIST;
+			static GDISPVMTLIST dclist[] = {GDISP_DRIVER_LIST};
+
+			for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++)
+				if (!(dclist[i]->d.flags & GDISP_VFLG_DYNAMICONLY))
+					gdriverRegister(&dclist[i]->d, 0);
+		}
+	#elif GDISP_TOTAL_DISPLAYS > 1
+		{
+			unsigned	i;
+			extern GDISPVMTLIST				GDISPVMT_OnlyOne;
+
+			if (!(GDISPVMT_OnlyOne->d.flags & GDISP_VFLG_DYNAMICONLY)) {
+				for(i = 0; i < GDISP_TOTAL_DISPLAYS; i++)
+					gdriverRegister(&GDISPVMT_OnlyOne->d, 0);
+			}
+		}
+	#else
+		{
+			extern GDISPVMTLIST				GDISPVMT_OnlyOne;
+
+			if (!(GDISPVMT_OnlyOne->d.flags & GDISP_VFLG_DYNAMICONLY))
+				gdriverRegister(&GDISPVMT_OnlyOne->d, 0);
+		}
+	#endif
+
+	// Re-clear the display after the timeout if we added the logo
+	#if GDISP_STARTUP_LOGO_TIMEOUT > 0
+		{
+			GDisplay	*g;
+
+			gfxSleepMilliseconds(GDISP_STARTUP_LOGO_TIMEOUT);
+
+			for(g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, 0); g; g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g)) {
+				gdispGClear(g, GDISP_STARTUP_COLOR);
+				#if GDISP_HARDWARE_FLUSH
+					gdispGFlush(g);
+				#endif
+			}
+
+			initDone = TRUE;
+		}
+	#endif
+
+	// Start the automatic timer flush (if required)
+	#if GDISP_NEED_TIMERFLUSH
+		gtimerInit(&FlushTimer);
+		gtimerStart(&FlushTimer, FlushTimerFn, 0, TRUE, GDISP_NEED_TIMERFLUSH);
+	#endif
+}
+
+void _gdispDeinit(void)
+{
+	/* ToDo */
+}
+
+bool_t _gdispInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance) {
+	#define		gd		((GDisplay *)g)
+	bool_t		ret;
+
+	// Intialise fields
+	gd->systemdisplay = systeminstance;
+	gd->controllerdisplay = driverinstance;
+	gd->flags = 0;
+	gd->priv = param;
+	MUTEX_INIT(gd);
+
+	// Call the driver init
+	MUTEX_ENTER(gd);
+	ret = gdisp_lld_init(gd);
+	MUTEX_EXIT(gd);
+	return ret;
+
+	#undef gd
+}
+
+void _gdispPostInitDriver(GDriver *g) {
+	#define		gd		((GDisplay *)g)
+
+	// Set orientation, clip
+	#if defined(GDISP_DEFAULT_ORIENTATION) && GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
+		#if GDISP_NEED_PIXMAP
+			// Pixmaps should stay in their created orientation (at least initially)
+			if (!(gvmt(gd)->d.flags & GDISP_VFLG_PIXMAP))
+		#endif
+			gdispGControl(gd, GDISP_CONTROL_ORIENTATION, (void *)GDISP_DEFAULT_ORIENTATION);
+	#endif
+	#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
+		gdispGSetClip(gd, 0, 0, gd->g.Width, gd->g.Height);
+	#endif
+
+	// Clear the Screen
+	gdispGClear(gd, GDISP_STARTUP_COLOR);
+
+	// Display the startup logo if this is a static initialised display
+	#if GDISP_STARTUP_LOGO_TIMEOUT > 0
+		if (!initDone)
+			StartupLogoDisplay(gd);
+	#endif
+
+	// Flush
+	#if GDISP_HARDWARE_FLUSH
+		gdispGFlush(gd);
+	#endif
+
+	// If this is the first driver set GDISP
+	if (!GDISP)
+		GDISP = gd;
+
+	#undef gd
+}
+
+void _gdispDeInitDriver(GDriver *g) {
+	#define		gd		((GDisplay *)g)
+
+	if (GDISP == gd)
+		GDISP = (GDisplay *)gdriverGetInstance(GDRIVER_TYPE_DISPLAY, 0);
+
+	#if GDISP_HARDWARE_DEINIT
+		#if GDISP_HARDWARE_DEINIT == HARDWARE_AUTODETECT
+			if (gvmt(gd)->deinit)
+		#endif
+		{
+			MUTEX_ENTER(gd);
+			gdisp_lld_deinit(gd);
+			MUTEX_EXIT(gd);
+		}
+	#endif
+	MUTEX_DEINIT(gd);
+
+	#undef gd
+}
+
+GDisplay *gdispGetDisplay(unsigned display) {
+	return (GDisplay *)gdriverGetInstance(GDRIVER_TYPE_DISPLAY, display);
+}
+
+void gdispSetDisplay(GDisplay *g) {
+	if (g) GDISP = g;
+}
+
+unsigned gdispGetDisplayCount(void) {
+	return gdriverInstanceCount(GDRIVER_TYPE_DISPLAY);
+}
+
+coord_t gdispGGetWidth(GDisplay *g)				{ return g->g.Width; }
+coord_t gdispGGetHeight(GDisplay *g)			{ return g->g.Height; }
+powermode_t gdispGGetPowerMode(GDisplay *g)		{ return g->g.Powermode; }
+orientation_t gdispGGetOrientation(GDisplay *g)	{ return g->g.Orientation; }
+uint8_t gdispGGetBacklight(GDisplay *g)			{ return g->g.Backlight; }
+uint8_t gdispGGetContrast(GDisplay *g)			{ return g->g.Contrast; }
+
+void gdispGFlush(GDisplay *g) {
+	#if GDISP_HARDWARE_FLUSH
+		#if GDISP_HARDWARE_FLUSH == HARDWARE_AUTODETECT
+			if (gvmt(g)->flush)
+		#endif
+		{
+			MUTEX_ENTER(g);
+			gdisp_lld_flush(g);
+			MUTEX_EXIT(g);
+		}
+	#else
+		(void) g;
+	#endif
+}
+
+#if GDISP_NEED_STREAMING
+	void gdispGStreamStart(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy) {
+		MUTEX_ENTER(g);
+
+		#if NEED_CLIPPING
+			#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+				if (!gvmt(g)->setclip)
+			#endif
+			// Test if the area is valid - if not then exit
+			if (x < g->clipx0 || x+cx > g->clipx1 || y < g->clipy0 || y+cy > g->clipy1) {
+				MUTEX_EXIT(g);
+				return;
+			}
+		#endif
+
+		g->flags |= GDISP_FLG_INSTREAM;
+
+		// Best is hardware streaming
+		#if GDISP_HARDWARE_STREAM_WRITE
+			#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+				if (gvmt(g)->writestart)
+			#endif
+			{
+				g->p.x = x;
+				g->p.y = y;
+				g->p.cx = cx;
+				g->p.cy = cy;
+				gdisp_lld_write_start(g);
+				#if GDISP_HARDWARE_STREAM_POS
+					#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
+						if (gvmt(g)->writepos)
+					#endif
+					gdisp_lld_write_pos(g);
+				#endif
+				return;
+			}
+		#endif
+
+		// Worst - save the parameters and use pixel drawing and/or area fills
+		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
+			// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
+			//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+			//	if (gvmt(g)->pixel)
+			//#endif
+			{
+				// Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position, cx = bufpos
+				g->p.x1 = g->p.x = x;
+				g->p.y1 = g->p.y = y;
+				g->p.x2 = x + cx;
+				g->p.y2 = y + cy;
+				#if (GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS) || GDISP_HARDWARE_FILLS
+					g->p.cx = 0;
+					g->p.cy = 1;
+				#endif
+				return;
+			}
+		#endif
+
+		// Don't release the mutex as gdispStreamEnd() will do that.
+	}
+
+	void gdispGStreamColor(GDisplay *g, color_t color) {
+		#if !GDISP_HARDWARE_STREAM_WRITE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS
+			coord_t	 sx1, sy1;
+		#endif
+
+		// Don't touch the mutex as we should already own it
+
+		// Ignore this call if we are not streaming
+		if (!(g->flags & GDISP_FLG_INSTREAM))
+			return;
+
+		// Best is hardware streaming
+		#if GDISP_HARDWARE_STREAM_WRITE
+			#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+				if (gvmt(g)->writestart)
+			#endif
+			{
+				g->p.color = color;
+				gdisp_lld_write_color(g);
+				return;
+			}
+		#endif
+
+		// Next best is to use bitfills with our line buffer
+		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS
+			#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
+				if (gvmt(g)->blit)
+			#endif
+			{
+				g->linebuf[g->p.cx++] = color;
+				if (g->p.cx >= GDISP_LINEBUF_SIZE) {
+					sx1 = g->p.x1;
+					sy1 = g->p.y1;
+					g->p.x1 = 0;
+					g->p.y1 = 0;
+					g->p.ptr = (void *)g->linebuf;
+					gdisp_lld_blit_area(g);
+					g->p.x1 = sx1;
+					g->p.y1 = sy1;
+					g->p.x += g->p.cx;
+					g->p.cx = 0;
+				}
+
+				// Just wrap at end-of-line and end-of-buffer
+				if (g->p.x+g->p.cx >= g->p.x2) {
+					if (g->p.cx) {
+						sx1 = g->p.x1;
+						sy1 = g->p.y1;
+						g->p.x1 = 0;
+						g->p.y1 = 0;
+						g->p.ptr = (void *)g->linebuf;
+						gdisp_lld_blit_area(g);
+						g->p.x1 = sx1;
+						g->p.y1 = sy1;
+						g->p.cx = 0;
+					}
+					g->p.x = g->p.x1;
+					if (++g->p.y >= g->p.y2)
+						g->p.y = g->p.y1;
+				}
+			}
+		#endif
+
+		// Only slightly better than drawing pixels is to look for runs and use fillarea
+		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS
+			// We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming.
+			#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+				if (gvmt(g)->fill)
+			#endif
+			{
+				if (!g->p.cx || g->p.color == color) {
+					g->p.cx++;
+					g->p.color = color;
+				} else {
+					if (g->p.cx == 1)
+						gdisp_lld_draw_pixel(g);
+					else
+						gdisp_lld_fill_area(g);
+					g->p.x += g->p.cx;
+					g->p.color = color;
+					g->p.cx = 1;
+				}
+				// Just wrap at end-of-line and end-of-buffer
+				if (g->p.x+g->p.cx >= g->p.x2) {
+					if (g->p.cx) {
+						if (g->p.cx == 1)
+							gdisp_lld_draw_pixel(g);
+						else
+							gdisp_lld_fill_area(g);
+						g->p.cx = 0;
+					}
+					g->p.x = g->p.x1;
+					if (++g->p.y >= g->p.y2)
+						g->p.y = g->p.y1;
+				}
+				return;
+			}
+		#endif
+
+		// Worst is using pixel drawing
+		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL
+			// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
+			//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+			//	if (gvmt(g)->pixel)
+			//#endif
+			{
+				g->p.color = color;
+				gdisp_lld_draw_pixel(g);
+
+				// Just wrap at end-of-line and end-of-buffer
+				if (++g->p.x >= g->p.x2) {
+					g->p.x = g->p.x1;
+					if (++g->p.y >= g->p.y2)
+						g->p.y = g->p.y1;
+				}
+				return;
+			}
+		#endif
+	}
+
+	void gdispGStreamStop(GDisplay *g) {
+		// Only release the mutex and end the stream if we are actually streaming.
+		if (!(g->flags & GDISP_FLG_INSTREAM))
+			return;
+
+		// Clear the flag
+		g->flags &= ~GDISP_FLG_INSTREAM;
+
+		// The cleanup below must match the streaming code above.
+
+		#if GDISP_HARDWARE_STREAM_WRITE
+			#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+				if (gvmt(g)->writestart)
+			#endif
+			{
+					gdisp_lld_write_stop(g);
+					autoflush_stopdone(g);
+					MUTEX_EXIT(g);
+					return;
+			}
+		#endif
+
+		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS
+			#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
+				if (gvmt(g)->blit)
+			#endif
+			{
+				if (g->p.cx) {
+					g->p.x1 = 0;
+					g->p.y1 = 0;
+					g->p.ptr = (void *)g->linebuf;
+					gdisp_lld_blit_area(g);
+				}
+				autoflush_stopdone(g);
+				MUTEX_EXIT(g);
+				return;
+			}
+		#endif
+
+		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS
+			// We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming.
+			#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+				if (gvmt(g)->fill)
+			#endif
+			{
+				if (g->p.cx) {
+					if (g->p.cx == 1)
+						gdisp_lld_draw_pixel(g);
+					else
+						gdisp_lld_fill_area(g);
+				}
+				autoflush_stopdone(g);
+				MUTEX_EXIT(g);
+				return;
+			}
+		#endif
+
+		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS != TRUE
+			{
+				autoflush_stopdone(g);
+				MUTEX_EXIT(g);
+			}
+		#endif
+	}
+#endif
+
+void gdispGDrawPixel(GDisplay *g, coord_t x, coord_t y, color_t color) {
+	MUTEX_ENTER(g);
+	g->p.x		= x;
+	g->p.y		= y;
+	g->p.color	= color;
+	drawpixel_clip(g);
+	autoflush(g);
+	MUTEX_EXIT(g);
+}
+
+void gdispGDrawLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) {
+	MUTEX_ENTER(g);
+	g->p.x = x0;
+	g->p.y = y0;
+	g->p.x1 = x1;
+	g->p.y1 = y1;
+	g->p.color = color;
+	line_clip(g);
+	autoflush(g);
+	MUTEX_EXIT(g);
+}
+
+void gdispGClear(GDisplay *g, color_t color) {
+	// Note - clear() ignores the clipping area. It clears the screen.
+	MUTEX_ENTER(g);
+
+	// Best is hardware accelerated clear
+	#if GDISP_HARDWARE_CLEARS
+		#if GDISP_HARDWARE_CLEARS == HARDWARE_AUTODETECT
+			if (gvmt(g)->clear)
+		#endif
+		{
+			g->p.color = color;
+			gdisp_lld_clear(g);
+			autoflush_stopdone(g);
+			MUTEX_EXIT(g);
+			return;
+		}
+	#endif
+
+	// Next best is hardware accelerated area fill
+	#if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS
+		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+			if (gvmt(g)->fill)
+		#endif
+		{
+			g->p.x = g->p.y = 0;
+			g->p.cx = g->g.Width;
+			g->p.cy = g->g.Height;
+			g->p.color = color;
+			gdisp_lld_fill_area(g);
+			autoflush_stopdone(g);
+			MUTEX_EXIT(g);
+			return;
+		}
+	#endif
+
+	// Next best is streaming
+	#if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
+		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+			if (gvmt(g)->writestart)
+		#endif
+		{
+			uint32_t	area;
+
+			g->p.x = g->p.y = 0;
+			g->p.cx = g->g.Width;
+			g->p.cy = g->g.Height;
+			g->p.color = color;
+			area = (uint32_t)g->p.cx * g->p.cy;
+
+			gdisp_lld_write_start(g);
+			#if GDISP_HARDWARE_STREAM_POS
+				#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
+					if (gvmt(g)->writepos)
+				#endif
+				gdisp_lld_write_pos(g);
+			#endif
+			for(; area; area--)
+				gdisp_lld_write_color(g);
+			gdisp_lld_write_stop(g);
+			autoflush_stopdone(g);
+			MUTEX_EXIT(g);
+			return;
+		}
+	#endif
+
+	// Worst is drawing pixels
+	#if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
+		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
+		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+		//	if (gvmt(g)->pixel)
+		//#endif
+		{
+			g->p.color = color;
+			for(g->p.y = 0; g->p.y < g->g.Height; g->p.y++)
+				for(g->p.x = 0; g->p.x < g->g.Width; g->p.x++)
+					gdisp_lld_draw_pixel(g);
+			autoflush_stopdone(g);
+			MUTEX_EXIT(g);
+			return;
+		}
+	#endif
+}
+
+void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
+	MUTEX_ENTER(g);
+	g->p.x = x;
+	g->p.y = y;
+	g->p.cx = cx;
+	g->p.cy = cy;
+	g->p.color = color;
+	TEST_CLIP_AREA(g) {
+		fillarea(g);
+	}
+	autoflush_stopdone(g);
+	MUTEX_EXIT(g);
+}
+
+void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
+	MUTEX_ENTER(g);
+
+	#if NEED_CLIPPING
+		#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+			if (!gvmt(g)->setclip)
+		#endif
+		{
+			// This is a different clipping to fillarea(g) as it needs to take into account srcx,srcy
+			if (x < g->clipx0) { cx -= g->clipx0 - x; srcx += g->clipx0 - x; x = g->clipx0; }
+			if (y < g->clipy0) { cy -= g->clipy0 - y; srcy += g->clipy0 - x; y = g->clipy0; }
+			if (x+cx > g->clipx1)	cx = g->clipx1 - x;
+			if (y+cy > g->clipy1)	cy = g->clipy1 - y;
+			if (srcx+cx > srccx) cx = srccx - srcx;
+			if (cx <= 0 || cy <= 0) { MUTEX_EXIT(g); return; }
+		}
+	#endif
+
+	// Best is hardware bitfills
+	#if GDISP_HARDWARE_BITFILLS
+		#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
+			if (gvmt(g)->blit)
+		#endif
+		{
+			g->p.x = x;
+			g->p.y = y;
+			g->p.cx = cx;
+			g->p.cy = cy;
+			g->p.x1 = srcx;
+			g->p.y1 = srcy;
+			g->p.x2 = srccx;
+			g->p.ptr = (void *)buffer;
+			gdisp_lld_blit_area(g);
+			autoflush_stopdone(g);
+			MUTEX_EXIT(g);
+			return;
+		}
+	#endif
+
+	// Next best is hardware streaming
+	#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
+		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+			if (gvmt(g)->writestart)
+		#endif
+		{
+			// Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap
+			buffer += srcy*srccx+srcx;
+			srcx = x + cx;
+			srcy = y + cy;
+			srccx -= cx;
+
+			g->p.x = x;
+			g->p.y = y;
+			g->p.cx = cx;
+			g->p.cy = cy;
+			gdisp_lld_write_start(g);
+			#if GDISP_HARDWARE_STREAM_POS
+				#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
+					if (gvmt(g)->writepos)
+				#endif
+				gdisp_lld_write_pos(g);
+			#endif
+			for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) {
+				for(g->p.x = x; g->p.x < srcx; g->p.x++) {
+					g->p.color = *buffer++;
+					gdisp_lld_write_color(g);
+				}
+			}
+			gdisp_lld_write_stop(g);
+			autoflush_stopdone(g);
+			MUTEX_EXIT(g);
+			return;
+		}
+	#endif
+
+	// Only slightly better than drawing pixels is to look for runs and use fill area
+	#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS
+		// We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming.
+		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+			if (gvmt(g)->fill)
+		#endif
+		{
+			// Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap
+			buffer += srcy*srccx+srcx;
+			srcx = x + cx;
+			srcy = y + cy;
+			srccx -= cx;
+
+			g->p.cy = 1;
+			for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) {
+				for(g->p.x=x; g->p.x < srcx; g->p.x += g->p.cx) {
+					g->p.cx=1;
+					g->p.color = *buffer++;
+					while(g->p.x+g->p.cx < srcx && *buffer == g->p.color) {
+						g->p.cx++;
+						buffer++;
+					}
+					if (g->p.cx == 1) {
+						gdisp_lld_draw_pixel(g);
+					} else {
+						gdisp_lld_fill_area(g);
+					}
+				}
+			}
+			autoflush_stopdone(g);
+			MUTEX_EXIT(g);
+			return;
+		}
+	#endif
+
+	// Worst is drawing pixels
+	#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL
+		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
+		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+		//	if (gvmt(g)->pixel)
+		//#endif
+		{
+			// Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap
+			buffer += srcy*srccx+srcx;
+			srcx = x + cx;
+			srcy = y + cy;
+			srccx -= cx;
+
+			for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) {
+				for(g->p.x=x; g->p.x < srcx; g->p.x++) {
+					g->p.color = *buffer++;
+					gdisp_lld_draw_pixel(g);
+				}
+			}
+			autoflush_stopdone(g);
+			MUTEX_EXIT(g);
+			return;
+		}
+	#endif
+}
+
+#if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION
+	void gdispGSetClip(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy) {
+		MUTEX_ENTER(g);
+
+		// Best is using hardware clipping
+		#if GDISP_HARDWARE_CLIP
+			#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+				if (gvmt(g)->setclip)
+			#endif
+			{
+				g->p.x = x;
+				g->p.y = y;
+				g->p.cx = cx;
+				g->p.cy = cy;
+				gdisp_lld_set_clip(g);
+			}
+			#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+				else
+			#endif
+		#endif
+
+		// Worst is using software clipping
+		#if GDISP_HARDWARE_CLIP != TRUE
+			{
+				if (x < 0) { cx += x; x = 0; }
+				if (y < 0) { cy += y; y = 0; }
+				if (cx <= 0 || cy <= 0 || x >= g->g.Width || y >= g->g.Height) { MUTEX_EXIT(g); return; }
+				g->clipx0 = x;
+				g->clipy0 = y;
+				g->clipx1 = x+cx;	if (g->clipx1 > g->g.Width) g->clipx1 = g->g.Width;
+				g->clipy1 = y+cy;	if (g->clipy1 > g->g.Height) g->clipy1 = g->g.Height;
+			}
+		#endif
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_CIRCLE
+	void gdispGDrawCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color) {
+		coord_t a, b, P;
+
+		MUTEX_ENTER(g);
+
+		// Calculate intermediates
+		a = 1;
+		b = radius;
+		P = 4 - radius;
+		g->p.color = color;
+
+		// Away we go using Bresenham's circle algorithm
+		// Optimized to prevent double drawing
+		g->p.x = x; g->p.y = y + b; drawpixel_clip(g);
+		g->p.x = x; g->p.y = y - b; drawpixel_clip(g);
+		g->p.x = x + b; g->p.y = y; drawpixel_clip(g);
+		g->p.x = x - b; g->p.y = y; drawpixel_clip(g);
+		do {
+			g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g);
+			g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g);
+			g->p.x = x + b; g->p.y = y + a; drawpixel_clip(g);
+			g->p.x = x - b; g->p.y = y + a; drawpixel_clip(g);
+			g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g);
+			g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g);
+			g->p.x = x + b; g->p.y = y - a; drawpixel_clip(g);
+			g->p.x = x - b; g->p.y = y - a; drawpixel_clip(g);
+			if (P < 0)
+				P += 3 + 2*a++;
+			else
+				P += 5 + 2*(a++ - b--);
+		} while(a < b);
+		g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g);
+		g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g);
+		g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g);
+		g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g);
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_CIRCLE
+	void gdispGFillCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color) {
+		coord_t a, b, P;
+
+		MUTEX_ENTER(g);
+
+		// Calculate intermediates
+		a = 1;
+		b = radius;
+		P = 4 - radius;
+		g->p.color = color;
+
+		// Away we go using Bresenham's circle algorithm
+		// This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value
+		g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
+		g->p.y = y+b; g->p.x = x; drawpixel_clip(g);
+		g->p.y = y-b; g->p.x = x; drawpixel_clip(g);
+		do {
+			g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
+			g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
+			if (P < 0) {
+				P += 3 + 2*a++;
+			} else {
+				g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);
+				g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);
+				P += 5 + 2*(a++ - b--);
+			}
+		} while(a < b);
+		g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
+		g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_ELLIPSE
+	void gdispGDrawEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
+		coord_t	dx, dy;
+		int32_t	a2, b2;
+		int32_t	err, e2;
+
+		MUTEX_ENTER(g);
+
+		// Calculate intermediates
+		dx = 0;
+		dy = b;
+		a2 = a*a;
+		b2 = b*b;
+		err = b2-(2*b-1)*a2;
+		g->p.color = color;
+
+		// Away we go using Bresenham's ellipse algorithm
+		do {
+			g->p.x = x + dx; g->p.y = y + dy; drawpixel_clip(g);
+			g->p.x = x - dx; g->p.y = y + dy; drawpixel_clip(g);
+			g->p.x = x - dx; g->p.y = y - dy; drawpixel_clip(g);
+			g->p.x = x + dx; g->p.y = y - dy; drawpixel_clip(g);
+
+			e2 = 2*err;
+			if(e2 <  (2*dx+1)*b2) {
+				dx++;
+				err += (2*dx+1)*b2;
+			}
+			if(e2 > -(2*dy-1)*a2) {
+				dy--;
+				err -= (2*dy-1)*a2;
+			}
+		} while(dy >= 0);
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_ELLIPSE
+	void gdispGFillEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
+		coord_t	dx, dy;
+		int32_t	a2, b2;
+		int32_t	err, e2;
+
+		MUTEX_ENTER(g);
+
+		// Calculate intermediates
+		dx = 0;
+		dy = b;
+		a2 = a*a;
+		b2 = b*b;
+		err = b2-(2*b-1)*a2;
+		g->p.color = color;
+
+		// Away we go using Bresenham's ellipse algorithm
+		// This is optimized to prevent overdrawing by drawing a line only when a y is about to change value
+		do {
+			e2 = 2*err;
+			if(e2 <  (2*dx+1)*b2) {
+				dx++;
+				err += (2*dx+1)*b2;
+			}
+			if(e2 > -(2*dy-1)*a2) {
+				g->p.y = y + dy; g->p.x = x - dx; g->p.x1 = x + dx; hline_clip(g);
+				if (y) { g->p.y = y - dy; g->p.x = x - dx; g->p.x1 = x + dx; hline_clip(g); }
+				dy--;
+				err -= (2*dy-1)*a2;
+			}
+		} while(dy >= 0);
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_ARCSECTORS
+	void gdispGDrawArcSectors(GDisplay *g, coord_t x, coord_t y, coord_t radius, uint8_t sectors, color_t color) {
+		coord_t a, b, P;
+
+		MUTEX_ENTER(g);
+
+		// Calculate intermediates
+		a = 1;              // x in many explanations
+		b = radius;         // y in many explanations
+		P = 4 - radius;
+		g->p.color = color;
+
+		// Away we go using Bresenham's circle algorithm
+		// Optimized to prevent double drawing
+		if (sectors & 0x06) { g->p.x = x; g->p.y = y - b; drawpixel_clip(g); }				// Upper upper
+		if (sectors & 0x60) { g->p.x = x; g->p.y = y + b; drawpixel_clip(g); }				// Lower lower
+		if (sectors & 0x81) { g->p.x = x + b; g->p.y = y; drawpixel_clip(g); }				// Right right
+		if (sectors & 0x18) { g->p.x = x - b; g->p.y = y; drawpixel_clip(g); }				// Left left
+
+		do {
+			if (sectors & 0x01) { g->p.x = x + b; g->p.y = y - a; drawpixel_clip(g); }		// Upper right right
+			if (sectors & 0x02) { g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g); }		// Upper upper right
+			if (sectors & 0x04) { g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g); }		// Upper upper left
+			if (sectors & 0x08) { g->p.x = x - b; g->p.y = y - a; drawpixel_clip(g); }		// Upper left  left
+			if (sectors & 0x10) { g->p.x = x - b; g->p.y = y + a; drawpixel_clip(g); }		// Lower left  left
+			if (sectors & 0x20) { g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g); }		// Lower lower left
+			if (sectors & 0x40) { g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g); }		// Lower lower right
+			if (sectors & 0x80) { g->p.x = x + b; g->p.y = y + a; drawpixel_clip(g); }		// Lower right right
+			if (P < 0)
+				P += 3 + 2*a++;
+			else
+				P += 5 + 2*(a++ - b--);
+		} while(a < b);
+
+		if (sectors & 0xC0) { g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g); }			// Lower right
+		if (sectors & 0x03) { g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g); }			// Upper right
+		if (sectors & 0x30) { g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g); }			// Lower left
+		if (sectors & 0x0C) { g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g); }			// Upper left
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_ARCSECTORS
+	void gdispGFillArcSectors(GDisplay *g, coord_t x, coord_t y, coord_t radius, uint8_t sectors, color_t color) {
+		coord_t a, b, P;
+
+		MUTEX_ENTER(g);
+
+		// Calculate intermediates
+		a = 1;              // x in many explanations
+		b = radius;         // y in many explanations
+		P = 4 - radius;
+		g->p.color = color;
+
+		// Away we go using Bresenham's circle algorithm
+		// Optimized to prevent double drawing
+		if (sectors & 0x06) { g->p.x = x; g->p.y = y - b; drawpixel_clip(g); }					// Upper upper
+		if (sectors & 0x60) { g->p.x = x; g->p.y = y + b; drawpixel_clip(g); }					// Lower lower
+		if (sectors & 0x81) {																	// Center right
+			g->p.y = y; g->p.x = x; g->p.x1 = x + b;
+			if (sectors & 0x18) g->p.x -= b;													// Left right
+			hline_clip(g);
+		} else if (sectors & 0x18) {															// Left center
+			g->p.x = x - b; g->p.x1 = x; g->p.y = y;
+			hline_clip(g);
+		}
+
+		do {
+			// Top half
+			switch(sectors & 0x0F) {
+			case 0x01:
+				g->p.y = y - a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x02:
+				g->p.y = y - b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				break;
+			case 0x03:
+				g->p.y = y - b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x04:
+				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				break;
+			case 0x05:
+				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y - a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x06:
+				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				break;
+			case 0x07:
+				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x08:
+				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
+				break;
+			case 0x09:
+				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0A:
+				g->p.y = y - b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				break;
+			case 0x0B:
+				g->p.y = y - b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0C:
+				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x; hline_clip(g);
+				break;
+			case 0x0D:
+				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x; hline_clip(g);
+				g->p.y = y - a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0E:
+				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x + a; hline_clip(g);
+				break;
+			case 0x0F:
+				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x + b; hline_clip(g);
+				break;
+			}
+
+			// Bottom half
+			switch((sectors & 0xF0)>>4) {
+			case 0x01:
+				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
+				break;
+			case 0x02:
+				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				break;
+			case 0x03:
+				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x; hline_clip(g);
+				break;
+			case 0x04:
+				g->p.y = y + b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				break;
+			case 0x05:
+				g->p.y = y + b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				break;
+			case 0x06:
+				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				break;
+			case 0x07:
+				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x + a; hline_clip(g);
+				break;
+			case 0x08:
+				g->p.y = y + a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x09:
+				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0A:
+				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y + a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0B:
+				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x; hline_clip(g);
+				g->p.y = y + a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0C:
+				g->p.y = y + b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0D:
+				g->p.y = y + b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0E:
+				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - a; g->p.x1 = x + b; hline_clip(g);
+				break;
+			case 0x0F:
+				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
+				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x + b; hline_clip(g);
+				break;
+			}
+
+			if (P < 0)
+				P += 3 + 2*a++;
+			else
+				P += 5 + 2*(a++ - b--);
+		} while(a < b);
+
+		// Top half
+		if (sectors & 0x02)			{ g->p.y = y - a; g->p.x = x; g->p.x1 = x + a; hline_clip(g); }
+		else if (sectors & 0x01)	{ g->p.y = y - a; g->p.x = x + a; drawpixel_clip(g); }
+		if (sectors & 0x04)			{ g->p.y = y - a; g->p.x = x - a; g->p.x1 = x; hline_clip(g); }
+		else if (sectors & 0x08)	{ g->p.y = y - a; g->p.x = x - a; drawpixel_clip(g); }
+
+		// Bottom half
+		if (sectors & 0x40)			{ g->p.y = y + a; g->p.x = x; g->p.x1 = x + a; hline_clip(g); }
+		else if (sectors & 0x80)	{ g->p.y = y + a; g->p.x = x + a; drawpixel_clip(g); }
+		if (sectors & 0x20)			{ g->p.y = y + a; g->p.x = x - a; g->p.x1 = x; hline_clip(g); }
+		else if (sectors & 0x10)	{ g->p.y = y + a; g->p.x = x - a; drawpixel_clip(g); }
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_ARC
+	#if (!GMISC_NEED_FIXEDTRIG && !GMISC_NEED_FASTTRIG) || !GFX_USE_GMISC
+		#include <math.h>
+	#endif
+
+	void gdispGDrawArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
+		coord_t a, b, P, sedge, eedge;
+		uint8_t	full, sbit, ebit, tbit;
+
+		// Normalize the angles
+		if (start < 0)
+			start -= (start/360-1)*360;
+		else if (start >= 360)
+			start %= 360;
+		if (end < 0)
+			end -= (end/360-1)*360;
+		else if (end >= 360)
+			end %= 360;
+
+		sbit = 1<<(start/45);
+		ebit = 1<<(end/45);
+		full = 0;
+		if (start == end) {
+			full = 0xFF;
+		} else if (end < start) {
+			for(tbit=sbit<<1; tbit; tbit<<=1) full |= tbit;
+			for(tbit=ebit>>1; tbit; tbit>>=1) full |= tbit;
+		} else if (sbit < 0x80) {
+			for(tbit=sbit<<1; tbit < ebit; tbit<<=1) full |= tbit;
+		}
+		tbit = start%45 == 0 ? sbit : 0;
+
+		MUTEX_ENTER(g);
+		g->p.color = color;
+
+		if (full) {
+			// Draw full sectors
+			// Optimized to prevent double drawing
+			a = 1;
+			b = radius;
+			P = 4 - radius;
+			if (full & 0x60) { g->p.y = y+b; g->p.x = x; drawpixel_clip(g); }
+			if (full & 0x06) { g->p.y = y-b; g->p.x = x; drawpixel_clip(g); }
+			if (full & 0x81) { g->p.y = y; g->p.x = x+b; drawpixel_clip(g); }
+			if (full & 0x18) { g->p.y = y; g->p.x = x-b; drawpixel_clip(g); }
+			do {
+				if (full & 0x01) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); }
+				if (full & 0x02) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
+				if (full & 0x04) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
+				if (full & 0x08) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); }
+				if (full & 0x10) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); }
+				if (full & 0x20) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
+				if (full & 0x40) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
+				if (full & 0x80) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); }
+				if (P < 0)
+					P += 3 + 2*a++;
+				else
+					P += 5 + 2*(a++ - b--);
+			} while(a < b);
+			if (full & 0xC0) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
+			if (full & 0x0C) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
+			if (full & 0x03) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
+			if (full & 0x30) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
+			if (full == 0xFF) {
+				autoflush(g);
+				MUTEX_EXIT(g);
+				return;
+			}
+		}
+
+		#if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG
+			sedge = NONFIXED(radius * ((sbit & 0x99) ? ffsin(start) : ffcos(start)) + FIXED0_5);
+			eedge = NONFIXED(radius * ((ebit & 0x99) ? ffsin(end) : ffcos(end)) + FIXED0_5);
+		#elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG
+			sedge = round(radius * ((sbit & 0x99) ? fsin(start) : fcos(start)));
+			eedge = round(radius * ((ebit & 0x99) ? fsin(end) : fcos(end)));
+		#else
+			sedge = round(radius * ((sbit & 0x99) ? sin(start*M_PI/180) : cos(start*M_PI/180)));
+			eedge = round(radius * ((ebit & 0x99) ? sin(end*M_PI/180) : cos(end*M_PI/180)));
+		#endif
+		if (sbit & 0xB4) sedge = -sedge;
+		if (ebit & 0xB4) eedge = -eedge;
+
+		if (sbit != ebit) {
+			// Draw start and end sectors
+			// Optimized to prevent double drawing
+			a = 1;
+			b = radius;
+			P = 4 - radius;
+			if ((sbit & 0x20) || (tbit & 0x40) || (ebit & 0x40)) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); }
+			if ((sbit & 0x02) || (tbit & 0x04) || (ebit & 0x04)) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); }
+			if ((sbit & 0x80) || (tbit & 0x01) || (ebit & 0x01)) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); }
+			if ((sbit & 0x08) || (tbit & 0x10) || (ebit & 0x10)) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); }
+			do {
+				if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); }
+				if (((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
+				if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
+				if (((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); }
+				if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); }
+				if (((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
+				if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
+				if (((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); }
+				if (P < 0)
+					P += 3 + 2*a++;
+				else
+					P += 5 + 2*(a++ - b--);
+			} while(a < b);
+			if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge) || ((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge))
+				{ g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
+			if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge) || ((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge))
+				{ g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
+			if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge) || ((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge))
+				{ g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
+			if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge) || ((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge))
+				{ g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
+		} else if (end < start) {
+			// Draw start/end sector where it is a non-internal angle
+			// Optimized to prevent double drawing
+			a = 1;
+			b = radius;
+			P = 4 - radius;
+			if ((sbit & 0x60) || (tbit & 0xC0)) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); }
+			if ((sbit & 0x06) || (tbit & 0x0C)) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); }
+			if ((sbit & 0x81) || (tbit & 0x03)) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); }
+			if ((sbit & 0x18) || (tbit & 0x30)) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); }
+			do {
+				if ((sbit & 0x01) && (a >= sedge || a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); }
+				if ((sbit & 0x02) && (a <= sedge || a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
+				if ((sbit & 0x04) && (a >= sedge || a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
+				if ((sbit & 0x08) && (a <= sedge || a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); }
+				if ((sbit & 0x10) && (a >= sedge || a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); }
+				if ((sbit & 0x20) && (a <= sedge || a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
+				if ((sbit & 0x40) && (a >= sedge || a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
+				if ((sbit & 0x80) && (a <= sedge || a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); }
+				if (P < 0)
+					P += 3 + 2*a++;
+				else
+					P += 5 + 2*(a++ - b--);
+			} while(a < b);
+			if (((sbit & 0x04) && (a >= sedge || a <= eedge)) || ((sbit & 0x08) && (a <= sedge || a >= eedge)))
+				{ g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
+			if (((sbit & 0x40) && (a >= sedge || a <= eedge)) || ((sbit & 0x80) && (a <= sedge || a >= eedge)))
+				{ g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
+			if (((sbit & 0x01) && (a >= sedge || a <= eedge)) || ((sbit & 0x02) && (a <= sedge || a >= eedge)))
+				{ g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
+			if (((sbit & 0x10) && (a >= sedge || a <= eedge)) || ((sbit & 0x20) && (a <= sedge || a >= eedge)))
+				{ g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
+		} else {
+			// Draw start/end sector where it is a internal angle
+			// Optimized to prevent double drawing
+			a = 1;
+			b = radius;
+			P = 4 - radius;
+			if (((sbit & 0x20) && !eedge) || ((sbit & 0x40) && !sedge)) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); }
+			if (((sbit & 0x02) && !eedge) || ((sbit & 0x04) && !sedge)) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); }
+			if (((sbit & 0x80) && !eedge) || ((sbit & 0x01) && !sedge)) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); }
+			if (((sbit & 0x08) && !eedge) || ((sbit & 0x10) && !sedge)) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); }
+			do {
+				if (((sbit & 0x01) && a >= sedge && a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); }
+				if (((sbit & 0x02) && a <= sedge && a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
+				if (((sbit & 0x04) && a >= sedge && a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
+				if (((sbit & 0x08) && a <= sedge && a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); }
+				if (((sbit & 0x10) && a >= sedge && a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); }
+				if (((sbit & 0x20) && a <= sedge && a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
+				if (((sbit & 0x40) && a >= sedge && a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
+				if (((sbit & 0x80) && a <= sedge && a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); }
+				if (P < 0)
+					P += 3 + 2*a++;
+				else
+					P += 5 + 2*(a++ - b--);
+			} while(a < b);
+			if (((sbit & 0x04) && a >= sedge && a <= eedge) || ((sbit & 0x08) && a <= sedge && a >= eedge))
+				{ g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
+			if (((sbit & 0x40) && a >= sedge && a <= eedge) || ((sbit & 0x80) && a <= sedge && a >= eedge))
+				{ g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
+			if (((sbit & 0x01) && a >= sedge && a <= eedge) || ((sbit & 0x02) && a <= sedge && a >= eedge))
+				{ g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
+			if (((sbit & 0x10) && a >= sedge && a <= eedge) || ((sbit & 0x20) && a <= sedge && a >= eedge))
+				{ g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
+		}
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_ARC
+	void gdispGFillArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
+		coord_t a, b, P;
+		coord_t	sy, ey;
+		fixed	sxa, sxb, sxd, exa, exb, exd;
+		uint8_t	qtr;
+
+		MUTEX_ENTER(g);
+
+		// Do the trig to get the formulas for the start and end lines.
+		sxa = exa = FIXED(x)+FIXED0_5;
+		#if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG
+			sxb = radius*ffcos(start);	sy = -NONFIXED(radius*ffsin(start) + FIXED0_5);
+			exb = radius*ffcos(end);	ey = -NONFIXED(radius*ffsin(end) + FIXED0_5);
+		#elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG
+			sxb = FP2FIXED(radius*fcos(start));	sy = -round(radius*fsin(start));
+			exb = FP2FIXED(radius*fcos(end));	ey = -round(radius*fsin(end));
+		#else
+			sxb = FP2FIXED(radius*cos(start*M_PI/180));	sy = -round(radius*sin(start*M_PI/180));
+			exb = FP2FIXED(radius*cos(end*M_PI/180));	ey = -round(radius*sin(end*M_PI/180));
+		#endif
+		sxd = sy ? sxb/sy : sxb;
+		exd = ey ? exb/ey : exb;
+
+		// Calculate which quarters and which direction we are traveling
+		qtr = 0;
+		if (sxb > 0)	qtr |= 0x01;		// S1=0001(1), S2=0000(0), S3=0010(2), S4=0011(3)
+		if (sy > 0) 	qtr |= 0x02;
+		if (exb > 0)	qtr |= 0x04;		// E1=0100(4), E2=0000(0), E3=1000(8), E4=1100(12)
+		if (ey > 0) 	qtr |= 0x08;
+		if (sy > ey)	qtr |= 0x10;		// order of start and end lines
+
+		// Calculate intermediates
+		a = 1;
+		b = radius;
+		P = 4 - radius;
+		g->p.color = color;
+		sxb += sxa;
+		exb += exa;
+
+		// Away we go using Bresenham's circle algorithm
+		// This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value
+
+		switch(qtr) {
+		case 0:		// S2E2 sy <= ey
+		case 1:		// S1E2 sy <= ey
+			if (ey && sy) {
+				g->p.x = x; g->p.x1 = x;									// E2S
+				sxa -= sxd; exa -= exd;
+			} else if (sy) {
+				g->p.x = x-b; g->p.x1 = x;								// C2S
+				sxa -= sxd;
+			} else if (ey) {
+				g->p.x = x; g->p.x1 = x+b;								// E2C
+				exa -= exd;
+			} else {
+				g->p.x = x-b; g->p.x1 = x+b;								// C2C
+			}
+			g->p.y = y;
+			hline_clip(g);
+			do {
+				if (-a >= ey) {
+					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g);		// E2S
+					sxa -= sxd; exa -= exd;
+				} else if (-a >= sy) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
+					sxa -= sxd;
+				} else if (qtr & 1) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= ey) {
+						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = NONFIXED(sxb); hline_clip(g);	// E2S
+						sxb += sxd; exb += exd;
+					} else if (-b >= sy) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);			// C2S
+						sxb += sxd;
+					} else if (qtr & 1) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= ey) {
+				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g);			// E2S
+			} else if (-a >= sy) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);					// C2S
+			} else if (qtr & 1) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+			}
+			break;
+
+		case 2:		// S3E2 sy <= ey
+		case 3:		// S4E2 sy <= ey
+		case 6:		// S3E1 sy <= ey
+		case 7:		// S4E1 sy <= ey
+		case 18:	// S3E2 sy > ey
+		case 19:	// S4E2 sy > ey
+		case 22:	// S3E1 sy > ey
+		case 23:	// S4E1 sy > ey
+			g->p.y = y; g->p.x = x; g->p.x1 = x+b; hline_clip(g);								// SE2C
+			sxa += sxd; exa -= exd;
+			do {
+				if (-a >= ey) {
+					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);		// E2C
+					exa -= exd;
+				} else if (!(qtr & 4)) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);					// C2C
+				}
+				if (a <= sy) {
+					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);		// S2C
+					sxa += sxd;
+				} else if (!(qtr & 1)) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);					// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= ey) {
+						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);		// E2C
+						exb += exd;
+					} else if (!(qtr & 4)) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);					// C2C
+					}
+					if (b <= sy) {
+						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);		// S2C
+						sxb -= sxd;
+					} else if (!(qtr & 1)) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); 				// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= ey) {
+				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
+			} else if (!(qtr & 4)) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+			}
+			if (a <= sy) {
+				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+a; hline_clip(g);				// S2C
+			} else if (!(qtr & 1)) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+a; hline_clip(g);							// C2C
+			}
+			break;
+
+		case 4:		// S2E1 sy <= ey
+		case 5:		// S1E1 sy <= ey
+			g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
+			do {
+				if (-a >= ey) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
+					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
+					sxa -= sxd; exa -= exd;
+				} else if (-a >= sy) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
+					sxa -= sxd;
+				} else if (qtr & 1) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+				}
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= ey) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);			// C2S
+						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);			// E2C
+						sxb += sxd; exb += exd;
+					} else if (-b >= sy) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);			// C2S
+						sxb += sxd;
+					} else if (qtr & 1) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
+					}
+					g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);							// C2C
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= ey) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);					// C2S
+				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);					// E2C
+			} else if (-a >= sy) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);					// C2S
+			} else if (qtr & 1) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+			}
+			g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);									// C2C
+			break;
+
+		case 8:		// S2E3 sy <= ey
+		case 9:		// S1E3 sy <= ey
+		case 12:	// S2E4 sy <= ey
+		case 13:	// S1E4 sy <= ey
+		case 24:	// S2E3 sy > ey
+		case 25:	// S1E3 sy > ey
+		case 28:	// S2E3 sy > ey
+		case 29:	// S1E3 sy > ey
+			g->p.y = y; g->p.x = x-b; g->p.x1 = x; hline_clip(g);								// C2SE
+			sxa -= sxd; exa += exd;
+			do {
+				if (-a >= sy) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);		// C2S
+					sxa -= sxd;
+				} else if (qtr & 1) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);					// C2C
+				}
+				if (a <= ey) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);		// C2E
+					exa += exd;
+				} else if (qtr & 4) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);					// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= sy) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);		// C2S
+						sxb += sxd;
+					} else if (qtr & 1) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);					// C2C
+					}
+					if (b <= ey) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);		// C2E
+						exb -= exd;
+					} else if (qtr & 4) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); 				// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= sy) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
+			} else if (qtr & 1) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+			}
+			if (a <= ey) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
+			} else if (qtr & 4) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+a; hline_clip(g);							// C2C
+			}
+			break;
+
+		case 10:	// S3E3 sy <= ey
+		case 14:	// S3E4 sy <= ey
+			g->p.y = y; g->p.x = x; drawpixel_clip(g);													// S2E
+			sxa += sxd; exa += exd;
+			do {
+				if (a <= sy) {
+					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g);		// S2E
+					sxa += sxd; exa += exd;
+				} else if (a <= ey) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
+					exa += exd;
+				} else if (qtr & 4) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (b <= sy) {
+						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = NONFIXED(exb); hline_clip(g);		// S2E
+						sxb -= sxd; exb -= exd;
+					} else if (b <= ey) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);				// C2E
+						exb -= exd;
+					} else if (qtr & 4) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);							// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (a <= sy) {
+				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g);		// S2E
+			} else if (a <= ey) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
+			} else if (qtr & 4) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+			}
+			break;
+
+		case 11:	// S4E3 sy <= ey
+		case 15:	// S4E4 sy <= ey
+			g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
+			do {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+				if (a <= sy) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
+					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
+					sxa += sxd; exa += exd;
+				} else if (a <= ey) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
+					exa += exd;
+				} else if (qtr & 4) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);							// C2C
+					if (b <= sy) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);			// C2E
+						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);			// S2C
+						sxb -= sxd; exb -= exd;
+					} else if (b <= ey) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);			// C2E
+						exb -= exd;
+					} else if (qtr & 4) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
+			if (a <= sy) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);					// C2E
+				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);					// S2C
+			} else if (a <= ey) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);					// C2E
+			} else if (qtr & 4) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+			}
+			break;
+
+		case 16:	// S2E2	sy > ey
+		case 20:	// S2E1 sy > ey
+			g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
+			sxa -= sxd; exa -= exd;
+			do {
+				if (-a >= sy) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
+					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
+					sxa -= sxd; exa -= exd;
+				} else if (-a >= ey) {
+					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
+					exa -= exd;
+				} else if (!(qtr & 4)){
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); 						// C2C
+				}
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); 							// C2C
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= sy) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);			// C2S
+						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);			// E2C
+						sxb += sxd; exb += exd;
+					} else if (-b >= ey) {
+						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);			// E2C
+						exb += exd;
+					} else if (!(qtr & 4)){
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); 					// C2C
+					}
+					g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); 						// C2C
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= sy) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);					// C2S
+				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);					// E2C
+			} else if (-a >= ey) {
+				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);					// E2C
+			} else if (!(qtr & 4)){
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); 							// C2C
+			}
+			g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); 								// C2C
+			break;
+
+		case 17:	// S1E2 sy > ey
+		case 21:	// S1E1 sy > ey
+			if (sy) {
+				g->p.x = x; g->p.x1 = x;																// E2S
+				sxa -= sxd; exa -= exd;
+			} else {
+				g->p.x = x; g->p.x1 = x+b;															// E2C
+				exa -= exd;
+			}
+			g->p.y = y;
+			hline_clip(g);
+			do {
+				if (-a >= sy) {
+					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g);		// E2S
+					sxa -= sxd; exa -= exd;
+				} else if (-a >= ey) {
+					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
+					exa -= exd;
+				} else if (!(qtr & 4)) {
+					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (-b >= sy) {
+						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = NONFIXED(sxb); hline_clip(g);	// E2S
+						sxb += sxd; exb += exd;
+					} else if (-b >= ey) {
+						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);			// E2C
+						exb += exd;
+					} else if (!(qtr & 4)) {
+						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (-a >= sy) {
+				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g);			// E2S
+			} else if (-a >= ey) {
+				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);					// E2C
+			} else if (!(qtr & 4)) {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+			}
+			break;
+
+		case 26:	// S3E3 sy > ey
+		case 27:	// S4E3 sy > ey
+			g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
+			do {
+				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+				if (a <= ey) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
+					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
+					sxa += sxd; exa += exd;
+				} else if (a <= sy) {
+					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
+					sxa += sxd;
+				} else if (!(qtr & 1)) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);							// C2C
+					if (b <= ey) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);			// C2E
+						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);			// S2C
+						sxb -= sxd; exb -= exd;
+					} else if (b <= sy) {
+						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);			// S2C
+						sxb -= sxd;
+					} else if (!(qtr & 1)) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
+			if (a <= ey) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);					// C2E
+				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);					// S2C
+			} else if (a <= sy) {
+				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);					// S2C
+			} else if (!(qtr & 4)) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+			}
+			break;
+
+		case 30:	// S3E4 sy > ey
+		case 31:	// S4E4 sy > ey
+			do {
+				if (a <= ey) {
+					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g);		// S2E
+					sxa += sxd; exa += exd;
+				} else if (a <= sy) {
+					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
+					sxa += sxd;
+				} else if (!(qtr & 1)) {
+					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
+				}
+				if (P < 0) {
+					P += 3 + 2*a++;
+				} else {
+					if (b <= ey) {
+						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = NONFIXED(exb); hline_clip(g);	// S2E
+						sxb -= sxd; exb -= exd;
+					} else if (b <= sy) {
+						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);			// S2C
+						sxb -= sxd;
+					} else if (!(qtr & 1)) {
+						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
+					}
+					P += 5 + 2*(a++ - b--);
+				}
+			} while(a < b);
+			if (a <= ey) {
+				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
+			} else if (a <= sy) {
+				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);					// S2C
+			} else if (!(qtr & 4)) {
+				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
+			}
+			break;
+		}
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_ARC || GDISP_NEED_ARCSECTORS
+	void gdispGDrawRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
+		if (2*radius > cx || 2*radius > cy) {
+			gdispGDrawBox(g, x, y, cx, cy, color);
+			return;
+		}
+
+		#if GDISP_NEED_ARCSECTORS
+			gdispGDrawArcSectors(g, x+radius, y+radius, radius, 0x0C, color);
+			gdispGDrawArcSectors(g, x+cx-1-radius, y+radius, radius, 0x03, color);
+			gdispGDrawArcSectors(g, x+cx-1-radius, y+cy-1-radius, radius, 0xC0, color);
+			gdispGDrawArcSectors(g, x+radius, y+cy-1-radius, radius, 0x30, color);
+		#else
+			gdispGDrawArc(g, x+radius, y+radius, radius, 90, 180, color);
+			gdispGDrawArc(g, x+cx-1-radius, y+radius, radius, 0, 90, color);
+			gdispGDrawArc(g, x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
+			gdispGDrawArc(g, x+radius, y+cy-1-radius, radius, 180, 270, color);
+		#endif
+		gdispGDrawLine(g, x+radius+1, y, x+cx-2-radius, y, color);
+		gdispGDrawLine(g, x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color);
+		gdispGDrawLine(g, x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color);
+		gdispGDrawLine(g, x, y+radius+1, x, y+cy-2-radius, color);
+	}
+#endif
+
+#if GDISP_NEED_ARC || GDISP_NEED_ARCSECTORS
+	void gdispGFillRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
+		coord_t radius2;
+
+		radius2 = radius*2;
+		if (radius2 > cx || radius2 > cy) {
+			gdispGFillArea(g, x, y, cx, cy, color);
+			return;
+		}
+		#if GDISP_NEED_ARCSECTORS
+			gdispGFillArcSectors(g, x+radius, y+radius, radius, 0x0C, color);
+			gdispGFillArcSectors(g, x+cx-1-radius, y+radius, radius, 0x03, color);
+			gdispGFillArcSectors(g, x+cx-1-radius, y+cy-1-radius, radius, 0xC0, color);
+			gdispGFillArcSectors(g, x+radius, y+cy-1-radius, radius, 0x30, color);
+		#else
+			gdispGFillArc(g, x+radius, y+radius, radius, 90, 180, color);
+			gdispGFillArc(g, x+cx-1-radius, y+radius, radius, 0, 90, color);
+			gdispGFillArc(g, x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
+			gdispGFillArc(g, x+radius, y+cy-1-radius, radius, 180, 270, color);
+		#endif
+		gdispGFillArea(g, x+radius+1, y, cx-radius2, radius, color);
+		gdispGFillArea(g, x+radius+1, y+cy-radius, cx-radius2, radius, color);
+		gdispGFillArea(g, x, y+radius, cx, cy-radius2, color);
+	}
+#endif
+
+#if GDISP_NEED_PIXELREAD
+	color_t gdispGGetPixelColor(GDisplay *g, coord_t x, coord_t y) {
+		color_t		c;
+
+		/* Always synchronous as it must return a value */
+		MUTEX_ENTER(g);
+		#if GDISP_HARDWARE_PIXELREAD
+			#if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT
+				if (gvmt(g)->get)
+			#endif
+			{
+				// Best is direct pixel read
+				g->p.x = x;
+				g->p.y = y;
+				c = gdisp_lld_get_pixel_color(g);
+				MUTEX_EXIT(g);
+				return c;
+			}
+		#endif
+		#if GDISP_HARDWARE_PIXELREAD != TRUE && GDISP_HARDWARE_STREAM_READ
+			#if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT
+				if (gvmt(g)->readcolor)
+			#endif
+			{
+				// Next best is hardware streaming
+				g->p.x = x;
+				g->p.y = y;
+				g->p.cx = 1;
+				g->p.cy = 1;
+				gdisp_lld_read_start(g);
+				c = gdisp_lld_read_color(g);
+				gdisp_lld_read_stop(g);
+				MUTEX_EXIT(g);
+				return c;
+			}
+		#endif
+		#if GDISP_HARDWARE_PIXELREAD != TRUE && GDISP_HARDWARE_STREAM_READ != TRUE
+			#if !GDISP_HARDWARE_PIXELREAD && !GDISP_HARDWARE_STREAM_READ
+				// Worst is "not possible"
+				#error "GDISP: GDISP_NEED_PIXELREAD has been set but there is no hardware support for reading the display"
+			#endif
+			MUTEX_EXIT(g);
+			return 0;
+		#endif
+	}
+#endif
+
+#if GDISP_NEED_SCROLL
+	void gdispGVerticalScroll(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) {
+		coord_t		abslines;
+		#if GDISP_HARDWARE_SCROLL != TRUE
+			coord_t 	fy, dy, ix, fx, i, j;
+		#endif
+
+		MUTEX_ENTER(g);
+		#if NEED_CLIPPING
+			#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+				if (!gvmt(g)->setclip)
+			#endif
+			{
+				if (x < g->clipx0) { cx -= g->clipx0 - x; x = g->clipx0; }
+				if (y < g->clipy0) { cy -= g->clipy0 - y; y = g->clipy0; }
+				if (!lines || cx <= 0 || cy <= 0 || x >= g->clipx1 || y >= g->clipy1) { MUTEX_EXIT(g); return; }
+				if (x+cx > g->clipx1)	cx = g->clipx1 - x;
+				if (y+cy > g->clipy1)	cy = g->clipy1 - y;
+			}
+		#endif
+
+		abslines = lines < 0 ? -lines : lines;
+		if (abslines >= cy) {
+			abslines = cy;
+			cy = 0;
+		} else {
+			// Best is hardware scroll
+			#if GDISP_HARDWARE_SCROLL
+				#if GDISP_HARDWARE_SCROLL == HARDWARE_AUTODETECT
+					if (gvmt(g)->vscroll)
+				#endif
+				{
+					g->p.x = x;
+					g->p.y = y;
+					g->p.cx = cx;
+					g->p.cy = cy;
+					g->p.y1 = lines;
+					g->p.color = bgcolor;
+					gdisp_lld_vertical_scroll(g);
+					cy -= abslines;
+				}
+				#if GDISP_HARDWARE_SCROLL == HARDWARE_AUTODETECT
+					else
+				#endif
+			#elif GDISP_LINEBUF_SIZE == 0
+				#error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support and GDISP_LINEBUF_SIZE is zero."
+			#endif
+
+			// Scroll Emulation
+			#if GDISP_HARDWARE_SCROLL != TRUE
+				{
+					cy -= abslines;
+					if (lines < 0) {
+						fy = y+cy-1;
+						dy = -1;
+					} else {
+						fy = y;
+						dy = 1;
+					}
+					// Move the screen - one line at a time
+					for(i = 0; i < cy; i++, fy += dy) {
+
+						// Handle where the buffer is smaller than a line
+						for(ix=0; ix < cx; ix += GDISP_LINEBUF_SIZE) {
+
+							// Calculate the data we can move in one operation
+							fx = cx - ix;
+							if (fx > GDISP_LINEBUF_SIZE)
+								fx = GDISP_LINEBUF_SIZE;
+
+							// Read one line of data from the screen
+
+							// Best line read is hardware streaming
+							#if GDISP_HARDWARE_STREAM_READ
+								#if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT
+									if (gvmt(g)->readstart)
+								#endif
+								{
+									g->p.x = x+ix;
+									g->p.y = fy+lines;
+									g->p.cx = fx;
+									g->p.cy = 1;
+									gdisp_lld_read_start(g);
+									for(j=0; j < fx; j++)
+										g->linebuf[j] = gdisp_lld_read_color(g);
+									gdisp_lld_read_stop(g);
+								}
+								#if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT
+									else
+								#endif
+							#endif
+
+							// Next best line read is single pixel reads
+							#if GDISP_HARDWARE_STREAM_READ != TRUE && GDISP_HARDWARE_PIXELREAD
+								#if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT
+									if (gvmt(g)->get)
+								#endif
+								{
+									for(j=0; j < fx; j++) {
+										g->p.x = x+ix+j;
+										g->p.y = fy+lines;
+										g->linebuf[j] = gdisp_lld_get_pixel_color(g);
+									}
+								}
+								#if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT
+									else {
+										// Worst is "not possible"
+										MUTEX_EXIT(g);
+										return;
+									}
+								#endif
+							#endif
+
+							// Worst is "not possible"
+							#if !GDISP_HARDWARE_STREAM_READ && !GDISP_HARDWARE_PIXELREAD
+								#error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support for scrolling or reading pixels."
+							#endif
+
+							// Write that line to the new location
+
+							// Best line write is hardware bitfills
+							#if GDISP_HARDWARE_BITFILLS
+								#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
+									if (gvmt(g)->blit)
+								#endif
+								{
+									g->p.x = x+ix;
+									g->p.y = fy;
+									g->p.cx = fx;
+									g->p.cy = 1;
+									g->p.x1 = 0;
+									g->p.y1 = 0;
+									g->p.x2 = fx;
+									g->p.ptr = (void *)g->linebuf;
+									gdisp_lld_blit_area(g);
+								}
+								#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
+									else
+								#endif
+							#endif
+
+							// Next best line write is hardware streaming
+							#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
+								#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+									if (gvmt(g)->writestart)
+								#endif
+								{
+									g->p.x = x+ix;
+									g->p.y = fy;
+									g->p.cx = fx;
+									g->p.cy = 1;
+									gdisp_lld_write_start(g);
+									#if GDISP_HARDWARE_STREAM_POS
+										gdisp_lld_write_pos(g);
+									#endif
+									for(j = 0; j < fx; j++) {
+										g->p.color = g->linebuf[j];
+										gdisp_lld_write_color(g);
+									}
+									gdisp_lld_write_stop(g);
+								}
+								#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
+									else
+								#endif
+							#endif
+
+							// Next best line write is drawing pixels in combination with filling
+							#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS && GDISP_HARDWARE_DRAWPIXEL
+								// We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming.
+								#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+									if (gvmt(g)->fill)
+								#endif
+								{
+									g->p.y = fy;
+									g->p.cy = 1;
+									g->p.x = x+ix;
+									g->p.cx = 1;
+									for(j = 0; j < fx; ) {
+										g->p.color = g->linebuf[j];
+										if (j + g->p.cx < fx && g->linebuf[j] == g->linebuf[j + g->p.cx])
+											g->p.cx++;
+										else if (g->p.cx == 1) {
+											gdisp_lld_draw_pixel(g);
+											j++;
+											g->p.x++;
+										} else {
+											gdisp_lld_fill_area(g);
+											j += g->p.cx;
+											g->p.x += g->p.cx;
+											g->p.cx = 1;
+										}
+									}
+								}
+								#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
+									else
+								#endif
+							#endif
+
+							// Worst line write is drawing pixels
+							#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL
+								// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
+								//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
+								//	if (gvmt(g)->pixel)
+								//#endif
+								{
+									g->p.y = fy;
+									for(g->p.x = x+ix, j = 0; j < fx; g->p.x++, j++) {
+										g->p.color = g->linebuf[j];
+										gdisp_lld_draw_pixel(g);
+									}
+								}
+							#endif
+						}
+					}
+				}
+			#endif
+		}
+
+		/* fill the remaining gap */
+		g->p.x = x;
+		g->p.y = lines > 0 ? (y+cy) : y;
+		g->p.cx = cx;
+		g->p.cy = abslines;
+		g->p.color = bgcolor;
+		fillarea(g);
+		autoflush_stopdone(g);
+		MUTEX_EXIT(g);
+	}
+#endif
+
+#if GDISP_NEED_CONTROL
+	#if GDISP_HARDWARE_CONTROL
+		void gdispGControl(GDisplay *g, unsigned what, void *value) {
+			#if GDISP_HARDWARE_CONTROL == HARDWARE_AUTODETECT
+				if (!gvmt(g)->control)
+					return;
+			#endif
+			MUTEX_ENTER(g);
+			g->p.x = what;
+			g->p.ptr = value;
+			if (what == GDISP_CONTROL_ORIENTATION) {
+				switch ((orientation_t) value) {
+				case GDISP_ROTATE_LANDSCAPE:
+					g->p.ptr = g->g.Width >= g->g.Height ? (void *)GDISP_ROTATE_0 : (void *)GDISP_ROTATE_90;
+					break;
+				case GDISP_ROTATE_PORTRAIT:
+					g->p.ptr = g->g.Width >= g->g.Height ? (void *)GDISP_ROTATE_90 : (void *)GDISP_ROTATE_0;
+					break;
+				default:
+					break;
+				}
+			}
+			gdisp_lld_control(g);
+			#if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION
+				if (what == GDISP_CONTROL_ORIENTATION) {
+					// Best is hardware clipping
+					#if GDISP_HARDWARE_CLIP
+						#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+							if (gvmt(g)->setclip)
+						#endif
+						{
+							g->p.x = 0;
+							g->p.y = 0;
+							g->p.cx = g->g.Width;
+							g->p.cy = g->g.Height;
+							gdisp_lld_set_clip(g);
+						}
+						#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
+							else
+						#endif
+					#endif
+
+					// Worst is software clipping
+					#if GDISP_HARDWARE_CLIP != TRUE
+						{
+							g->clipx0 = 0;
+							g->clipy0 = 0;
+							g->clipx1 = g->g.Width;
+							g->clipy1 = g->g.Height;
+						}
+					#endif
+				}
+			#endif
+			MUTEX_EXIT(g);
+		}
+	#else
+		void gdispGControl(GDisplay *g, unsigned what, void *value) {
+			(void)g;
+			(void)what;
+			(void)value;
+			/* Ignore everything */
+		}
+	#endif
+#endif
+
+#if GDISP_NEED_QUERY
+	#if GDISP_HARDWARE_QUERY
+		void *gdispGQuery(GDisplay *g, unsigned what) {
+			void *res;
+
+			#if GDISP_HARDWARE_QUERY == HARDWARE_AUTODETECT
+				if (!gvmt(g)->query)
+					return -1;
+			#endif
+			MUTEX_ENTER(g);
+			g->p.x = (coord_t)what;
+			res = gdisp_lld_query(g);
+			MUTEX_EXIT(g);
+			return res;
+		}
+	#else
+		void *gdispGQuery(GDisplay *g, unsigned what) {
+			(void) what;
+			return (void *)-1;
+		}
+	#endif
+#endif
+
+/*===========================================================================*/
+/* High Level Driver Routines.                                               */
+/*===========================================================================*/
+
+void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
+	if (cx <= 0 || cy <= 0) return;
+	cx = x+cx-1; cy = y+cy-1;			// cx, cy are now the end point.
+
+	MUTEX_ENTER(g);
+
+	g->p.color = color;
+
+	if (cx - x > 2) {
+		g->p.x = x; g->p.y = y; g->p.x1 = cx; hline_clip(g);
+		if (y != cy) {
+			g->p.x = x; g->p.y = cy; g->p.x1 = cx; hline_clip(g);
+			if (cy - y > 2) {
+				y++; cy--;
+				g->p.x = x; g->p.y = y; g->p.y1 = cy; vline_clip(g);
+				g->p.x = cx; g->p.y = y; g->p.y1 = cy; vline_clip(g);
+			}
+		}
+	} else {
+		g->p.x = x; g->p.y = y; g->p.y1 = cy; vline_clip(g);
+		if (x != cx) {
+			g->p.x = cx; g->p.y = y; g->p.y1 = cy; vline_clip(g);
+		}
+	}
+
+	autoflush(g);
+	MUTEX_EXIT(g);
+}
+
+#if GDISP_NEED_CONVEX_POLYGON
+	void gdispGDrawPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) {
+		const point	*epnt, *p;
+
+		epnt = &pntarray[cnt-1];
+
+		MUTEX_ENTER(g);
+		g->p.color = color;
+		for(p = pntarray; p < epnt; p++) {
+			g->p.x=tx+p->x; g->p.y=ty+p->y; g->p.x1=tx+p[1].x; g->p.y1=ty+p[1].y; line_clip(g);
+		}
+		g->p.x=tx+p->x; g->p.y=ty+p->y; g->p.x1=tx+pntarray->x; g->p.y1=ty+pntarray->y; line_clip(g);
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+
+	void gdispGFillConvexPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) {
+		const point	*lpnt, *rpnt, *epnts;
+		fixed		lx, rx, lk, rk;
+		coord_t		y, ymax, lxc, rxc;
+
+		epnts = &pntarray[cnt-1];
+
+		/* Find a top point */
+		rpnt = pntarray;
+		for(lpnt=pntarray+1; lpnt <= epnts; lpnt++) {
+			if (lpnt->y < rpnt->y)
+				rpnt = lpnt;
+		}
+		lx = rx = FIXED(rpnt->x);
+		y = rpnt->y;
+
+		/* Work out the slopes of the two attached line segs */
+		for (lpnt = rpnt <= pntarray ? epnts : rpnt-1; lpnt->y == y; cnt--) {
+			if (!cnt) return;
+			lx = FIXED(lpnt->x);
+			lpnt = lpnt <= pntarray ? epnts : lpnt-1;
+		}
+		for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) {
+			if (!cnt) return;
+			rx = FIXED(rpnt->x);
+			rpnt = rpnt >= epnts ? pntarray : rpnt+1;
+		}
+		lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y);
+		rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y);
+
+		MUTEX_ENTER(g);
+		g->p.color = color;
+		while(1) {
+			/* Determine our boundary */
+			ymax = rpnt->y < lpnt->y ? rpnt->y : lpnt->y;
+
+			/* Scan down the line segments until we hit a boundary */
+			for(; y < ymax; y++) {
+				lxc = NONFIXED(lx);
+				rxc = NONFIXED(rx);
+				/*
+				 * Doesn't print the right hand point in order to allow polygon joining.
+				 * Also ensures that we draw from left to right with the minimum number
+				 * of pixels.
+				 */
+				if (lxc < rxc) {
+					g->p.x=tx+lxc; g->p.y=ty+y; g->p.x1=tx+rxc-1; hline_clip(g);
+				} else if (lxc > rxc) {
+					g->p.x=tx+rxc; g->p.y=ty+y; g->p.x1=tx+lxc-1; hline_clip(g);
+				}
+
+				lx += lk;
+				rx += rk;
+			}
+
+			if (!cnt) {
+				autoflush(g);
+				MUTEX_EXIT(g);
+				return;
+			}
+			cnt--;
+
+			/* Replace the appropriate point */
+			if (ymax == lpnt->y) {
+				for (lpnt = lpnt <= pntarray ? epnts : lpnt-1; lpnt->y == y; cnt--) {
+					if (!cnt) {
+						autoflush(g);
+						MUTEX_EXIT(g);
+						return;
+					}
+					lx = FIXED(lpnt->x);
+					lpnt = lpnt <= pntarray ? epnts : lpnt-1;
+				}
+				lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y);
+			} else {
+				for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) {
+					if (!cnt) {
+						autoflush(g);
+						MUTEX_EXIT(g);
+						return;
+					}
+					rx = FIXED(rpnt->x);
+					rpnt = rpnt >= epnts ? pntarray : rpnt+1;
+				}
+				rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y);
+			}
+		}
+	}
+
+	static int32_t rounding_div(const int32_t n, const int32_t d)
+	{
+		if ((n < 0) != (d < 0))
+			return (n - d/2) / d;
+		else
+			return (n + d/2) / d;
+	}
+
+	/* Find a vector (nx, ny) that is perpendicular to (dx, dy) and has length
+	 * equal to 'norm'. */
+	static void get_normal_vector(coord_t dx, coord_t dy, coord_t norm, coord_t *nx, coord_t *ny)
+	{
+		int32_t dx2, dy2, len_sq, norm_sq, norm_sq2;
+		int div, step, best, delta, abs_delta;
+
+		dx2 = dx; dy2 = dy;
+		norm_sq = (int32_t)norm * norm;
+		norm_sq2 = norm_sq * 512;
+
+		/* Scale dx2 and dy2 so that
+		 *     len_sq / 2 <= norm_sq * 512 <= len_sq * 2.
+		 * The scaling by 512 is to yield higher accuracy in division later. */
+		len_sq = dx2 * dx2 + dy2 * dy2;
+
+		if (len_sq < norm_sq2)
+		{
+			while (len_sq && len_sq < norm_sq2)
+			{
+				len_sq <<= 2; dx2 <<= 1; dy2 <<= 1;
+			}
+		}
+		else if (len_sq > norm_sq2)
+		{
+			while (len_sq && len_sq > norm_sq2)
+			{
+				len_sq >>= 2; dx2 >>= 1; dy2 >>= 1;
+			}
+		}
+
+		/* Now find the divider div so that
+		 *     len_sq / div^2 == norm_sq   i.e.  div = sqrt(len_sq / norm_sq)
+		 *
+		 * This is done using bisection search to avoid the need for floating
+		 * point sqrt.
+		 *
+		 * Based on previous scaling, we know that
+		 *     len_sq / 2 <= norm_sq * 512   <=>   div <= sqrt(1024) = 32
+		 *     len_sq * 2 >= norm_sq * 512   <=>   div >= sqrt(256) = 16
+		 */
+		div = 24; step = 8;
+		best = 256;
+
+		for (;;)
+		{
+			dx = dx2 / div;
+			dy = dy2 / div;
+			len_sq = dx*dx + dy*dy;
+
+			delta = len_sq - norm_sq;
+
+			abs_delta = (delta >= 0) ? delta : -delta;
+
+			if (abs_delta < best)
+			{
+				*nx = dy;
+				*ny = -dx;
+				best = abs_delta;
+			}
+
+			if (delta > 0)
+				div += step;
+			else if (delta < 0)
+				div -= step;
+			else if (delta == 0)
+				break;
+
+			if (step == 0)
+				break;
+			else
+				step >>= 1; /* Do one round with step = 0 to calculate final result. */
+		}
+	}
+
+	void gdispGDrawThickLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color, coord_t width, bool_t round) {
+		coord_t dx, dy, nx = 0, ny = 0;
+
+		/* Compute the direction vector for the line */
+		dx = x1 - x0;
+		dy = y1 - y0;
+
+		/* Draw a small dot if the line length is zero. */
+		if (dx == 0 && dy == 0)
+			dx += 1;
+
+		/* Compute a normal vector with length 'width'. */
+		get_normal_vector(dx, dy, width, &nx, &ny);
+
+		/* Handle 1px wide lines gracefully */
+		if (nx == 0 && ny == 0)
+			nx = 1;
+
+		/* Offset the x0,y0 by half the width of the line. This way we
+		 * can keep the width of the line accurate even if it is not evenly
+		 * divisible by 2.
+		 */
+		{
+			x0 -= rounding_div(nx, 2);
+			y0 -= rounding_div(ny, 2);
+		}
+
+		/* Fill in the point array */
+		if (!round) {
+			/* We use 4 points for the basic line shape:
+			 *
+			 *  pt1                                      pt2
+			 * (+n) ------------------------------------ (d+n)
+			 *   |                                       |
+			 * (0,0) ----------------------------------- (d)
+			 *  pt0                                      pt3
+			 */
+			point pntarray[4];
+
+			pntarray[0].x = 0;
+			pntarray[0].y = 0;
+			pntarray[1].x = nx;
+			pntarray[1].y = ny;
+			pntarray[2].x = dx + nx;
+			pntarray[2].y = dy + ny;
+			pntarray[3].x = dx;
+			pntarray[3].y = dy;
+
+			gdispGFillConvexPoly(g, x0, y0, pntarray, 4, color);
+		} else {
+			/* We use 4 points for basic shape, plus 4 extra points for ends:
+			 *
+			 *           pt3 ------------------ pt4
+			 *          /                         \
+			 *        pt2                        pt5
+			 *         |                          |
+			 *        pt1                        pt6
+			 *         \                         /
+			 *          pt0 -------------------pt7
+			 */
+			point pntarray[8];
+			coord_t nx2, ny2;
+
+			/* Magic numbers:
+			 * 75/256  = sin(45) / (1 + sqrt(2))		diagonal octagon segments
+			 * 106/256 = 1 / (1 + sqrt(2))				octagon side
+			 * 53/256  = 0.5 / (1 + sqrt(2))			half of octagon side
+			 * 150/256 = 1 - 1 / (1 + sqrt(2))	  		octagon height minus one side
+			 */
+
+			/* Rotate the normal vector 45 deg counter-clockwise and reduce
+			 * to 1 / (1 + sqrt(2)) length, for forming octagonal ends. */
+			nx2 = rounding_div((nx * 75 + ny * 75), 256);
+			ny2 = rounding_div((-nx * 75 + ny * 75), 256);
+
+			/* Offset and extend the line so that the center of the octagon
+			 * is at the specified points. */
+			x0 += ny * 53 / 256;
+			y0 -= nx * 53 / 256;
+			dx -= ny * 106 / 256;
+			dy += nx * 106 / 256;
+
+			/* Now fill in the points by summing the calculated vectors. */
+			pntarray[0].x = 0;
+			pntarray[0].y = 0;
+			pntarray[1].x = nx2;
+			pntarray[1].y = ny2;
+			pntarray[2].x = nx2 + nx * 106/256;
+			pntarray[2].y = ny2 + ny * 106/256;
+			pntarray[3].x = nx;
+			pntarray[3].y = ny;
+			pntarray[4].x = dx + nx;
+			pntarray[4].y = dy + ny;
+			pntarray[5].x = dx + nx - nx2;
+			pntarray[5].y = dy + ny - ny2;
+			pntarray[6].x = dx + nx * 150/256 - nx2;
+			pntarray[6].y = dy + ny * 150/256 - ny2;
+			pntarray[7].x = dx;
+			pntarray[7].y = dy;
+
+			gdispGFillConvexPoly(g, x0, y0, pntarray, 8, color);
+		}
+	}
+#endif
+
+#if GDISP_NEED_TEXT
+	#include "mcufont/mcufont.h"
+
+	#if GDISP_NEED_ANTIALIAS && GDISP_HARDWARE_PIXELREAD
+		static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+			#define GD	((GDisplay *)state)
+			if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x+count <= GD->t.clipx0 || x >= GD->t.clipx1)
+				return;
+			if (x < GD->t.clipx0) {
+				count -= GD->t.clipx0 - x;
+				x = GD->t.clipx0;
+			}
+			if (x+count > GD->t.clipx1)
+				count = GD->t.clipx1 - x;
+			if (alpha == 255) {
+				GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color;
+				hline_clip(GD);
+			} else {
+				for (; count; count--, x++) {
+					GD->p.x = x; GD->p.y = y;
+					GD->p.color = gdispBlendColor(GD->t.color, gdisp_lld_get_pixel_color(GD), alpha);
+					drawpixel_clip(GD);
+				}
+			}
+			#undef GD
+		}
+	#else
+		static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+			#define GD	((GDisplay *)state)
+			if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x+count <= GD->t.clipx0 || x >= GD->t.clipx1)
+				return;
+			if (x < GD->t.clipx0) {
+				count -= GD->t.clipx0 - x;
+				x = GD->t.clipx0;
+			}
+			if (x+count > GD->t.clipx1)
+				count = GD->t.clipx1 - x;
+			if (alpha > 0x80) {			// A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased
+				GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color;
+				hline_clip(GD);
+			}
+			#undef GD
+		}
+	#endif
+
+	#if GDISP_NEED_ANTIALIAS
+		static void fillcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
+			#define GD	((GDisplay *)state)
+			if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x+count <= GD->t.clipx0 || x >= GD->t.clipx1)
+				return;
+			if (x < GD->t.clipx0) {
+				count -= GD->t.clipx0 - x;
+				x = GD->t.clipx0;
+			}
+			if (x+count > GD->t.clipx1)
+				count = GD->t.clipx1 - x;
+			if (alpha == 255) {
+				GD->p.color = GD->t.color;
+			} else {
+				GD->p.color = gdispBlendColor(GD->t.color, GD->t.bgcolor, alpha);
+			}
+			GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1;
+			hline_clip(GD);
+			#undef GD
+		}
+	#else
+		#define fillcharline	drawcharline
+	#endif
+
+	/* Callback to render characters. */
+	static uint8_t drawcharglyph(int16_t x, int16_t y, mf_char ch, void *state) {
+		#define GD	((GDisplay *)state)
+			return mf_render_character(GD->t.font, x, y, ch, drawcharline, state);
+		#undef GD
+	}
+
+	/* Callback to render characters. */
+	static uint8_t fillcharglyph(int16_t x, int16_t y, mf_char ch, void *state) {
+		#define GD	((GDisplay *)state)
+			return mf_render_character(GD->t.font, x, y, ch, fillcharline, state);
+		#undef GD
+	}
+
+	void gdispGDrawChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color) {
+		MUTEX_ENTER(g);
+		g->t.font = font;
+		g->t.clipx0 = x;
+		g->t.clipy0 = y;
+		g->t.clipx1 = x + mf_character_width(font, c) + font->baseline_x;
+		g->t.clipy1 = y + font->height;
+		g->t.color = color;
+		mf_render_character(font, x, y, c, drawcharline, g);
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+
+	void gdispGFillChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) {
+		MUTEX_ENTER(g);
+		g->p.cx = mf_character_width(font, c) + font->baseline_x;
+		g->p.cy = font->height;
+		g->t.font = font;
+		g->t.clipx0 = g->p.x = x;
+		g->t.clipy0 = g->p.y = y;
+		g->t.clipx1 = g->p.x+g->p.cx;
+		g->t.clipy1 = g->p.y+g->p.cy;
+		g->t.color = color;
+		g->t.bgcolor = g->p.color = bgcolor;
+
+		TEST_CLIP_AREA(g) {
+			fillarea(g);
+			mf_render_character(font, x, y, c, fillcharline, g);
+		}
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+
+	void gdispGDrawString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color) {
+		MUTEX_ENTER(g);
+		g->t.font = font;
+		g->t.clipx0 = x;
+		g->t.clipy0 = y;
+		g->t.clipx1 = x + mf_get_string_width(font, str, 0, 0);
+		g->t.clipy1 = y + font->height;
+		g->t.color = color;
+
+		mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, g);
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+
+	void gdispGFillString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) {
+		MUTEX_ENTER(g);
+		g->p.cx = mf_get_string_width(font, str, 0, 0);
+		g->p.cy = font->height;
+		g->t.font = font;
+		g->t.clipx0 = g->p.x = x;
+		g->t.clipy0 = g->p.y = y;
+		g->t.clipx1 = g->p.x+g->p.cx;
+		g->t.clipy1 = g->p.y+g->p.cy;
+		g->t.color = color;
+		g->t.bgcolor = g->p.color = bgcolor;
+
+		TEST_CLIP_AREA(g) {
+			fillarea(g);
+			mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, g);
+		}
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+
+	void gdispGDrawStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) {
+		MUTEX_ENTER(g);
+		g->t.font = font;
+		g->t.clipx0 = x;
+		g->t.clipy0 = y;
+		g->t.clipx1 = x+cx;
+		g->t.clipy1 = y+cy;
+		g->t.color = color;
+
+		/* Select the anchor position */
+		switch(justify) {
+		case justifyCenter:
+			x += (cx + 1) / 2;
+			break;
+		case justifyRight:
+			x += cx;
+			break;
+		default:	// justifyLeft
+			x += font->baseline_x;
+			break;
+		}
+		y += (cy+1 - font->height)/2;
+
+		mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, g);
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+
+	void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) {
+		MUTEX_ENTER(g);
+		g->p.cx = cx;
+		g->p.cy = cy;
+		g->t.font = font;
+		g->t.clipx0 = g->p.x = x;
+		g->t.clipy0 = g->p.y = y;
+		g->t.clipx1 = x+cx;
+		g->t.clipy1 = y+cy;
+		g->t.color = color;
+		g->t.bgcolor = g->p.color = bgcolor;
+
+		TEST_CLIP_AREA(g) {
+
+			// background fill
+			fillarea(g);
+
+			/* Select the anchor position */
+			switch(justify) {
+			case justifyCenter:
+				x += (cx + 1) / 2;
+				break;
+			case justifyRight:
+				x += cx;
+				break;
+			default:	// justifyLeft
+				x += font->baseline_x;
+				break;
+			}
+			y += (cy+1 - font->height)/2;
+
+			/* Render */
+			mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, g);
+		}
+
+		autoflush(g);
+		MUTEX_EXIT(g);
+	}
+
+	coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) {
+		/* No mutex required as we only read static data */
+		switch(metric) {
+		case fontHeight:			return font->height;
+		case fontDescendersHeight:	return font->height - font->baseline_y;
+		case fontLineSpacing:		return font->line_height;
+		case fontCharPadding:		return 0;
+		case fontMinWidth:			return font->min_x_advance;
+		case fontMaxWidth:			return font->max_x_advance;
+		}
+		return 0;
+	}
+
+	coord_t gdispGetCharWidth(char c, font_t font) {
+		/* No mutex required as we only read static data */
+		return mf_character_width(font, c);
+	}
+
+	coord_t gdispGetStringWidth(const char* str, font_t font) {
+		if (!str)
+			return 0;
+
+		/* No mutex required as we only read static data */
+		return mf_get_string_width(font, str, 0, 0);
+	}
+#endif
+
+color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha)
+{
+	uint16_t fg_ratio = alpha + 1;
+	uint16_t bg_ratio = 256 - alpha;
+	uint16_t r, g, b;
+
+	r = RED_OF(fg) * fg_ratio;
+	g = GREEN_OF(fg) * fg_ratio;
+	b = BLUE_OF(fg) * fg_ratio;
+
+	r += RED_OF(bg) * bg_ratio;
+	g += GREEN_OF(bg) * bg_ratio;
+	b += BLUE_OF(bg) * bg_ratio;
+
+	r >>= 8;
+	g >>= 8;
+	b >>= 8;
+
+	return RGB2COLOR(r, g, b);
+}
+
+color_t gdispContrastColor(color_t color) {
+	uint16_t r, g, b;
+
+	r = RED_OF(color) > 128 ? 0 : 255;
+	g = GREEN_OF(color) > 128 ? 0 : 255;
+	b = BLUE_OF(color) > 128 ? 0 : 255;
+
+	return RGB2COLOR(r, g, b);
+}
+
+#if (!defined(gdispPackPixels) && !defined(GDISP_PIXELFORMAT_CUSTOM))
+	void gdispPackPixels(pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color) {
+		/* No mutex required as we only read static data */
+		#if defined(GDISP_PIXELFORMAT_RGB888)
+			#error "GDISP: Packed pixels not supported yet"
+		#elif defined(GDISP_PIXELFORMAT_RGB444)
+			#error "GDISP: Packed pixels not supported yet"
+		#elif defined(GDISP_PIXELFORMAT_RGB666)
+			#error "GDISP: Packed pixels not supported yet"
+		#elif
+			#error "GDISP: Unsupported packed pixel format"
+		#endif
+	}
+#endif
+
+#endif /* GFX_USE_GDISP */
diff --git a/src/gdisp/gdisp.h b/src/gdisp/gdisp.h
new file mode 100644
index 00000000..aaf53478
--- /dev/null
+++ b/src/gdisp/gdisp.h
@@ -0,0 +1,1124 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gdisp/gdisp.h
+ * @brief   GDISP Graphic Driver subsystem header file.
+ *
+ * @addtogroup GDISP
+ *
+ * @brief		Module to interface graphic / pixel oriented displays
+ *
+ * @details		The GDISP module provides high level abstraction to interface pixel oriented graphic displays.
+ *
+ * @pre			GFX_USE_GDISP must be set to TRUE in gfxconf.h
+ *
+ * @note		Each drawing routine supports a gdispXXXX and a gdispGXXXX function. The difference is that the
+ * 				gdispXXXX function does not require a display to be specified. Note there is a slight anomaly
+ * 				in the naming with gdispGBlitArea() vs gdispBlitAreaEx() and gdispBlitArea(), the latter of
+ * 				which is now deprecated.
+ * @{
+ */
+
+#ifndef _GDISP_H
+#define _GDISP_H
+
+#include "gfx.h"
+
+/* This type definition is defined here as it gets used in other gfx sub-systems even
+ * if GFX_USE_GDISP is FALSE.
+ */
+
+/**
+ * @brief   The type for a coordinate or length on the screen.
+ */
+typedef int16_t	coord_t;
+
+#if GFX_USE_GDISP || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+/**
+ * @brief   Type for a 2D point on the screen.
+ */
+typedef struct point { coord_t x, y; } point, point_t;
+/**
+ * @brief   Type for the text justification.
+ */
+typedef enum justify { justifyLeft=0, justifyCenter=1, justifyRight=2 } justify_t;
+/**
+ * @brief   Type for the font metric.
+ */
+typedef enum fontmetric { fontHeight, fontDescendersHeight, fontLineSpacing, fontCharPadding, fontMinWidth, fontMaxWidth } fontmetric_t;
+/**
+ * @brief   The type of a font.
+ */
+typedef const struct mf_font_s* font_t;
+/**
+ * @brief   Type for the screen orientation.
+ * @note	GDISP_ROTATE_LANDSCAPE and GDISP_ROTATE_PORTRAIT are internally converted to the
+ * 			most appropriate other orientation.
+ */
+typedef enum orientation { GDISP_ROTATE_0=0, GDISP_ROTATE_90=90, GDISP_ROTATE_180=180, GDISP_ROTATE_270=270, GDISP_ROTATE_PORTRAIT=1000,  GDISP_ROTATE_LANDSCAPE=1001 } orientation_t;
+/**
+ * @brief   Type for the available power modes for the screen.
+ */
+typedef enum powermode { powerOff, powerSleep, powerDeepSleep, powerOn } powermode_t;
+
+/*
+ * Our black box display structure.
+ */
+typedef struct GDisplay		GDisplay;
+
+/**
+ * @brief   The default screen to use for the gdispXXXX calls.
+ * @note	This is set by default to the first display in the system. You can change
+ * 			it by calling @p gdispGSetDisplay().
+ */
+extern GDisplay	*GDISP;
+
+/*===========================================================================*/
+/* Constants.                                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Driver Control Constants
+ * @details	Unsupported control codes are ignored.
+ * @note	The value parameter should always be typecast to (void *).
+ * @note	There are some predefined and some specific to the low level driver.
+ * @note	GDISP_CONTROL_POWER			- Takes a gdisp_powermode_t
+ * 			GDISP_CONTROL_ORIENTATION	- Takes a gdisp_orientation_t
+ * 			GDISP_CONTROL_BACKLIGHT -	 Takes an int from 0 to 100. For a driver
+ * 											that only supports off/on anything other
+ * 											than zero is on.
+ * 			GDISP_CONTROL_CONTRAST		- Takes an int from 0 to 100.
+ * 			GDISP_CONTROL_LLD			- Low level driver control constants start at
+ * 											this value.
+ */
+#define GDISP_CONTROL_POWER			0
+#define GDISP_CONTROL_ORIENTATION	1
+#define GDISP_CONTROL_BACKLIGHT		2
+#define GDISP_CONTROL_CONTRAST		3
+#define GDISP_CONTROL_LLD			1000
+
+/*===========================================================================*/
+/* Defines relating to the display hardware									 */
+/*===========================================================================*/
+
+#if !defined(GDISP_DRIVER_LIST)
+	// Pull in the default hardware configuration for a single controller.
+	// If we have multiple controllers the settings must be set in the
+	// users gfxconf.h file.
+	#include "gdisp_lld_config.h"
+
+	// Unless the user has specified a specific pixel format, use
+	// the native format for the controller.
+	#if !defined(GDISP_PIXELFORMAT) && defined(GDISP_LLD_PIXELFORMAT)
+		#define GDISP_PIXELFORMAT 			GDISP_LLD_PIXELFORMAT
+	#endif
+#endif
+
+/**
+ * @name    GDISP pixel format choices
+ * @{
+ */
+	/**
+	 * @brief   The pixel format.
+	 * @details	It generally defaults to the hardware pixel format.
+	 * @note	This doesn't need to match the hardware pixel format.
+	 * 			It is definitely more efficient when it does.
+	 * @note	When GDISP_DRIVER_LIST is defined, this must
+	 * 			be explicitly defined and you should ensure the best match
+	 * 			with your hardware across all devices.
+	 */
+	#ifndef GDISP_PIXELFORMAT
+		#define GDISP_PIXELFORMAT 			GDISP_PIXELFORMAT_ERROR
+	#endif
+	/**
+	 * @brief   Do pixels require packing for a blit
+	 * @note	Is only valid for a pixel format that doesn't fill it's datatype. eg formats:
+	 *				GDISP_PIXELFORMAT_RGB888
+	 *				GDISP_PIXELFORMAT_RGB444
+	 *				GDISP_PIXELFORMAT_RGB666
+	 *				GDISP_PIXELFORMAT_CUSTOM
+	 * @note	Very few cases should actually require packed pixels as the low
+	 *				level driver can also pack on the fly as it is sending it
+	 *				to the graphics device.
+	 * @note	Packed pixels are not really supported at this point.
+	 */
+	#ifndef GDISP_PACKED_PIXELS
+		#define GDISP_PACKED_PIXELS			FALSE
+	#endif
+
+	/**
+	 * @brief   Do lines of pixels require packing for a blit
+	 * @note	Ignored if GDISP_PACKED_PIXELS is FALSE
+	 */
+	#ifndef GDISP_PACKED_LINES
+		#define GDISP_PACKED_LINES			FALSE
+	#endif
+/** @} */
+
+/*===========================================================================*/
+/* Defines related to the pixel format										 */
+/*===========================================================================*/
+
+/* Load our color definitions and pixel formats */
+#include "gdisp_colors.h"
+
+/**
+ * @brief   The type of a pixel.
+ */
+typedef color_t		pixel_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Color Utility Functions */
+
+/**
+ * @brief   Blend 2 colors according to the alpha
+ * @return	The combined color
+ *
+ * @param[in] fg		The foreground color
+ * @param[in] bg		The background color
+ * @param[in] alpha		The alpha value (0-255). 0 is all background, 255 is all foreground.
+ *
+ * @api
+ */
+color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha);
+
+/**
+ * @brief   Find a contrasting color
+ * @return	The contrasting color
+ *
+ * @param[in] color		The color to contrast
+ *
+ * @api
+ */
+color_t gdispContrastColor(color_t color);
+
+/* Base Functions */
+
+/**
+ * @brief   Get the specified display
+ * @return	The pointer to the display or NULL if the display doesn't exist
+ * @note	The GDISP variable contains the display used by the gdispXxxx routines
+ * 			as opposed to the gdispGXxxx routines which take an explicit display
+ * 			parameter.
+ * @note	Displays are numbered from 0 to @p gdispGetDisplayCount() - 1
+ *
+ * @param[in] display	The display number (0..n)
+ *
+ * @api
+ */
+GDisplay *gdispGetDisplay(unsigned display);
+
+/**
+ * @brief   Set the current default display to the specified display
+ * @note	The default display is used for the gdispXxxx functions.
+ * @note	The default display is contained in the variable GDISP. Using
+ * 			this function to set it protects against it being set to a NULL
+ * 			value.
+ * @note	If a NULL is passed for the dispay this call is ignored.
+ *
+ * @param[in] g 	The display to use
+ *
+ * @api
+ */
+void gdispSetDisplay(GDisplay *g);
+
+/**
+ * @brief   Get the count of currently active displays
+ * @return  The count of displays currently in the system
+ *
+ * @note	Displays are numbered from 0 to @p gdispGetDisplayCount() - 1
+ */
+unsigned gdispGetDisplayCount(void);
+
+/* Property Functions */
+
+/**
+ * @brief   Get the display width in pixels.
+ *
+ * @param[in] g 		The display to use
+ *
+ * @return	The width of the display
+ *
+ * @api
+ */
+coord_t gdispGGetWidth(GDisplay *g);
+#define gdispGetWidth()								gdispGGetWidth(GDISP)
+
+/**
+ * @brief   Get the display height in pixels.
+ *
+ * @param[in] g 		The display to use
+ *
+ * @return	The height of the display
+ *
+ * @api
+ */
+coord_t gdispGGetHeight(GDisplay *g);
+#define gdispGetHeight()							gdispGGetHeight(GDISP)
+
+/**
+ * @brief   Get the current display power mode.
+ *
+ * @param[in] g 		The display to use
+ *
+ * @return	The current power mode
+ *
+ * @api
+ */
+powermode_t gdispGGetPowerMode(GDisplay *g);
+#define gdispGetPowerMode()							gdispGGetPowerMode(GDISP)
+
+/**
+ * @brief   Get the current display orientation.
+ *
+ * @param[in] g 		The display to use
+ *
+ * @return	The current orientation
+ *
+ * @api
+ */
+orientation_t gdispGGetOrientation(GDisplay *g);
+#define gdispGetOrientation()						gdispGGetOrientation(GDISP)
+
+/**
+ * @brief   Get the current display backlight brightness.
+ *
+ * @param[in] g 		The display to use
+ *
+ * @return	The current backlight value
+ *
+ * @api
+ */
+uint8_t gdispGGetBacklight(GDisplay *g);
+#define gdispGetBacklight()							gdispGGetBacklight(GDISP)
+
+/**
+ * @brief   Get the current display contrast.
+ *
+ * @param[in] g 		The display to use
+ *
+ * @return	The current contrast value
+ *
+ * @api
+ */
+uint8_t gdispGGetContrast(GDisplay *g);
+#define gdispGetContrast()							gdispGGetContrast(GDISP)
+
+/* Drawing Functions */
+
+/**
+ * @brief   Flush current drawing operations to the display
+ * @note	Some low level drivers do not update the display until
+ * 			the display is flushed. For others it is optional but can
+ * 			help prevent tearing effects. For some it is ignored.
+ * 			Calling it at the end of a logic set of drawing operations
+ * 			in your application will ensure controller portability. If you
+ * 			know your controller does not need to be flushed there is no
+ * 			need to call it (which is in reality most controllers).
+ * @note	Even for displays that require flushing, there is no need to
+ * 			call this function if GDISP_NEED_AUTOFLUSH is TRUE.
+ * 			Calling it again won't hurt though.
+ *
+ *
+ * @param[in] g 	The display to use
+ *
+ * @api
+ */
+void gdispGFlush(GDisplay *g);
+#define gdispFlush()									gdispGFlush(GDISP)
+
+/**
+ * @brief   Clear the display to the specified color.
+ *
+ * @param[in] g 	The display to use
+ * @param[in] color The color to use when clearing the screen
+ *
+ * @api
+ */
+void gdispGClear(GDisplay *g, color_t color);
+#define gdispClear(c)									gdispGClear(GDISP, c)
+
+/**
+ * @brief   Set a pixel in the specified color.
+ *
+ * @param[in] g 	The display to use
+ * @param[in] x,y   The position to set the pixel.
+ * @param[in] color The color to use
+ *
+ * @api
+ */
+void gdispGDrawPixel(GDisplay *g, coord_t x, coord_t y, color_t color);
+#define gdispDrawPixel(x,y,c)							gdispGDrawPixel(GDISP,x,y,c)
+
+/**
+ * @brief   Draw a line.
+ *
+ * @param[in] g 	The display to use
+ * @param[in] x0,y0		The start position
+ * @param[in] x1,y1 	The end position
+ * @param[in] color		The color to use
+ *
+ * @api
+ */
+void gdispGDrawLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
+#define gdispDrawLine(x0,y0,x1,y1,c)					gdispGDrawLine(GDISP,x0,y0,x1,y1,c)
+
+/**
+ * @brief   Fill an area with a color.
+ *
+ * @param[in] g 		The display to use
+ * @param[in] x,y		The start position
+ * @param[in] cx,cy		The size of the box (outside dimensions)
+ * @param[in] color		The color to use
+ *
+ * @api
+ */
+void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
+#define gdispFillArea(x,y,cx,cy,c)						gdispGFillArea(GDISP,x,y,cx,cy,c)
+
+/**
+ * @brief   Fill an area using the supplied bitmap.
+ * @details The bitmap is in the pixel format specified by the low level driver
+ * @note	If a packed pixel format is used and the width doesn't
+ *			match a whole number of bytes, the next line will start on a
+ *			non-byte boundary (no end-of-line padding).
+ * @note	If GDISP_NEED_ASYNC is defined then the buffer must be static
+ * 			or at least retained until this call has finished the blit. You can
+ * 			tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE.
+ *
+ * @param[in] g 		The display to use
+ * @param[in] x,y		The start position
+ * @param[in] cx,cy		The size of the filled area
+ * @param[in] srcx,srcy The bitmap position to start the fill form
+ * @param[in] srccx		The width of a line in the bitmap
+ * @param[in] buffer	The bitmap in the driver's pixel format
+ *
+ * @api
+ */
+void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer);
+#define gdispBlitAreaEx(x,y,cx,cy,sx,sy,rx,b)			gdispGBlitArea(GDISP,x,y,cx,cy,sx,sy,rx,b)
+
+/**
+ * @brief   Draw a rectangular box.
+ *
+ * @param[in] g 		The display to use
+ * @param[in] x,y		The start position
+ * @param[in] cx,cy		The size of the box (outside dimensions)
+ * @param[in] color		The color to use
+ *
+ * @api
+ */
+void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
+#define gdispDrawBox(x,y,cx,cy,c)						gdispGDrawBox(GDISP,x,y,cx,cy,c)
+
+/* Streaming Functions */
+
+#if GDISP_NEED_STREAMING || defined(__DOXYGEN__)
+	/**
+	 * @brief   Start a streaming operation.
+	 * @details Stream data to a window on the display sequentially and very fast.
+	 * @pre		GDISP_NEED_STREAMING must be TRUE in your gfxconf.h
+	 * @note	While streaming is in operation - no other calls to GDISP functions
+	 * 			can be made (with the exception of @p gdispBlendColor() and streaming
+	 * 			functions). If a call is made (eg in a multi-threaded application) the other
+	 * 			call is blocked waiting for the streaming operation to finish.
+	 * @note	@p gdispStreamStop() must be called to finish the streaming operation.
+	 * @note	If more data is written than the defined area then the results are unspecified.
+	 * 			Some drivers may wrap back to the beginning of the area, others may just
+	 * 			ignore subsequent data.
+	 * @note	Unlike most operations that clip the defined area to the display to generate
+	 * 			a smaller active area, this call will just silently fail if any of the stream
+	 * 			region lies outside the current clipping area.
+	 * @note	A streaming operation may be terminated early (without writing to every location
+	 * 			in the stream area) by calling @p gdispStreamStop().
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The start position
+	 * @param[in] cx,cy		The size of the streamable area
+	 *
+	 * @api
+	 */
+	void gdispGStreamStart(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy);
+	#define gdispStreamStart(x,y,cx,cy)						gdispGStreamStart(GDISP,x,y,cx,cy)
+
+	/**
+	 * @brief   Send pixel data to the stream.
+	 * @details Write a pixel to the next position in the streamed area and increment the position
+	 * @pre		GDISP_NEED_STREAMING must be TRUE in your gfxconf.h
+	 * @pre		@p gdispStreamStart() has been called.
+	 * @note	If the gdispStreamStart() has not been called (or failed due to clipping), the
+	 * 			data provided here is simply thrown away.
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] color		The color of the pixel to write
+	 *
+	 * @api
+	 */
+	void gdispGStreamColor(GDisplay *g, color_t color);
+	#define gdispStreamColor(c)								gdispGStreamColor(GDISP,c)
+
+	/**
+	 * @brief   Finish the current streaming operation.
+	 * @details	Completes the current streaming operation and allows other GDISP calls to operate again.
+	 * @pre		GDISP_NEED_STREAMING must be TRUE in your gfxconf.h
+	 * @pre		@p gdispStreamStart() has been called.
+	 * @note	If the gdispStreamStart() has not been called (or failed due to clipping), this
+	 * 			call is simply ignored.
+	 *
+	 * @param[in] g 		The display to use
+	 *
+	 * @api
+	 */
+	void gdispGStreamStop(GDisplay *g);
+	#define gdispStreamStop()								gdispGStreamStop(GDISP)
+#endif
+
+/* Clipping Functions */
+
+#if GDISP_NEED_CLIP || defined(__DOXYGEN__)
+	/**
+	 * @brief   Clip all drawing to the defined area.
+	 * @pre		GDISP_NEED_CLIP must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The start position
+	 * @param[in] cx,cy		The size of the clip area
+	 *
+	 * @api
+	 */
+	void gdispGSetClip(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy);
+	#define gdispSetClip(x,y,cx,cy)							gdispGSetClip(GDISP,x,y,cx,cy)
+#endif
+
+/* Circle Functions */
+
+#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__)
+	/**
+	 * @brief   Draw a circle.
+	 * @pre		GDISP_NEED_CIRCLE must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The center of the circle
+	 * @param[in] radius	The radius of the circle
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGDrawCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color);
+	#define gdispDrawCircle(x,y,r,c)						gdispGDrawCircle(GDISP,x,y,r,c)
+
+	/**
+	 * @brief   Draw a filled circle.
+	 * @pre		GDISP_NEED_CIRCLE must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The center of the circle
+	 * @param[in] radius	The radius of the circle
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGFillCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color);
+	#define gdispFillCircle(x,y,r,c)						gdispGFillCircle(GDISP,x,y,r,c)
+#endif
+
+/* Ellipse Functions */
+
+#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__)
+	/**
+	 * @brief   Draw an ellipse.
+	 * @pre		GDISP_NEED_ELLIPSE must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The center of the ellipse
+	 * @param[in] a,b		The dimensions of the ellipse
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGDrawEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
+	#define gdispDrawEllipse(x,y,a,b,c)						gdispGDrawEllipse(GDISP,x,y,a,b,c)
+
+	/**
+	 * @brief   Draw a filled ellipse.
+	 * @pre		GDISP_NEED_ELLIPSE must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The center of the ellipse
+	 * @param[in] a,b		The dimensions of the ellipse
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGFillEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
+	#define gdispFillEllipse(x,y,a,b,c)						gdispGFillEllipse(GDISP,x,y,a,b,c)
+#endif
+
+/* Arc Functions */
+#if GDISP_NEED_ARCSECTORS || defined(__DOXYGEN__)
+	/**
+	 * @brief	Draw a selection of 45 degree arcs of a circle
+	 * @pre		GDISP_NEED_ARCSECTORS must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The center of the circle
+	 * @param[in] radius	The radius of the circle
+	 * @param[in] sectors	Bits determine which sectors are drawn.
+	 * 						Bits go anti-clockwise from the 0 degree mark (y = 0, x is positive), as follows:
+	 *  						bit 0 - upper right right		  -----
+	 *  						bit 1 - upper upper right		 /2   1\
+	 *  						bit 2 - upper upper left		/3     0\
+	 *  						bit 3 - upper left  left		\4     7/
+	 *  						bit 4 - lower left  left		 \5   6/
+	 *  						bit 5 - lower lower left		  -----
+	 *  						bit 6 - lower lower right
+	 *  						bit 7 - lower left  left
+	 * @param[in] color		The color to use
+	 *
+	 * @note	This is a more limited versions of the general arc drawing routine. It
+	 * 			doesn't require trig libraries or tables or floating point and is smaller in code size.
+	 * 			There is probably little point in including both this and the general
+	 * 			arc routine as the general arc routine can do everything this can do.
+	 *
+	 * @api
+	 */
+	void gdispGDrawArcSectors(GDisplay *g, coord_t x, coord_t y, coord_t radius, uint8_t sectors, color_t color);
+	#define gdispDrawArcSectors(x,y,r,s,c)						gdispGDrawArcSectors(GDISP,x,y,r,s,c)
+
+	/**
+	 * @brief	Fill a selection of 45 degree arcs of a circle
+	 * @pre		GDISP_NEED_ARCSECTORS must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The center of the circle
+	 * @param[in] radius	The radius of the circle
+	 * @param[in] sectors	Bits determine which sectors are drawn.
+	 * 						Bits go anti-clockwise from the 0 degree mark (y = 0, x is positive), as follows:
+	 *  						bit 0 - upper right right		  -----
+	 *  						bit 1 - upper upper right		 /2   1\
+	 *  						bit 2 - upper upper left		/3     0\
+	 *  						bit 3 - upper left  left		\4     7/
+	 *  						bit 4 - lower left  left		 \5   6/
+	 *  						bit 5 - lower lower left		  -----
+	 *  						bit 6 - lower lower right
+	 *  						bit 7 - lower left  left
+	 * @param[in] color		The color to use
+	 *
+	 * @note	This is a more limited versions of the general arc filling routine. It
+	 * 			doesn't require trig libraries or tables or floating point and is smaller in code size.
+	 * 			There is probably little point in including both this and the general
+	 * 			arc routine as the general arc routine can do everything this can do.
+	 *
+	 * @api
+	 */
+	void gdispGFillArcSectors(GDisplay *g, coord_t x, coord_t y, coord_t radius, uint8_t sectors, color_t color);
+	#define gdispFillArcSectors(x,y,r,s,c)						gdispGFillArcSectors(GDISP,x,y,r,s,c)
+#endif
+
+#if GDISP_NEED_ARC || defined(__DOXYGEN__)
+	/*
+	 * @brief	Draw an arc.
+	 * @pre		GDISP_NEED_ARC must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x0,y0		The center point
+	 * @param[in] radius	The radius of the arc
+	 * @param[in] start		The start angle (0 to 360)
+	 * @param[in] end		The end angle (0 to 360)
+	 * @param[in] color		The color of the arc
+	 *
+	 * @note		If you are just doing 45 degree angles consider using @p gdispDrawArcSectors() instead.
+	 * @note		This routine requires trig support. It can either come from your C runtime library
+	 * 				cos() and sin() which requires floating point support (and is slow), or you can define GFX_USE_GMISC
+	 * 				and either GMISC_NEED_FIXEDTRIG or GMISC_NEED_FASTTRIG.
+	 * 				GMISC_NEED_FASTTRIG uses table based floating point trig operations.
+	 * 				GMISC_NEED_FIXEDTRIG uses fixed point integer trig operations.
+	 * 				Note accuracy on both the table based options are more than adequate for the one degree
+	 * 				resolution provided by these arc routines. Both are much faster than your C runtime library.
+	 *
+	 * @api
+	 */
+	void gdispGDrawArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
+	#define gdispDrawArc(x,y,r,s,e,c)						gdispGDrawArc(GDISP,x,y,r,s,e,c)
+
+	/*
+	 * @brief	Draw a filled arc.
+	 * @pre		GDISP_NEED_ARC must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x0,y0		The center point
+	 * @param[in] radius	The radius of the arc
+	 * @param[in] start		The start angle (0 to 360)
+	 * @param[in] end		The end angle (0 to 360)
+	 * @param[in] color		The color of the arc
+	 *
+	 * @note		If you are just doing 45 degree angles consider using @p gdispFillArcSectors() instead.
+	 * @note		This routine requires trig support. It can either come from your C runtime library
+	 * 				cos() and sin() which requires floating point support (and is slow), or you can define GFX_USE_GMISC
+	 * 				and either GMISC_NEED_FIXEDTRIG or GMISC_NEED_FASTTRIG.
+	 * 				GMISC_NEED_FASTTRIG uses table based floating point trig operations.
+	 * 				GMISC_NEED_FIXEDTRIG uses fixed point integer trig operations.
+	 * 				Note accuracy on both the table based options are more than adequate for the one degree
+	 * 				resolution provided by these arc routines. Both are much faster than your C runtime library.
+	 *
+	 * @api
+	 */
+	void gdispGFillArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
+	#define gdispFillArc(x,y,r,s,e,c)						gdispGFillArc(GDISP,x,y,r,s,e,c)
+#endif
+
+/* Read a pixel Function */
+
+#if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__)
+	/**
+	 * @brief   Get the color of a pixel.
+	 * @return  The color of the pixel.
+	 * @pre		GDISP_NEED_PIXELREAD must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The position of the pixel
+	 *
+	 * @api
+	 */
+	color_t gdispGGetPixelColor(GDisplay *g, coord_t x, coord_t y);
+	#define gdispGetPixelColor(x,y)							gdispGGetPixelColor(GDISP,x,y)
+#endif
+
+/* Scrolling Function - clears the area scrolled out */
+
+#if GDISP_NEED_SCROLL || defined(__DOXYGEN__)
+	/**
+	 * @brief   Scroll vertically a section of the screen.
+	 * @pre		GDISP_NEED_SCROLL must be set to TRUE in gfxconf.h
+	 * @note    Optional.
+	 * @note    If lines is >= cy, it is equivelent to a area fill with bgcolor.
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x, y		The start of the area to be scrolled
+	 * @param[in] cx, cy	The size of the area to be scrolled
+	 * @param[in] lines		The number of lines to scroll (Can be positive or negative)
+	 * @param[in] bgcolor	The color to fill the newly exposed area.
+	 *
+	 * @api
+	 */
+	void gdispGVerticalScroll(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor);
+	#define gdispVerticalScroll(x,y,cx,cy,l,b)				gdispGVerticalScroll(GDISP,x,y,cx,cy,l,b)
+#endif
+
+/* Set driver specific control */
+
+#if GDISP_NEED_CONTROL || defined(__DOXYGEN__)
+	/**
+	 * @brief   Control hardware specific parts of the display. eg powermodes, backlight etc
+	 * @pre		GDISP_NEED_CONTROL must be TRUE in your gfxconf.h
+	 * @note    Depending on the hardware implementation this function may not
+	 *          support some codes. They will be ignored.
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] what		what you want to control
+	 * @param[in] value		The value to be assigned
+	 *
+	 * @api
+	 */
+	void gdispGControl(GDisplay *g, unsigned what, void *value);
+	#define gdispControl(w,v)								gdispGControl(GDISP,w,v)
+#endif
+
+/* Query driver specific data */
+
+#if GDISP_NEED_QUERY || defined(__DOXYGEN__)
+	/**
+	 * @brief   Query a property of the display.
+	 * @pre		GDISP_NEED_QUERY must be TRUE in your gfxconf.h
+	 * @note    The result must be typecast to the correct type.
+	 * @note    An unsupported query will return (void *)-1.
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] what		What to query
+	 *
+	 * @api
+	 */
+	void *gdispGQuery(GDisplay *g, unsigned what);
+	#define gdispQuery(w)									gdispGQuery(GDISP,w)
+#endif
+
+#if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__)
+	/**
+	 * @brief   Draw an enclosed polygon (convex, non-convex or complex).
+	 * @pre		GDISP_NEED_CONVEX_POLYGON must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] tx, ty	Transform all points in pntarray by tx, ty
+	 * @param[in] pntarray	An array of points
+	 * @param[in] cnt		The number of points in the array
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGDrawPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color);
+	#define gdispDrawPoly(x,y,p,i,c)						gdispGDrawPoly(GDISP,x,y,p,i,c)
+
+	/**
+	 * @brief   Fill a convex polygon
+	 * @details Doesn't handle non-convex or complex polygons.
+	 * @pre		GDISP_NEED_CONVEX_POLYGON must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] tx, ty	Transform all points in pntarray by tx, ty
+	 * @param[in] pntarray	An array of points
+	 * @param[in] cnt		The number of points in the array
+	 * @param[in] color		The color to use
+	 *
+	 * @note	Convex polygons are those that have no internal angles. That is;
+	 * 			you can draw a line from any point on the polygon to any other point
+	 * 			on the polygon without it going outside the polygon. In our case we generalise
+	 * 			this a little by saying that an infinite horizontal line (at any y value) will cross
+	 * 			no more than two edges on the polygon. Some non-convex polygons do fit this criteria
+	 * 			and can therefore be drawn.
+	 * @note	This routine is designed to be very efficient with even simple display hardware.
+	 *
+	 * @api
+	 */
+	void gdispGFillConvexPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color);
+	#define gdispFillConvexPoly(x,y,p,i,c)					gdispGFillConvexPoly(GDISP,x,y,p,i,c)
+
+	/**
+	 * @brief   Draw a line with a specified thickness
+	 * @details The line thickness is specified in pixels. The line ends can
+	 *          be selected to be either flat or round.
+	 * @pre		GDISP_NEED_CONVEX_POLYGON must be TRUE in your gfxconf.h
+	 * @note	Uses gdispGFillConvexPoly() internally to perform the drawing.
+	 *
+	 * @param[in] g			The display to use
+	 * @param[in] x0,y0		The start position
+	 * @param[in] x1,y1		The end position
+	 * @param[in] color		The color to use
+	 * @param[in] width		The width of the line
+	 * @param[in] round		Use round ends for the line
+	 *
+	 * @api
+	 */
+	void gdispGDrawThickLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color, coord_t width, bool_t round);
+	#define gdispDrawThickLine(x0,y0,x1,y1,c,w,r)			gdispGDrawThickLine(GDISP,x0,y0,x1,y1,c,w,r)
+#endif
+
+/* Text Functions */
+
+#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
+	/**
+	 * @brief   Draw a text character.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The position for the text
+	 * @param[in] c			The character to draw
+	 * @param[in] font		The font to use
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGDrawChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color);
+	#define	gdispDrawChar(x,y,s,f,c)						gdispGDrawChar(GDISP,x,y,s,f,c)
+
+	/**
+	 * @brief   Draw a text character with a filled background.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The position for the text
+	 * @param[in] c			The character to draw
+	 * @param[in] font		The font to use
+	 * @param[in] color		The color to use
+	 * @param[in] bgcolor	The background color to use
+	 *
+	 * @api
+	 */
+	void gdispGFillChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor);
+	#define	gdispFillChar(x,y,s,f,c,b)						gdispGFillChar(GDISP,x,y,s,f,c,b)
+
+	/**
+	 * @brief   Draw a text string.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The position for the text
+	 * @param[in] str		The string to draw
+	 * @param[in] font		The font to use
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGDrawString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color);
+	#define	gdispDrawString(x,y,s,f,c)						gdispGDrawString(GDISP,x,y,s,f,c)
+
+	/**
+	 * @brief   Draw a text string.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The position for the text
+	 * @param[in] str		The string to draw
+	 * @param[in] font		The font to use
+	 * @param[in] color		The color to use
+	 * @param[in] bgcolor	The background color to use
+	 *
+	 * @api
+	 */
+	void gdispGFillString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor);
+	#define	gdispFillString(x,y,s,f,c,b)					gdispGFillString(GDISP,x,y,s,f,c,b)
+
+	/**
+	 * @brief   Draw a text string vertically centered within the specified box.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
+	 * @param[in] cx,cy		The width and height of the box
+	 * @param[in] str		The string to draw
+	 * @param[in] font		The font to use
+	 * @param[in] color		The color to use
+	 * @param[in] justify	Justify the text left, center or right within the box
+	 *
+	 * @api
+	 */
+	void gdispGDrawStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify);
+	#define	gdispDrawStringBox(x,y,cx,cy,s,f,c,j)			gdispGDrawStringBox(GDISP,x,y,cx,cy,s,f,c,j)
+
+	/**
+	 * @brief   Draw a text string vertically centered within the specified box. The box background is filled with the specified background color.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 * @note    The entire box is filled
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
+	 * @param[in] cx,cy		The width and height of the box
+	 * @param[in] str		The string to draw
+	 * @param[in] font		The font to use
+	 * @param[in] color		The color to use
+	 * @param[in] bgColor	The background color to use
+	 * @param[in] justify	Justify the text left, center or right within the box
+	 *
+	 * @api
+	 */
+	void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgColor, justify_t justify);
+	#define	gdispFillStringBox(x,y,cx,cy,s,f,c,b,j)			gdispGFillStringBox(GDISP,x,y,cx,cy,s,f,c,b,j)
+
+	/**
+	 * @brief   Get a metric of a font.
+	 * @return  The metric requested in pixels.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] font    The font to test
+	 * @param[in] metric  The metric to measure
+	 *
+	 * @api
+	 */
+	coord_t gdispGetFontMetric(font_t font, fontmetric_t metric);
+
+	/**
+	 * @brief   Get the pixel width of a character.
+	 * @return  The width of the character in pixels. Does not include any between character padding.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] c       The character to draw
+	 * @param[in] font    The font to use
+	 *
+	 * @api
+	 */
+	coord_t gdispGetCharWidth(char c, font_t font);
+
+	/**
+	 * @brief   Get the pixel width of a string.
+	 * @return  The width of the string in pixels.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] str     The string to measure
+	 * @param[in] font    The font to use
+	 *
+	 * @api
+	 */
+	coord_t gdispGetStringWidth(const char* str, font_t font);
+
+	/**
+	 * @brief	Find a font and return it.
+	 * @details	The supplied name is matched against the font name. A '*' will replace 0 or more characters.
+	 * @return	Returns a font or NULL if no matching font could be found.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] name		The font name to find.
+	 *
+	 * @note				Wildcard matching will match the shortest possible match.
+	 *
+	 * @api
+	 */
+	font_t gdispOpenFont(const char *name);
+
+	/**
+	 * @brief	Release a font after use.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] font		The font to release.
+	 *
+	 * @api
+	 */
+	void gdispCloseFont(font_t font);
+
+	/**
+	 * @brief	Make a scaled copy of an existing font.
+	 * @details	Allocates memory for new font metadata using gfxAlloc, remember to close font after use!
+	 * @return	A new font or NULL if out of memory.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] font	The base font to use.
+	 * @param[in] scale_x	The scale factor in horizontal direction.
+	 * @param[in] scale_y	The scale factor in vertical direction.
+	 */
+	font_t gdispScaleFont(font_t font, uint8_t scale_x, uint8_t scale_y);
+
+	/**
+	 * @brief	Get the name of the specified font.
+	 * @returns	The name of the font.
+	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] font		The font to get the name for.
+	 *
+	 * @api
+	 */
+	const char *gdispGetFontName(font_t font);
+#endif
+
+/* Extra Arc Functions */
+
+#if GDISP_NEED_ARC || GDISP_NEED_ARCSECTORS || defined(__DOXYGEN__)
+	/**
+	 * @brief   Draw a rectangular box with rounded corners
+	 * @pre		GDISP_NEED_ARC or GDISP_NEED_ARCSECTORS must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The start position
+	 * @param[in] cx,cy		The size of the box (outside dimensions)
+	 * @param[in] radius	The radius of the rounded corners
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGDrawRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color);
+	#define gdispDrawRoundedBox(x,y,cx,cy,r,c)		gdispGDrawRoundedBox(GDISP,x,y,cx,cy,r,c)
+
+	/**
+	 * @brief   Draw a filled rectangular box with rounded corners
+	 * @pre		GDISP_NEED_ARC or GDISP_NEED_ARCSECTORS must be TRUE in your gfxconf.h
+	 *
+	 * @param[in] g 		The display to use
+	 * @param[in] x,y		The start position
+	 * @param[in] cx,cy		The size of the box (outside dimensions)
+	 * @param[in] radius	The radius of the rounded corners
+	 * @param[in] color		The color to use
+	 *
+	 * @api
+	 */
+	void gdispGFillRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color);
+	#define gdispFillRoundedBox(x,y,cx,cy,r,c)		gdispGFillRoundedBox(GDISP,x,y,cx,cy,r,c)
+#endif
+
+/*
+ * Macro definitions
+ */
+
+/* Now obsolete functions */
+#define gdispBlitArea(x, y, cx, cy, buffer)			gdispGBlitArea(GDISP, x, y, cx, cy, 0, 0, cx, buffer)
+
+/* Macro definitions for common gets and sets */
+
+/**
+ * @brief   Set the display power mode.
+ * @note    Ignored if not supported by the display.
+ *
+ * @param[in] g 			The display to use
+ * @param[in] powerMode		The new power mode
+ *
+ * @api
+ */
+#define gdispGSetPowerMode(g, powerMode)			gdispGControl((g), GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode))
+#define gdispSetPowerMode(powerMode)				gdispGControl(GDISP, GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode))
+
+/**
+ * @brief   Set the display orientation.
+ * @note    Ignored if not supported by the display.
+ *
+ * @param[in] g 					The display to use
+ * @param[in] newOrientation		The new orientation
+ *
+ * @api
+ */
+#define gdispGSetOrientation(g, newOrientation)		gdispGControl((g), GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation))
+#define gdispSetOrientation(newOrientation)			gdispGControl(GDISP, GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation))
+
+/**
+ * @brief   Set the display backlight.
+ * @note    Ignored if not supported by the display.
+ *
+ * @param[in] g 			The display to use
+ * @param[in] percent		The new brightness (0 - 100%)
+ *
+ * @note	For displays that only support backlight off and on,
+ * 			0 = off, anything else = on
+ *
+ * @api
+ */
+#define gdispGSetBacklight(g, percent)				gdispGControl((g), GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent))
+#define gdispSetBacklight(percent)					gdispGControl(GDISP, GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent))
+
+/**
+ * @brief   Set the display contrast.
+ * @note    Ignored if not supported by the display.
+ *
+ * @param[in] g 			The display to use
+ * @param[in] percent		The new contrast (0 - 100%)
+ *
+ * @api
+ */
+#define gdispGSetContrast(g, percent)				gdispGControl((g), GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent))
+#define gdispSetContrast(percent)					gdispGControl(GDISP, GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent))
+
+/* More interesting macros */
+
+/**
+ * @brief   Reset the clip area to the full screen
+ *
+ * @param[in] g 		The display to use
+ *
+ * @api
+ */
+#define gdispGUnsetClip(g)							gdispGSetClip((g),0,0,gdispGGetWidth(g),gdispGGetHeight(g))
+#define gdispUnsetClip()							gdispGUnsetClip(GDISP)
+
+#ifdef __cplusplus
+}
+#endif
+
+#if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
+	#include "gdisp_image.h"
+#endif
+#if GDISP_NEED_PIXMAP || defined(__DOXYGEN__)
+	#include "gdisp_pixmap.h"
+#endif
+
+
+#endif /* GFX_USE_GDISP */
+
+#endif /* _GDISP_H */
+/** @} */
diff --git a/src/gdisp/gdisp.mk b/src/gdisp/gdisp.mk
new file mode 100644
index 00000000..3c8af80a
--- /dev/null
+++ b/src/gdisp/gdisp.mk
@@ -0,0 +1,14 @@
+GFXSRC +=   $(GFXLIB)/src/gdisp/gdisp.c \
+			$(GFXLIB)/src/gdisp/gdisp_fonts.c \
+			$(GFXLIB)/src/gdisp/gdisp_pixmap.c \
+			$(GFXLIB)/src/gdisp/gdisp_image.c \
+			$(GFXLIB)/src/gdisp/gdisp_image_native.c \
+			$(GFXLIB)/src/gdisp/gdisp_image_gif.c \
+			$(GFXLIB)/src/gdisp/gdisp_image_bmp.c \
+			$(GFXLIB)/src/gdisp/gdisp_image_jpg.c \
+			$(GFXLIB)/src/gdisp/gdisp_image_png.c
+			
+MFDIR = $(GFXLIB)/src/gdisp/mcufont
+include $(GFXLIB)/src/gdisp/mcufont/mcufont.mk
+GFXINC += $(MFDIR)
+GFXSRC += $(MFSRC)
diff --git a/src/gdisp/gdisp_driver.h b/src/gdisp/gdisp_driver.h
new file mode 100644
index 00000000..085e248f
--- /dev/null
+++ b/src/gdisp/gdisp_driver.h
@@ -0,0 +1,1070 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gdisp/gdisp_driver.h
+ * @brief   GDISP Graphic Driver subsystem low level driver header.
+ *
+ * @addtogroup GDISP
+ * @{
+ */
+
+#ifndef _GDISP_LLD_H
+#define _GDISP_LLD_H
+
+#if GFX_USE_GDISP
+
+// Include the GDRIVER infrastructure
+#include "src/gdriver/gdriver.h"
+
+// Are we currently compiling the driver itself?
+#if defined(GDISP_DRIVER_VMT)
+	#define	IN_DRIVER			TRUE
+#else
+	#define	IN_DRIVER			FALSE
+#endif
+
+// Is this a multiple driver situation?
+#if defined(GDISP_DRIVER_LIST)
+	#define IS_MULTIPLE			TRUE
+#else
+	#define IS_MULTIPLE			FALSE
+#endif
+
+// Do we need to use VMT calling rather than direct calls to the driver?
+#if IS_MULTIPLE || GDISP_NEED_PIXMAP
+	#define USE_VMT				TRUE
+#else
+	#define USE_VMT				FALSE
+#endif
+
+// Are we in the pixmap virtual driver
+#ifndef IN_PIXMAP_DRIVER
+	#define IN_PIXMAP_DRIVER	FALSE
+#endif
+
+//------------------------------------------------------------------------------------------------------------
+
+// Our special auto-detect hardware code which uses the VMT.
+#define HARDWARE_AUTODETECT		2
+
+#if USE_VMT && !IN_DRIVER
+	// Multiple controllers the default is to hardware detect
+	#define HARDWARE_DEFAULT		HARDWARE_AUTODETECT
+#else
+	// The default is not to include code functions that aren't needed
+	#define HARDWARE_DEFAULT		FALSE
+#endif
+
+//------------------------------------------------------------------------------------------------------------
+
+/**
+ * @name    GDISP hardware accelerated support
+ * @{
+ */
+	/**
+	 * @brief   The display hardware can benefit from being de-initialized when usage is complete.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 * @note	This is most useful for displays such as remote network displays.
+	 */
+	#ifndef GDISP_HARDWARE_DEINIT
+		#define GDISP_HARDWARE_DEINIT		HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   The display hardware can benefit from being flushed.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 * @note	Some controllers ** require ** the application to flush
+	 */
+	#ifndef GDISP_HARDWARE_FLUSH
+		#define GDISP_HARDWARE_FLUSH		HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Hardware streaming writing is supported.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 * @note	Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by each driver
+	 */
+	#ifndef GDISP_HARDWARE_STREAM_WRITE
+		#define GDISP_HARDWARE_STREAM_WRITE		HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Hardware streaming reading of the display surface is supported.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 *
+	 */
+	#ifndef GDISP_HARDWARE_STREAM_READ
+		#define GDISP_HARDWARE_STREAM_READ		HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Hardware supports setting the cursor position within the stream window.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 * @note	This is used to optimise setting of individual pixels within a stream window.
+	 * 			It should therefore not be implemented unless it is cheaper than just setting
+	 * 			a new window.
+	 */
+	#ifndef GDISP_HARDWARE_STREAM_POS
+		#define GDISP_HARDWARE_STREAM_POS		HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Hardware accelerated draw pixel.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 * @note	Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver
+	 */
+	#ifndef GDISP_HARDWARE_DRAWPIXEL
+		#define GDISP_HARDWARE_DRAWPIXEL		HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Hardware accelerated screen clears.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 * @note	This clears the entire display surface regardless of the clipping area currently set
+	 */
+	#ifndef GDISP_HARDWARE_CLEARS
+		#define GDISP_HARDWARE_CLEARS			HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Hardware accelerated rectangular fills.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 */
+	#ifndef GDISP_HARDWARE_FILLS
+		#define GDISP_HARDWARE_FILLS			HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Hardware accelerated fills from an image.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 */
+	#ifndef GDISP_HARDWARE_BITFILLS
+		#define GDISP_HARDWARE_BITFILLS			HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Hardware accelerated scrolling.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 */
+	#ifndef GDISP_HARDWARE_SCROLL
+		#define GDISP_HARDWARE_SCROLL			HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   Reading back of pixel values.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 */
+	#ifndef GDISP_HARDWARE_PIXELREAD
+		#define GDISP_HARDWARE_PIXELREAD		HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   The driver supports one or more control commands.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 */
+	#ifndef GDISP_HARDWARE_CONTROL
+		#define GDISP_HARDWARE_CONTROL			HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   The driver supports a non-standard query.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 */
+	#ifndef GDISP_HARDWARE_QUERY
+		#define GDISP_HARDWARE_QUERY			HARDWARE_DEFAULT
+	#endif
+
+	/**
+	 * @brief   The driver supports a clipping in hardware.
+	 * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT
+	 *
+	 * @note	HARDWARE_AUTODETECT is only meaningful when GDISP_DRIVER_LIST is defined
+	 * @note	If this is defined the driver must perform its own clipping on all calls to
+	 * 			the driver and respond appropriately if a parameter is outside the display area.
+	 * @note	If this is not defined then the software ensures that all calls to the
+	 * 			driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION
+	 * 			has been set).
+	 */
+	#ifndef GDISP_HARDWARE_CLIP
+		#define GDISP_HARDWARE_CLIP				HARDWARE_DEFAULT
+	#endif
+/** @} */
+
+//------------------------------------------------------------------------------------------------------------
+
+// For pixmaps certain routines MUST not be FALSE as they are needed for pixmap drawing
+//	Similarly some routines MUST not be TRUE as pixmap's don't provide them.
+#if GDISP_NEED_PIXMAP && !IN_DRIVER
+	#if !GDISP_HARDWARE_DEINIT
+		#undef GDISP_HARDWARE_DEINIT
+		#define GDISP_HARDWARE_DEINIT		HARDWARE_AUTODETECT
+	#endif
+	#if !GDISP_HARDWARE_DRAWPIXEL
+		#undef GDISP_HARDWARE_DRAWPIXEL
+		#define GDISP_HARDWARE_DRAWPIXEL	HARDWARE_AUTODETECT
+	#endif
+	#if !GDISP_HARDWARE_PIXELREAD
+		#undef GDISP_HARDWARE_PIXELREAD
+		#define GDISP_HARDWARE_PIXELREAD	HARDWARE_AUTODETECT
+	#endif
+	#if !GDISP_HARDWARE_CONTROL
+		#undef GDISP_HARDWARE_CONTROL
+		#define GDISP_HARDWARE_CONTROL		HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_FLUSH == TRUE
+		#undef GDISP_HARDWARE_FLUSH
+		#define GDISP_HARDWARE_FLUSH		HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_STREAM_WRITE == TRUE
+		#undef GDISP_HARDWARE_STREAM_WRITE
+		#define GDISP_HARDWARE_STREAM_WRITE	HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_STREAM_READ == TRUE
+		#undef GDISP_HARDWARE_STREAM_READ
+		#define GDISP_HARDWARE_STREAM_READ	HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_CLEARS == TRUE
+		#undef GDISP_HARDWARE_CLEARS
+		#define GDISP_HARDWARE_CLEARS		HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_FILLS == TRUE
+		#undef GDISP_HARDWARE_FILLS
+		#define GDISP_HARDWARE_FILLS		HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_BITFILLS == TRUE
+		#undef GDISP_HARDWARE_BITFILLS
+		#define GDISP_HARDWARE_BITFILLS		HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_SCROLL == TRUE
+		#undef GDISP_HARDWARE_SCROLL
+		#define GDISP_HARDWARE_SCROLL		HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_QUERY == TRUE
+		#undef GDISP_HARDWARE_QUERY
+		#define GDISP_HARDWARE_QUERY		HARDWARE_AUTODETECT
+	#endif
+	#if GDISP_HARDWARE_CLIP == TRUE
+		#undef GDISP_HARDWARE_CLIP
+		#define GDISP_HARDWARE_CLIP			HARDWARE_AUTODETECT
+	#endif
+#endif
+
+//------------------------------------------------------------------------------------------------------------
+
+/* Verify information for packed pixels and define a non-packed pixel macro */
+#if !GDISP_PACKED_PIXELS
+	#define gdispPackPixels(buf,cx,x,y,c)	{ ((color_t *)(buf))[(y)*(cx)+(x)] = (c); }
+#elif !GDISP_HARDWARE_BITFILLS
+	#error "GDISP: packed pixel formats are only supported for hardware accelerated drivers."
+#elif GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 \
+		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB444 \
+		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB666 \
+		&& GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_CUSTOM
+	#error "GDISP: A packed pixel format has been specified for an unsupported pixel format."
+#endif
+
+/* Support routine for packed pixel formats */
+#if !defined(gdispPackPixels) || defined(__DOXYGEN__)
+	/**
+	 * @brief   Pack a pixel into a pixel buffer.
+	 * @note    This function performs no buffer boundary checking
+	 *			regardless of whether GDISP_NEED_CLIP has been specified.
+	 *
+	 * @param[in] buf		The buffer to put the pixel in
+	 * @param[in] cx		The width of a pixel line
+	 * @param[in] x, y		The location of the pixel to place
+	 * @param[in] color		The color to put into the buffer
+	 *
+	 * @api
+	 */
+	void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color);
+#endif
+
+//------------------------------------------------------------------------------------------------------------
+
+struct GDisplay {
+	struct GDriver				d;					// This must be the first element
+		#define gvmt(g)		((const GDISPVMT const *)((g)->d.vmt))	// For ease of access to the vmt member
+
+	struct GDISPControl {
+		coord_t					Width;
+		coord_t					Height;
+		orientation_t			Orientation;
+		powermode_t				Powermode;
+		uint8_t					Backlight;
+		uint8_t					Contrast;
+	} g;
+
+	void *						priv;				// A private area just for the drivers use.
+	void *						board;				// A private area just for the board interfaces use.
+
+	uint8_t						systemdisplay;
+	uint8_t						controllerdisplay;
+	uint16_t					flags;
+		#define GDISP_FLG_INSTREAM		0x0001		// We are in a user based stream operation
+		#define GDISP_FLG_SCRSTREAM		0x0002		// The stream area currently covers the whole screen
+		#define GDISP_FLG_DRIVER		0x0004		// This flags and above are for use by the driver
+
+	// Multithread Mutex
+	#if GDISP_NEED_MULTITHREAD
+		gfxMutex				mutex;
+	#endif
+
+	// Software clipping
+	#if GDISP_HARDWARE_CLIP != TRUE && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)
+		coord_t					clipx0, clipy0;
+		coord_t					clipx1, clipy1;		/* not inclusive */
+	#endif
+
+	// Driver call parameters
+	struct {
+		coord_t			x, y;
+		coord_t			cx, cy;
+		coord_t			x1, y1;
+		coord_t			x2, y2;
+		color_t			color;
+		void			*ptr;
+	} p;
+
+	// In call working buffers
+
+	#if GDISP_NEED_TEXT
+		// Text rendering parameters
+		struct {
+			font_t		font;
+			color_t		color;
+			color_t		bgcolor;
+			coord_t		clipx0, clipy0;
+			coord_t		clipx1, clipy1;
+		} t;
+	#endif
+	#if GDISP_LINEBUF_SIZE != 0 && ((GDISP_NEED_SCROLL && !GDISP_HARDWARE_SCROLL) || (!GDISP_HARDWARE_STREAM_WRITE && GDISP_HARDWARE_BITFILLS))
+		// A pixel line buffer
+		color_t		linebuf[GDISP_LINEBUF_SIZE];
+	#endif
+};
+
+typedef struct GDISPVMT {
+	GDriverVMT	d;
+		#define GDISP_VFLG_DYNAMICONLY		0x0001		// This display should never be statically initialised
+		#define GDISP_VFLG_PIXMAP			0x0002		// This is a pixmap display
+	bool_t (*init)(GDisplay *g);
+	void (*deinit)(GDisplay *g);
+	void (*writestart)(GDisplay *g);				// Uses p.x,p.y  p.cx,p.cy
+	void (*writepos)(GDisplay *g);					// Uses p.x,p.y
+	void (*writecolor)(GDisplay *g);				// Uses p.color
+	void (*writestop)(GDisplay *g);					// Uses no parameters
+	void (*readstart)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy
+	color_t (*readcolor)(GDisplay *g);				// Uses no parameters
+	void (*readstop)(GDisplay *g);					// Uses no parameters
+	void (*pixel)(GDisplay *g);						// Uses p.x,p.y  p.color
+	void (*clear)(GDisplay *g);						// Uses p.color
+	void (*fill)(GDisplay *g);						// Uses p.x,p.y  p.cx,p.cy  p.color
+	void (*blit)(GDisplay *g);						// Uses p.x,p.y  p.cx,p.cy  p.x1,p.y1 (=srcx,srcy)  p.x2 (=srccx), p.ptr (=buffer)
+	color_t (*get)(GDisplay *g);					// Uses p.x,p.y
+	void (*vscroll)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy, p.y1 (=lines) p.color
+	void (*control)(GDisplay *g);					// Uses p.x (=what)  p.ptr (=value)
+	void *(*query)(GDisplay *g);					// Uses p.x (=what);
+	void (*setclip)(GDisplay *g);					// Uses p.x,p.y  p.cx,p.cy
+	void (*flush)(GDisplay *g);						// Uses no parameters
+} GDISPVMT;
+
+//------------------------------------------------------------------------------------------------------------
+
+// Do we need function definitions or macro's (via the VMT)
+#if IN_DRIVER || !USE_VMT || defined(__DOXYGEN__)
+	#ifdef __cplusplus
+	extern "C" {
+	#endif
+
+	// Should the driver routines should be static or not
+	#if USE_VMT
+		#define LLDSPEC         static
+	#else
+		#define LLDSPEC
+	#endif
+
+	/**
+	 * @brief   Initialize the driver.
+	 * @return	TRUE if successful.
+	 * @param[in]	g					The driver structure
+	 * @param[out]	g->g				The driver must fill in the GDISPControl structure
+	 */
+	LLDSPEC	bool_t gdisp_lld_init(GDisplay *g);
+
+	#if GDISP_HARDWARE_DEINIT || defined(__DOXYGEN__)
+		/**
+		 * @brief   The driver is being de-initialized
+		 * @pre		GDISP_HARDWARE_FLUSH is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 *
+		 */
+		LLDSPEC	void gdisp_lld_deinit(GDisplay *g);
+	#endif
+
+	#if GDISP_HARDWARE_FLUSH || defined(__DOXYGEN__)
+		/**
+		 * @brief   Flush the current drawing operations to the display
+		 * @pre		GDISP_HARDWARE_FLUSH is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_flush(GDisplay *g);
+	#endif
+
+	#if GDISP_HARDWARE_STREAM_WRITE || defined(__DOXYGEN__)
+		/**
+		 * @brief   Start a streamed write operation
+		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 *
+		 * @note		g->p.x,g->p.y	The window position
+		 * @note		g->p.cx,g->p.cy	The window size
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 * @note		Streaming operations that wrap the defined window have
+		 * 				undefined results.
+		 * @note		This must be followed by a call to @p gdisp_lld_write_pos() if GDISP_HARDWARE_STREAM_POS is TRUE.
+		 */
+		LLDSPEC	void gdisp_lld_write_start(GDisplay *g);
+
+		/**
+		 * @brief   Send a pixel to the current streaming position and then increment that position
+		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 *
+		 * @note		g->p.color		The color to display at the curent position
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_write_color(GDisplay *g);
+
+		/**
+		 * @brief   End the current streaming write operation
+		 * @pre		GDISP_HARDWARE_STREAM_WRITE is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_write_stop(GDisplay *g);
+
+		#if GDISP_HARDWARE_STREAM_POS || defined(__DOXYGEN__)
+			/**
+			 * @brief   Change the current position within the current streaming window
+			 * @pre		GDISP_HARDWARE_STREAM_POS is TRUE and GDISP_HARDWARE_STREAM_WRITE is TRUE
+			 *
+			 * @param[in]	g				The driver structure
+			 * @param[in]	g->p.x,g->p.y	The new position (which will always be within the existing stream window)
+			 *
+			 * @note		The parameter variables must not be altered by the driver.
+			 */
+			LLDSPEC	void gdisp_lld_write_pos(GDisplay *g);
+		#endif
+	#endif
+
+	#if GDISP_HARDWARE_STREAM_READ || defined(__DOXYGEN__)
+		/**
+		 * @brief   Start a streamed read operation
+		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x,g->p.y	The window position
+		 * @param[in]	g->p.cx,g->p.cy	The window size
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 * @note		Streaming operations that wrap the defined window have
+		 * 				undefined results.
+		 */
+		LLDSPEC	void gdisp_lld_read_start(GDisplay *g);
+
+		/**
+		 * @brief   Read a pixel from the current streaming position and then increment that position
+		 * @return	The color at the current position
+		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	color_t gdisp_lld_read_color(GDisplay *g);
+
+		/**
+		 * @brief   End the current streaming operation
+		 * @pre		GDISP_HARDWARE_STREAM_READ is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_read_stop(GDisplay *g);
+	#endif
+
+	#if GDISP_HARDWARE_DRAWPIXEL || defined(__DOXYGEN__)
+		/**
+		 * @brief   Draw a pixel
+		 * @pre		GDISP_HARDWARE_DRAWPIXEL is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x,g->p.y	The pixel position
+		 * @param[in]	g->p.color		The color to set
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_draw_pixel(GDisplay *g);
+	#endif
+
+	#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__)
+		/**
+		 * @brief   Clear the screen using the defined color
+		 * @pre		GDISP_HARDWARE_CLEARS is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.color		The color to set
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_clear(GDisplay *g);
+	#endif
+
+	#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__)
+		/**
+		 * @brief   Fill an area with a single color
+		 * @pre		GDISP_HARDWARE_FILLS is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x,g->p.y	The area position
+		 * @param[in]	g->p.cx,g->p.cy	The area size
+		 * @param[in]	g->p.color		The color to set
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_fill_area(GDisplay *g);
+	#endif
+
+	#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__)
+		/**
+		 * @brief   Fill an area using a bitmap
+		 * @pre		GDISP_HARDWARE_BITFILLS is TRUE
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x,g->p.y	The area position
+		 * @param[in]	g->p.cx,g->p.cy	The area size
+		 * @param[in]	g->p.x1,g->p.y1	The starting position in the bitmap
+		 * @param[in]	g->p.x2			The width of a bitmap line
+		 * @param[in]	g->p.ptr		The pointer to the bitmap
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_blit_area(GDisplay *g);
+	#endif
+
+	#if GDISP_HARDWARE_PIXELREAD || defined(__DOXYGEN__)
+		/**
+		 * @brief   Read a pixel from the display
+		 * @return	The color at the defined position
+		 * @pre		GDISP_HARDWARE_PIXELREAD is TRUE (and the application needs it)
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x,g->p.y	The pixel position
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	color_t gdisp_lld_get_pixel_color(GDisplay *g);
+	#endif
+
+	#if (GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL) || defined(__DOXYGEN__)
+		/**
+		 * @brief   Scroll an area of the screen
+		 * @pre		GDISP_HARDWARE_SCROLL is TRUE (and the application needs it)
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x,g->p.y	The area position
+		 * @param[in]	g->p.cx,g->p.cy	The area size
+		 * @param[in]	g->p.y1			The number of lines to scroll (positive or negative)
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 * @note		This can be easily implemented if the hardware supports
+		 * 				display area to display area copying.
+		 * @note		Clearing the exposed area on the scroll operation is not
+		 * 				needed as the high level code handles this.
+		 */
+		LLDSPEC	void gdisp_lld_vertical_scroll(GDisplay *g);
+	#endif
+
+	#if (GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL) || defined(__DOXYGEN__)
+		/**
+		 * @brief   Control some feature of the hardware
+		 * @pre		GDISP_HARDWARE_CONTROL is TRUE (and the application needs it)
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x			The operation to perform
+		 * @param[in]	g->p.ptr		The operation parameter
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_control(GDisplay *g);
+	#endif
+
+	#if (GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY) || defined(__DOXYGEN__)
+		/**
+		 * @brief   Query some feature of the hardware
+		 * @return	The information requested (typecast as void *)
+		 * @pre		GDISP_HARDWARE_QUERY is TRUE (and the application needs it)
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x			What to query
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void *gdisp_lld_query(GDisplay *g);				// Uses p.x (=what);
+	#endif
+
+	#if (GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)) || defined(__DOXYGEN__)
+		/**
+		 * @brief   Set the hardware clipping area
+		 * @pre		GDISP_HARDWARE_CLIP is TRUE (and the application needs it)
+		 *
+		 * @param[in]	g				The driver structure
+		 * @param[in]	g->p.x,g->p.y	The area position
+		 * @param[in]	g->p.cx,g->p.cy	The area size
+		 *
+		 * @note		The parameter variables must not be altered by the driver.
+		 */
+		LLDSPEC	void gdisp_lld_set_clip(GDisplay *g);
+	#endif
+
+	#ifdef __cplusplus
+	}
+	#endif
+
+#else
+	#define gdisp_lld_init(g)				gvmt(g)->init(g)
+	#define gdisp_lld_deinit(g)				gvmt(g)->deinit(g)
+	#define gdisp_lld_flush(g)				gvmt(g)->flush(g)
+	#define gdisp_lld_write_start(g)		gvmt(g)->writestart(g)
+	#define gdisp_lld_write_pos(g)			gvmt(g)->writepos(g)
+	#define gdisp_lld_write_color(g)		gvmt(g)->writecolor(g)
+	#define gdisp_lld_write_stop(g)			gvmt(g)->writestop(g)
+	#define gdisp_lld_read_start(g)			gvmt(g)->readstart(g)
+	#define gdisp_lld_read_color(g)			gvmt(g)->readcolor(g)
+	#define gdisp_lld_read_stop(g)			gvmt(g)->readstop(g)
+	#define gdisp_lld_draw_pixel(g)			gvmt(g)->pixel(g)
+	#define gdisp_lld_clear(g)				gvmt(g)->clear(g)
+	#define gdisp_lld_fill_area(g)			gvmt(g)->fill(g)
+	#define gdisp_lld_blit_area(g)			gvmt(g)->blit(g)
+	#define gdisp_lld_get_pixel_color(g)	gvmt(g)->get(g)
+	#define gdisp_lld_vertical_scroll(g)	gvmt(g)->vscroll(g)
+	#define gdisp_lld_control(g)			gvmt(g)->control(g)
+	#define gdisp_lld_query(g)				gvmt(g)->query(g)
+	#define gdisp_lld_set_clip(g)			gvmt(g)->setclip(g)
+#endif
+
+//------------------------------------------------------------------------------------------------------------
+
+// If compiling the driver then build the VMT and set the low level driver color macros.
+#if IN_DRIVER
+
+	// Make sure the driver has a valid model
+	#if !GDISP_HARDWARE_STREAM_WRITE && !GDISP_HARDWARE_DRAWPIXEL
+		#error "GDISP Driver: Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be TRUE"
+	#endif
+
+	// If we are not using multiple displays then hard-code the VMT name (except for the pixmap driver)
+	#if !IS_MULTIPLE && !IN_PIXMAP_DRIVER
+		#undef GDISP_DRIVER_VMT
+		#define GDISP_DRIVER_VMT		GDISPVMT_OnlyOne
+	#endif
+
+	// Default the flags if the driver doesn't specify any
+	#ifndef GDISP_DRIVER_VMT_FLAGS
+		#define GDISP_DRIVER_VMT_FLAGS		0
+	#endif
+
+	// Routines needed by the general driver VMT
+	#ifdef __cplusplus
+	extern "C" {
+	#endif
+		bool_t _gdispInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance);
+		void _gdispPostInitDriver(GDriver *g);
+		void _gdispDeInitDriver(GDriver *g);
+	#ifdef __cplusplus
+	}
+	#endif
+
+	// Build the VMT
+	const GDISPVMT const GDISP_DRIVER_VMT[1] = {{
+		{ GDRIVER_TYPE_DISPLAY, 0, sizeof(GDisplay), _gdispInitDriver, _gdispPostInitDriver, _gdispDeInitDriver },
+		gdisp_lld_init,
+		#if GDISP_HARDWARE_DEINIT
+			gdisp_lld_deinit,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_STREAM_WRITE
+			gdisp_lld_write_start,
+			#if GDISP_HARDWARE_STREAM_POS
+				gdisp_lld_write_pos,
+			#else
+				0,
+			#endif
+			gdisp_lld_write_color,
+			gdisp_lld_write_stop,
+		#else
+			0, 0, 0, 0,
+		#endif
+		#if GDISP_HARDWARE_STREAM_READ
+			gdisp_lld_read_start,
+			gdisp_lld_read_color,
+			gdisp_lld_read_stop,
+		#else
+			0, 0, 0,
+		#endif
+		#if GDISP_HARDWARE_DRAWPIXEL
+			gdisp_lld_draw_pixel,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_CLEARS
+			gdisp_lld_clear,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_FILLS
+			gdisp_lld_fill_area,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_BITFILLS
+			gdisp_lld_blit_area,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_PIXELREAD
+			gdisp_lld_get_pixel_color,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL
+			gdisp_lld_vertical_scroll,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL
+			gdisp_lld_control,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY
+			gdisp_lld_query,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)
+			gdisp_lld_set_clip,
+		#else
+			0,
+		#endif
+		#if GDISP_HARDWARE_FLUSH
+			gdisp_lld_flush,
+		#else
+			0,
+		#endif
+	}};
+
+	//--------------------------------------------------------------------------------------------------------
+
+	/* Low level driver pixel format information */
+	//-------------------------
+	//	True-Color color system
+	//-------------------------
+	#if GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_TRUECOLOR
+		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_TRUECOLOR
+
+		// Calculate the number of bits
+		#define LLDCOLOR_BITS_R			((GDISP_LLD_PIXELFORMAT>>8) & 0x0F)
+		#define LLDCOLOR_BITS_G			((GDISP_LLD_PIXELFORMAT>>4) & 0x0F)
+		#define LLDCOLOR_BITS_B			((GDISP_LLD_PIXELFORMAT>>0) & 0x0F)
+		#define LLDCOLOR_BITS			(LLDCOLOR_BITS_R + LLDCOLOR_BITS_G + LLDCOLOR_BITS_B)
+
+		// From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking
+		#if LLDCOLOR_BITS <= 8
+			#define LLDCOLOR_TYPE			uint8_t
+			#define LLDCOLOR_TYPE_BITS		8
+		#elif LLDCOLOR_BITS <= 16
+			#define LLDCOLOR_TYPE			uint16_t
+			#define LLDCOLOR_TYPE_BITS		16
+		#elif LLDCOLOR_BITS <= 32
+			#define LLDCOLOR_TYPE			uint32_t
+			#define LLDCOLOR_TYPE_BITS		32
+		#else
+			#error "GDISP: Cannot define low level driver color types with more than 32 bits"
+		#endif
+		#if LLDCOLOR_TYPE_BITS == LLDCOLOR_BITS
+			#define LLDCOLOR_NEEDS_MASK	FALSE
+		#else
+			#define LLDCOLOR_NEEDS_MASK	TRUE
+		#endif
+		#define LLDCOLOR_MASK()			((1 << LLDCOLOR_BITS)-1)
+
+		// Calculate the component bit shifts
+		#if (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_RGB
+			#define LLDCOLOR_SHIFT_R		(LLDCOLOR_BITS_B+LLDCOLOR_BITS_G)
+			#define LLDCOLOR_SHIFT_G		LLDCOLOR_BITS_B
+			#define LLDCOLOR_SHIFT_B		0
+		#else
+			#define LLDCOLOR_SHIFT_B		(LLDCOLOR_BITS_R+LLDCOLOR_BITS_G)
+			#define LLDCOLOR_SHIFT_G		LLDCOLOR_BITS_R
+			#define LLDCOLOR_SHIFT_R		0
+		#endif
+
+		// Calculate LLDRED_OF, LLDGREEN_OF, LLDBLUE_OF and LLDRGB2COLOR
+		#if LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R == 8
+			#define LLDRED_OF(c)			((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R))
+			#define LLDRGB2COLOR_R(r)		((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))))
+		#elif LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R > 8
+			#define LLDRED_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R)) >> (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-8))
+			#define LLDRGB2COLOR_R(r)		(((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1)))) << (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-8))
+		#else // LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R < 8
+			#define LLDRED_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_R)-1) << LLDCOLOR_SHIFT_R)) << (8-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
+			#define LLDRGB2COLOR_R(r)		(((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1)))) >> (8-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
+		#endif
+		#if LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G == 8
+			#define LLDGREEN_OF(c)			((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G))
+			#define LLDRGB2COLOR_G(g)		((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))))
+		#elif LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G > 8
+			#define LLDGREEN_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G)) >> (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-8))
+			#define LLDRGB2COLOR_G(g)		(((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1)))) << (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-8))
+		#else // LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G < 8
+			#define LLDGREEN_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_G)-1) << LLDCOLOR_SHIFT_G)) << (8-(LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G)))
+			#define LLDRGB2COLOR_G(g)		(((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1)))) >> (8-(LLDCOLOR_BITS_LLDG+COLOR_SHIFT_G)))
+		#endif
+		#if LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B == 8
+			#define LLDBLUE_OF(c)			((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B))
+			#define LLDRGB2COLOR_B(b)		((LLDCOLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))))
+		#elif LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B > 8
+			#define LLDBLUE_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B)) >> (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
+			#define LLDRGB2COLOR_B(b)		(((LLDCOLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))) << (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
+		#else // LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B < 8
+			#define LLDBLUE_OF(c)			(((c) & (((1<<LLDCOLOR_BITS_B)-1) << LLDCOLOR_SHIFT_B)) << (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
+			#define LLDRGB2COLOR_B(b)		(((COLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))) >> (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
+		#endif
+		#define LLDLUMA_OF(c)				((LLDRED_OF(c)+((uint16_t)LLDGREEN_OF(c)<<1)+LLDBLUE_OF(c))>>2)
+		#define LLDEXACT_RED_OF(c)			(((uint16_t)(((c)>>LLDCOLOR_SHIFT_R)&((1<<LLDCOLOR_BITS_R)-1))*255)/((1<<LLDCOLOR_BITS_R)-1))
+		#define LLDEXACT_GREEN_OF(c)		(((uint16_t)(((c)>>LLDCOLOR_SHIFT_G)&((1<<LLDCOLOR_BITS_G)-1))*255)/((1<<LLDCOLOR_BITS_G)-1))
+		#define LLDEXACT_BLUE_OF(c)			(((uint16_t)(((c)>>LLDCOLOR_SHIFT_B)&((1<<LLDCOLOR_BITS_B)-1))*255)/((1<<LLDCOLOR_BITS_B)-1))
+		#define LLDEXACT_LUMA_OF(c)			((LLDEXACT_RED_OF(c)+((uint16_t)LLDEXACT_GREEN_OF(c)<<1)+LLDEXACT_BLUE_OF(c))>>2)
+		#define LLDLUMA2COLOR(l)			(LLDRGB2COLOR_R(l) | LLDRGB2COLOR_G(l) | LLDRGB2COLOR_B(l))
+		#define LLDRGB2COLOR(r,g,b)			(LLDRGB2COLOR_R(r) | LLDRGB2COLOR_G(g) | LLDRGB2COLOR_B(b))
+
+		// Calculate LLDHTML2COLOR
+		#if LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R == 24
+			#define LLDHTML2COLOR_R(h)		((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16))
+		#elif COLOR_BITS_R + COLOR_SHIFT_R > 24
+			#define LLDHTML2COLOR_R(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) << (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-24))
+		#else // COLOR_BITS_R + COLOR_SHIFT_R < 24
+			#define LLDHTML2COLOR_R(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) >> (24-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R)))
+		#endif
+		#if LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G == 16
+			#define LLDHTML2COLOR_G(h)		((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8))
+		#elif LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G > 16
+			#define LLDHTML2COLOR_G(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) << (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-16))
+		#else // LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G < 16
+			#define LLDHTML2COLOR_G(h)		(((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) >> (16-(LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G)))
+		#endif
+		#if LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B == 8
+			#define LLDHTML2COLOR_B(h)		((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))
+		#elif LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B > 8
+			#define LLDHTML2COLOR_B(h)		(((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) << (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8))
+		#else // LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B < 8
+			#define LLDHTML2COLOR_B(h)		(((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) >> (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B)))
+		#endif
+		#define LLDHTML2COLOR(h)		((LLDCOLOR_TYPE)(LLDHTML2COLOR_R(h) | LLDHTML2COLOR_G(h) | LLDHTML2COLOR_B(h)))
+
+	//-------------------------
+	//	Gray-scale color system
+	//-------------------------
+	#elif (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_GRAYSCALE
+		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_GRAYSCALE
+
+		// Calculate the number of bits and shifts
+		#define LLDCOLOR_BITS			(GDISP_LLD_PIXELFORMAT & 0xFF)
+		#define LLDCOLOR_BITS_R			LLDCOLOR_BITS
+		#define LLDCOLOR_BITS_G			LLDCOLOR_BITS
+		#define LLDCOLOR_BITS_B			LLDCOLOR_BITS
+		#define LLDCOLOR_SHIFT_R		0
+		#define LLDCOLOR_SHIFT_G		0
+		#define LLDCOLOR_SHIFT_B		0
+
+		// From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking
+		#if LLDCOLOR_BITS <= 8
+			#define LLDCOLOR_TYPE		uint8_t
+			#define LLDCOLOR_TYPE_BITS	8
+		#else
+			#error "GDISP: Cannot define gray-scale low level driver color types with more than 8 bits"
+		#endif
+		#if LLDCOLOR_TYPE_BITS == LLDCOLOR_BITS
+			#define LLDCOLOR_NEEDS_MASK	FALSE
+		#else
+			#define LLDCOLOR_NEEDS_MASK	TRUE
+		#endif
+		#define LLDCOLOR_MASK()			((1 << LLDCOLOR_BITS)-1)
+
+		#if COLOR_BITS == 1
+			#define LLDRGB2COLOR(r,g,b)		(((r)|(g)|(b)) ? 1 : 0)
+			#define LLDLUMA2COLOR(l)		((l) ? 1 : 0)
+			#define LLDHTML2COLOR(h)		((h) ? 1 : 0)
+			#define LLDLUMA_OF(c)			((c) ? 255 : 0)
+			#define LLDEXACT_LUMA_OF(c)		LLDLUMA_OF(c)
+		#else
+			// They eye is more sensitive to green
+			#define LLDRGB2COLOR(r,g,b)		((LLDCOLOR_TYPE)(((uint16_t)(r)+(g)+(g)+(b)) >> (10-LLDCOLOR_BITS)))
+			#define LLDLUMA2COLOR(l)		((LLDCOLOR_TYPE)((l)>>(8-LLDCOLOR_BITS)))
+			#define LLDHTML2COLOR(h)		((LLDCOLOR_TYPE)(((((h)&0xFF0000)>>16)+(((h)&0x00FF00)>>7)+((h)&0x0000FF)) >> (10-LLDCOLOR_BITS)))
+			#define LLDLUMA_OF(c)			(((c) & ((1<<LLDCOLOR_BITS)-1)) << (8-LLDCOLOR_BITS))
+			#define LLDEXACT_LUMA_OF(c)		((((uint16_t)(c) & ((1<<LLDCOLOR_BITS)-1))*255)/((1<<LLDCOLOR_BITS)-1))
+		#endif
+
+		#define LLDRED_OF(c)			LLDLUMA_OF(c)
+		#define LLDGREEN_OF(c)			LLDLUMA_OF(c)
+		#define LLDBLUE_OF(c)			LLDLUMA_OF(c)
+		#define LLDEXACT_RED_OF(c)		LLDEXACT_LUMA_OF(c)
+		#define LLDEXACT_GREEN_OF(c)	LLDEXACT_LUMA_OF(c)
+		#define LLDEXACT_BLUE_OF(c)		LLDEXACT_LUMA_OF(c)
+
+	//-------------------------
+	//	Palette color system
+	//-------------------------
+	#elif (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_PALETTE
+		#define LLDCOLOR_SYSTEM			GDISP_COLORSYSTEM_PALETTE
+
+		#error "GDISP: A palette color system for low level drivers is not currently supported"
+
+	//-------------------------
+	//	Some other color system
+	//-------------------------
+	#else
+		#error "GDISP: Unsupported color system for low level drivers"
+	#endif
+
+	/* Which is the larger color type */
+	#if COLOR_BITS > LLDCOLOR_BITS
+		#define LARGER_COLOR_BITS	COLOR_BITS
+		#define LARGER_COLOR_TYPE	COLOR_TYPE
+	#else
+		#define LARGER_COLOR_BITS	LLDCOLOR_BITS
+		#define LARGER_COLOR_TYPE	LLDCOLOR_TYPE
+	#endif
+
+	/**
+	 * @brief	Controls color conversion accuracy for a low level driver
+	 * @details	Should higher precision be used when converting colors.
+	 * @note	Color conversion is only necessary if GDISP_PIXELFORMAT != GDISP_LLD_PIXELFORMAT
+	 * @note	It only makes sense to turn this on if you have a high bit depth display but
+	 * 			are running the application in low bit depths.
+	 * @note	To achieve higher color accuracy bit shifting is replaced with multiplies and divides.
+	 */
+	#ifndef GDISP_HARDWARE_USE_EXACT_COLOR
+		#if LLDCOLOR_BITS_R - COLOR_BITS_R >= LLDCOLOR_BITS_R/2 || LLDCOLOR_BITS_G - COLOR_BITS_G >= LLDCOLOR_BITS_G/2 || LLDCOLOR_BITS_B - COLOR_BITS_B >= LLDCOLOR_BITS_B/2
+			#define GDISP_HARDWARE_USE_EXACT_COLOR	TRUE
+		#else
+			#define GDISP_HARDWARE_USE_EXACT_COLOR	FALSE
+		#endif
+	#endif
+
+	/* Low level driver pixel format conversion functions */
+	#if GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT || defined(__DOXYGEN__)
+		/**
+		 * @brief	Convert from a standard color format to the low level driver pixel format
+		 * @note	For use only by low level drivers
+		 */
+		#define gdispColor2Native(c)	(c)
+		/**
+		 * @brief	Convert from a low level driver pixel format to the standard color format
+		 * @note	For use only by low level drivers
+		 */
+		#define gdispNative2Color(c)	(c)
+	#else
+		static LLDCOLOR_TYPE gdispColor2Native(color_t c) {
+			#if COLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE || LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE
+				#if GDISP_HARDWARE_USE_EXACT_COLOR
+					return LLDLUMA2COLOR(EXACT_LUMA_OF(c));
+				#else
+					return LLDLUMA2COLOR(LUMA_OF(c));
+				#endif
+			#elif COLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR && LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR
+				#if GDISP_HARDWARE_USE_EXACT_COLOR
+					return LLDRGB2COLOR(EXACT_RED_OF(c), EXACT_GREEN_OF(c), EXACT_BLUE_OF(c));
+				#else
+					return LLDRGB2COLOR(RED_OF(c), GREEN_OF(c), BLUE_OF(c));
+				#endif
+			#else
+				#error "GDISP: This pixel format conversion is not supported yet"
+			#endif
+		}
+		static color_t gdispNative2Color(LLDCOLOR_TYPE c) {
+			#if COLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE || LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE
+				#if GDISP_HARDWARE_USE_EXACT_COLOR
+					return LUMA2COLOR(LLDEXACT_LUMA_OF(c));
+				#else
+					return LUMA2COLOR(LLDLUMA_OF(c));
+				#endif
+			#elif COLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR && LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR
+				#if GDISP_HARDWARE_USE_EXACT_COLOR
+					return RGB2COLOR(LLDEXACT_RED_OF(c), LLDEXACT_GREEN_OF(c), LLDEXACT_BLUE_OF(c));
+				#else
+					return RGB2COLOR(LLDRED_OF(c), LLDGREEN_OF(c), LLDBLUE_OF(c));
+				#endif
+			#else
+				#error "GDISP: This pixel format conversion is not supported yet"
+			#endif
+		}
+	#endif
+
+#endif
+
+//------------------------------------------------------------------------------------------------------------
+
+#undef IN_PIXMAP_DRIVER
+#undef IS_MULTIPLE
+#undef IN_DRIVER
+#undef USE_VMT
+#endif	/* GFX_USE_GDISP */
+
+#endif	/* _GDISP_LLD_H */
+/** @} */
diff --git a/src/gdisp/gdisp_fonts.c b/src/gdisp/gdisp_fonts.c
index cdb8e075..81df08ec 100644
--- a/src/gdisp/gdisp_fonts.c
+++ b/src/gdisp/gdisp_fonts.c
@@ -5,14 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gdisp/gdisp_fonts.c
- * @brief   GDISP Font Handling.
- *
- * @addtogroup GDISP
- * @{
- */
-
 #include "gfx.h"
 
 #if GFX_USE_GDISP && GDISP_NEED_TEXT
@@ -93,4 +85,3 @@ const char *gdispGetFontName(font_t font) {
 }
 
 #endif /* GFX_USE_GDISP && GDISP_NEED_TEXT */
-/** @} */
diff --git a/src/gdisp/gdisp_gdisp.c b/src/gdisp/gdisp_gdisp.c
deleted file mode 100644
index 8910bcf1..00000000
--- a/src/gdisp/gdisp_gdisp.c
+++ /dev/null
@@ -1,3378 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gdisp/gdisp_gdisp.c
- * @brief   GDISP Driver code.
- *
- * @addtogroup GDISP
- * @{
- */
-#include "gfx.h"
-
-#if GFX_USE_GDISP
-
-/* Include the low level driver information */
-#include "driver.h"
-
-#if 1
-	#undef INLINE
-	#if defined(__KEIL__) || defined(__C51__)
-		#define INLINE	__inline
-	#else
-		#define INLINE	inline
-	#endif
-#else
-	#undef INLINE
-	#define INLINE
-#endif
-
-// Number of milliseconds for the startup logo - 0 means disabled.
-#if GDISP_NEED_STARTUP_LOGO
-	#define GDISP_STARTUP_LOGO_TIMEOUT		1000
-#else
-	#define GDISP_STARTUP_LOGO_TIMEOUT		0
-#endif
-
-/*===========================================================================*/
-/* Driver local variables.                                                   */
-/*===========================================================================*/
-
-#if GDISP_NEED_TIMERFLUSH
-	static GTimer	FlushTimer;
-#endif
-
-GDisplay	*GDISP;
-
-#if GDISP_NEED_MULTITHREAD
-	#define MUTEX_INIT(g)		gfxMutexInit(&(g)->mutex)
-	#define MUTEX_ENTER(g)		gfxMutexEnter(&(g)->mutex)
-	#define MUTEX_EXIT(g)		gfxMutexExit(&(g)->mutex)
-	#define MUTEX_DEINIT(g)		gfxMutexDestroy(&(g)->mutex)
-#else
-	#define MUTEX_INIT(g)
-	#define MUTEX_ENTER(g)
-	#define MUTEX_EXIT(g)
-	#define MUTEX_DEINIT(g)
-#endif
-
-#define NEED_CLIPPING	(GDISP_HARDWARE_CLIP != TRUE && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP))
-
-#if !NEED_CLIPPING
-	#define TEST_CLIP_AREA(g)
-#elif GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-	#define TEST_CLIP_AREA(g)																					\
-			if (!gvmt(g)->setclip) {																				\
-				if ((g)->p.x < (g)->clipx0) { (g)->p.cx -= (g)->clipx0 - (g)->p.x; (g)->p.x = (g)->clipx0; }	\
-				if ((g)->p.y < (g)->clipy0) { (g)->p.cy -= (g)->clipy0 - (g)->p.y; (g)->p.y = (g)->clipy0; }	\
-				if ((g)->p.x + (g)->p.cx > (g)->clipx1)	(g)->p.cx = (g)->clipx1 - (g)->p.x;						\
-				if ((g)->p.y + (g)->p.cy > (g)->clipy1)	(g)->p.cy = (g)->clipy1 - (g)->p.y;						\
-			}																									\
-			if ((g)->p.cx > 0 && (g)->p.cy > 0)
-#else
-	#define TEST_CLIP_AREA(g)																				\
-			if ((g)->p.x < (g)->clipx0) { (g)->p.cx -= (g)->clipx0 - (g)->p.x; (g)->p.x = (g)->clipx0; }	\
-			if ((g)->p.y < (g)->clipy0) { (g)->p.cy -= (g)->clipy0 - (g)->p.y; (g)->p.y = (g)->clipy0; }	\
-			if ((g)->p.x + (g)->p.cx > (g)->clipx1)	(g)->p.cx = (g)->clipx1 - (g)->p.x;						\
-			if ((g)->p.y + (g)->p.cy > (g)->clipy1)	(g)->p.cy = (g)->clipy1 - (g)->p.y;						\
-			if ((g)->p.cx > 0 && (g)->p.cy > 0)
-#endif
-
-/*==========================================================================*/
-/* Internal functions.														*/
-/*==========================================================================*/
-
-#if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE
-	static INLINE void setglobalwindow(GDisplay *g) {
-		coord_t	x, y;
-		x = g->p.x; y = g->p.y;
-		g->p.x = g->p.y = 0;
-		g->p.cx = g->g.Width; g->p.cy = g->g.Height;
-		gdisp_lld_write_start(g);
-		g->p.x = x; g->p.y = y;
-		g->flags |= GDISP_FLG_SCRSTREAM;
-	}
-#endif
-
-#if GDISP_NEED_AUTOFLUSH && GDISP_HARDWARE_FLUSH == HARDWARE_AUTODETECT
-	#define autoflush_stopdone(g)	if (gvmt(g)->flush) gdisp_lld_flush(g)
-#elif GDISP_NEED_AUTOFLUSH && GDISP_HARDWARE_FLUSH
-	#define autoflush_stopdone(g)	gdisp_lld_flush(g)
-#else
-	#define autoflush_stopdone(g)
-#endif
-
-#if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE
-	#define autoflush(g)									\
-			{												\
-				if ((g->flags & GDISP_FLG_SCRSTREAM)) {		\
-					gdisp_lld_write_stop(g);				\
-					g->flags &= ~GDISP_FLG_SCRSTREAM;		\
-				}											\
-				autoflush_stopdone(g);						\
-			}
-#else
-	#define autoflush(g)		autoflush_stopdone(g)
-#endif
-
-// drawpixel(g)
-// Parameters:	x,y
-// Alters:		cx, cy (if using streaming)
-// Does not clip
-static INLINE void drawpixel(GDisplay *g) {
-
-	// Best is hardware accelerated pixel draw
-	#if GDISP_HARDWARE_DRAWPIXEL
-		#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-			if (gvmt(g)->pixel)
-		#endif
-		{
-			gdisp_lld_draw_pixel(g);
-			return;
-		}
-	#endif
-
-	// Next best is cursor based streaming
-	#if GDISP_HARDWARE_DRAWPIXEL != TRUE && GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE
-		#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
-			if (gvmt(g)->writepos)
-		#endif
-		{
-			if (!(g->flags & GDISP_FLG_SCRSTREAM))
-				setglobalwindow(g);
-			gdisp_lld_write_pos(g);
-			gdisp_lld_write_color(g);
-			return;
-		}
-	#endif
-
-	// Worst is general streaming
-	#if GDISP_HARDWARE_DRAWPIXEL != TRUE && GDISP_HARDWARE_STREAM_POS != TRUE && GDISP_HARDWARE_STREAM_WRITE
-		// The following test is unneeded because we are guaranteed to have streaming if we don't have drawpixel
-		//#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-		//	if (gvmt(g)->writestart)
-		//#endif
-		{
-			g->p.cx = g->p.cy = 1;
-			gdisp_lld_write_start(g);
-			gdisp_lld_write_color(g);
-			gdisp_lld_write_stop(g);
-			return;
-		}
-	#endif
-}
-
-// drawpixel_clip(g)
-// Parameters:	x,y
-// Alters:		cx, cy (if using streaming)
-#if NEED_CLIPPING
-	static INLINE void drawpixel_clip(GDisplay *g) {
-		#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-			if (!gvmt(g)->setclip)
-		#endif
-		{
-			if (g->p.x < g->clipx0 || g->p.x >= g->clipx1 || g->p.y < g->clipy0 || g->p.y >= g->clipy1)
-				return;
-		}
-		drawpixel(g);
-	}
-#else
-	#define drawpixel_clip(g)		drawpixel(g)
-#endif
-
-// fillarea(g)
-// Parameters:	x,y cx,cy and color
-// Alters:		nothing
-// Note:		This is not clipped
-// Resets the streaming area if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set.
-static INLINE void fillarea(GDisplay *g) {
-
-	// Best is hardware accelerated area fill
-	#if GDISP_HARDWARE_FILLS
-		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-			if (gvmt(g)->fill)
-		#endif
-		{
-			gdisp_lld_fill_area(g);
-			return;
-		}
-	#endif
-
-	// Next best is hardware streaming
-	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
-		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-			if (gvmt(g)->writestart)
-		#endif
-		{
-			uint32_t	area;
-
-			#if GDISP_HARDWARE_STREAM_POS
-				if ((g->flags & GDISP_FLG_SCRSTREAM)) {
-					gdisp_lld_write_stop(g);
-					g->flags &= ~GDISP_FLG_SCRSTREAM;
-				}
-			#endif
-
-			area = (uint32_t)g->p.cx * g->p.cy;
-			gdisp_lld_write_start(g);
-			#if GDISP_HARDWARE_STREAM_POS
-				#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
-					if (gvmt(g)->writepos)
-				#endif
-				gdisp_lld_write_pos(g);
-			#endif
-			for(; area; area--)
-				gdisp_lld_write_color(g);
-			gdisp_lld_write_stop(g);
-			return;
-		}
-	#endif
-
-	// Worst is pixel drawing
-	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
-		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
-		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-		//	if (gvmt(g)->pixel)
-		//#endif
-		{
-			coord_t x0, y0, x1, y1;
-
-			x0 = g->p.x;
-			y0 = g->p.y;
-			x1 = g->p.x + g->p.cx;
-			y1 = g->p.y + g->p.cy;
-			for(; g->p.y < y1; g->p.y++, g->p.x = x0)
-				for(; g->p.x < x1; g->p.x++)
-					gdisp_lld_draw_pixel(g);
-			g->p.y = y0;
-			return;
-		}
-	#endif
-}
-
-// Parameters:	x,y and x1
-// Alters:		x,y x1,y1 cx,cy
-// Assumes the window covers the screen and a write_stop() will occur later
-//	if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set.
-static void hline_clip(GDisplay *g) {
-	// Swap the points if necessary so it always goes from x to x1
-	if (g->p.x1 < g->p.x) {
-		g->p.cx = g->p.x; g->p.x = g->p.x1; g->p.x1 = g->p.cx;
-	}
-
-	// Clipping
-	#if NEED_CLIPPING
-		#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-			if (!gvmt(g)->setclip)
-		#endif
-		{
-			if (g->p.y < g->clipy0 || g->p.y >= g->clipy1) return;
-			if (g->p.x < g->clipx0) g->p.x = g->clipx0;
-			if (g->p.x1 >= g->clipx1) g->p.x1 = g->clipx1 - 1;
-			if (g->p.x1 < g->p.x) return;
-		}
-	#endif
-
-	// This is an optimization for the point case. It is only worthwhile however if we
-	// have hardware fills or if we support both hardware pixel drawing and hardware streaming
-	#if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE)
-		// Is this a point
-		if (g->p.x == g->p.x1) {
-			drawpixel(g);
-			return;
-		}
-	#endif
-
-	// Best is hardware accelerated area fill
-	#if GDISP_HARDWARE_FILLS
-		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-			if (gvmt(g)->fill)
-		#endif
-		{
-			g->p.cx = g->p.x1 - g->p.x + 1;
-			g->p.cy = 1;
-			gdisp_lld_fill_area(g);
-			return;
-		}
-	#endif
-
-	// Next best is cursor based streaming
-	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE
-		#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
-			if (gvmt(g)->writepos)
-		#endif
-		{
-			if (!(g->flags & GDISP_FLG_SCRSTREAM))
-				setglobalwindow(g);
-			g->p.cx = g->p.x1 - g->p.x + 1;
-			gdisp_lld_write_pos(g);
-			do { gdisp_lld_write_color(g); } while(--g->p.cx);
-			return;
-		}
-	#endif
-
-	// Next best is streaming
-	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_POS != TRUE && GDISP_HARDWARE_STREAM_WRITE
-		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-			if (gvmt(g)->writestart)
-		#endif
-		{
-			g->p.cx = g->p.x1 - g->p.x + 1;
-			g->p.cy = 1;
-			gdisp_lld_write_start(g);
-			do { gdisp_lld_write_color(g); } while(--g->p.cx);
-			gdisp_lld_write_stop(g);
-			return;
-		}
-	#endif
-
-	// Worst is drawing pixels
-	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
-		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
-		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-		//	if (gvmt(g)->pixel)
-		//#endif
-		{
-			for(; g->p.x <= g->p.x1; g->p.x++)
-				gdisp_lld_draw_pixel(g);
-			return;
-		}
-	#endif
-}
-
-// Parameters:	x,y and y1
-// Alters:		x,y x1,y1 cx,cy
-static void vline_clip(GDisplay *g) {
-	// Swap the points if necessary so it always goes from y to y1
-	if (g->p.y1 < g->p.y) {
-		g->p.cy = g->p.y; g->p.y = g->p.y1; g->p.y1 = g->p.cy;
-	}
-
-	// Clipping
-	#if NEED_CLIPPING
-		#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-			if (!gvmt(g)->setclip)
-		#endif
-		{
-			if (g->p.x < g->clipx0 || g->p.x >= g->clipx1) return;
-			if (g->p.y < g->clipy0) g->p.y = g->clipy0;
-			if (g->p.y1 >= g->clipy1) g->p.y1 = g->clipy1 - 1;
-			if (g->p.y1 < g->p.y) return;
-		}
-	#endif
-
-	// This is an optimization for the point case. It is only worthwhile however if we
-	// have hardware fills or if we support both hardware pixel drawing and hardware streaming
-	#if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) || (GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE)
-		// Is this a point
-		if (g->p.y == g->p.y1) {
-			drawpixel(g);
-			return;
-		}
-	#endif
-
-	// Best is hardware accelerated area fill
-	#if GDISP_HARDWARE_FILLS
-		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-			if (gvmt(g)->fill)
-		#endif
-		{
-			g->p.cy = g->p.y1 - g->p.y + 1;
-			g->p.cx = 1;
-			gdisp_lld_fill_area(g);
-			return;
-		}
-	#endif
-
-	// Next best is streaming
-	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
-		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-			if (gvmt(g)->writestart)
-		#endif
-		{
-			#if GDISP_HARDWARE_STREAM_POS
-				if ((g->flags & GDISP_FLG_SCRSTREAM)) {
-					gdisp_lld_write_stop(g);
-					g->flags &= ~GDISP_FLG_SCRSTREAM;
-				}
-			#endif
-			g->p.cy = g->p.y1 - g->p.y + 1;
-			g->p.cx = 1;
-			gdisp_lld_write_start(g);
-			#if GDISP_HARDWARE_STREAM_POS
-				#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
-					if (gvmt(g)->writepos)
-				#endif
-				gdisp_lld_write_pos(g);
-			#endif
-			do { gdisp_lld_write_color(g); } while(--g->p.cy);
-			gdisp_lld_write_stop(g);
-			return;
-		}
-	#endif
-
-	// Worst is drawing pixels
-	#if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
-		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
-		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-		//	if (gvmt(g)->pixel)
-		//#endif
-		{
-			for(; g->p.y <= g->p.y1; g->p.y++)
-				gdisp_lld_draw_pixel(g);
-			return;
-		}
-	#endif
-}
-
-// Parameters:	x,y and x1,y1
-// Alters:		x,y x1,y1 cx,cy
-static void line_clip(GDisplay *g) {
-	int16_t dy, dx;
-	int16_t addx, addy;
-	int16_t P, diff, i;
-
-	// Is this a horizontal line (or a point)
-	if (g->p.y == g->p.y1) {
-		hline_clip(g);
-		return;
-	}
-
-	// Is this a vertical line (or a point)
-	if (g->p.x == g->p.x1) {
-		vline_clip(g);
-		return;
-	}
-
-	// Not horizontal or vertical
-
-	// Use Bresenham's line drawing algorithm.
-	//	This should be replaced with fixed point slope based line drawing
-	//	which is more efficient on modern processors as it branches less.
-	//	When clipping is needed, all the clipping could also be done up front
-	//	instead of on each pixel.
-
-	if (g->p.x1 >= g->p.x) {
-		dx = g->p.x1 - g->p.x;
-		addx = 1;
-	} else {
-		dx = g->p.x - g->p.x1;
-		addx = -1;
-	}
-	if (g->p.y1 >= g->p.y) {
-		dy = g->p.y1 - g->p.y;
-		addy = 1;
-	} else {
-		dy = g->p.y - g->p.y1;
-		addy = -1;
-	}
-
-	if (dx >= dy) {
-		dy <<= 1;
-		P = dy - dx;
-		diff = P - dx;
-
-		for(i=0; i<=dx; ++i) {
-			drawpixel_clip(g);
-			if (P < 0) {
-				P  += dy;
-				g->p.x += addx;
-			} else {
-				P  += diff;
-				g->p.x += addx;
-				g->p.y += addy;
-			}
-		}
-	} else {
-		dx <<= 1;
-		P = dx - dy;
-		diff = P - dy;
-
-		for(i=0; i<=dy; ++i) {
-			drawpixel_clip(g);
-			if (P < 0) {
-				P  += dx;
-				g->p.y += addy;
-			} else {
-				P  += diff;
-				g->p.x += addx;
-				g->p.y += addy;
-			}
-		}
-	}
-}
-
-#if GDISP_STARTUP_LOGO_TIMEOUT > 0
-	static bool_t	initDone;
-	static void StartupLogoDisplay(GDisplay *g) {
-		coord_t			x, y, w;
-		const coord_t *	p;
-		static const coord_t blks[] = {
-				// u
-				2, 6, 1, 10,
-				3, 11, 4, 1,
-				6, 6, 1, 6,
-				// G
-				8, 0, 1, 12,
-				9, 0, 6, 1,
-				9, 11, 6, 1,
-				14, 6, 1, 5,
-				12, 6, 2, 1,
-				// F
-				16, 0, 1, 12,
-				17, 0, 6, 1,
-				17, 6, 3, 1,
-				// X
-				22, 6, 7, 1,
-				24, 0, 1, 6,
-				22, 7, 1, 5,
-				28, 0, 1, 6,
-				26, 7, 1, 5,
-		};
-
-		// Get a starting position and a scale
-		// Work on a 8x16 grid for each char, 4 chars (uGFX) in 1 line, using half the screen
-		w = g->g.Width/(8*4*2);
-		if (!w) w = 1;
-		x = (g->g.Width - (8*4)*w)/2;
-		y = (g->g.Height - (16*1)*w)/2;
-
-		// Simple but crude!
-		for(p = blks; p < blks+sizeof(blks)/sizeof(blks[0]); p+=4)
-			gdispGFillArea(g, x+p[0]*w, y+p[1]*w, p[2]*w, p[3]*w, Blue);
-	}
-#endif
-
-#if GDISP_NEED_TIMERFLUSH
-	static void FlushTimerFn(void *param) {
-		GDisplay *	g;
-		(void)		param;
-
-		for(g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, 0); g; g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g))
-			gdispGFlush(g);
-	}
-#endif
-
-/*===========================================================================*/
-/* Driver exported functions.                                                */
-/*===========================================================================*/
-
-typedef const GDISPVMT const GDISPVMTLIST[];
-
-void _gdispInit(void)
-{
-	// GDISP_DRIVER_LIST is defined - create each driver instance
-	#if defined(GDISP_DRIVER_LIST)
-		{
-			unsigned	i;
-
-			extern GDISPVMTLIST				GDISP_DRIVER_LIST;
-			static GDISPVMTLIST dclist[] = {GDISP_DRIVER_LIST};
-
-			for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++)
-				if (!(dclist[i]->d.flags & GDISP_VFLG_DYNAMICONLY))
-					gdriverRegister(&dclist[i]->d, 0);
-		}
-	#elif GDISP_TOTAL_DISPLAYS > 1
-		{
-			unsigned	i;
-			extern GDISPVMTLIST				GDISPVMT_OnlyOne;
-
-			if (!(GDISPVMT_OnlyOne->d.flags & GDISP_VFLG_DYNAMICONLY)) {
-				for(i = 0; i < GDISP_TOTAL_DISPLAYS; i++)
-					gdriverRegister(&GDISPVMT_OnlyOne->d, 0);
-			}
-		}
-	#else
-		{
-			extern GDISPVMTLIST				GDISPVMT_OnlyOne;
-
-			if (!(GDISPVMT_OnlyOne->d.flags & GDISP_VFLG_DYNAMICONLY))
-				gdriverRegister(&GDISPVMT_OnlyOne->d, 0);
-		}
-	#endif
-
-	// Re-clear the display after the timeout if we added the logo
-	#if GDISP_STARTUP_LOGO_TIMEOUT > 0
-		{
-			GDisplay	*g;
-
-			gfxSleepMilliseconds(GDISP_STARTUP_LOGO_TIMEOUT);
-
-			for(g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, 0); g; g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g)) {
-				gdispGClear(g, GDISP_STARTUP_COLOR);
-				#if GDISP_HARDWARE_FLUSH
-					gdispGFlush(g);
-				#endif
-			}
-
-			initDone = TRUE;
-		}
-	#endif
-
-	// Start the automatic timer flush (if required)
-	#if GDISP_NEED_TIMERFLUSH
-		gtimerInit(&FlushTimer);
-		gtimerStart(&FlushTimer, FlushTimerFn, 0, TRUE, GDISP_NEED_TIMERFLUSH);
-	#endif
-}
-
-void _gdispDeinit(void)
-{
-	/* ToDo */
-}
-
-bool_t _gdispInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance) {
-	#define		gd		((GDisplay *)g)
-	bool_t		ret;
-
-	// Intialise fields
-	gd->systemdisplay = systeminstance;
-	gd->controllerdisplay = driverinstance;
-	gd->flags = 0;
-	gd->priv = param;
-	MUTEX_INIT(gd);
-
-	// Call the driver init
-	MUTEX_ENTER(gd);
-	ret = gdisp_lld_init(gd);
-	MUTEX_EXIT(gd);
-	return ret;
-
-	#undef gd
-}
-
-void _gdispPostInitDriver(GDriver *g) {
-	#define		gd		((GDisplay *)g)
-
-	// Set orientation, clip
-	#if defined(GDISP_DEFAULT_ORIENTATION) && GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
-		#if GDISP_NEED_PIXMAP
-			// Pixmaps should stay in their created orientation (at least initially)
-			if (!(gvmt(gd)->d.flags & GDISP_VFLG_PIXMAP))
-		#endif
-			gdispGControl(gd, GDISP_CONTROL_ORIENTATION, (void *)GDISP_DEFAULT_ORIENTATION);
-	#endif
-	#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP
-		gdispGSetClip(gd, 0, 0, gd->g.Width, gd->g.Height);
-	#endif
-
-	// Clear the Screen
-	gdispGClear(gd, GDISP_STARTUP_COLOR);
-
-	// Display the startup logo if this is a static initialised display
-	#if GDISP_STARTUP_LOGO_TIMEOUT > 0
-		if (!initDone)
-			StartupLogoDisplay(gd);
-	#endif
-
-	// Flush
-	#if GDISP_HARDWARE_FLUSH
-		gdispGFlush(gd);
-	#endif
-
-	// If this is the first driver set GDISP
-	if (!GDISP)
-		GDISP = gd;
-
-	#undef gd
-}
-
-void _gdispDeInitDriver(GDriver *g) {
-	#define		gd		((GDisplay *)g)
-
-	if (GDISP == gd)
-		GDISP = (GDisplay *)gdriverGetInstance(GDRIVER_TYPE_DISPLAY, 0);
-
-	#if GDISP_HARDWARE_DEINIT
-		#if GDISP_HARDWARE_DEINIT == HARDWARE_AUTODETECT
-			if (gvmt(gd)->deinit)
-		#endif
-		{
-			MUTEX_ENTER(gd);
-			gdisp_lld_deinit(gd);
-			MUTEX_EXIT(gd);
-		}
-	#endif
-	MUTEX_DEINIT(gd);
-
-	#undef gd
-}
-
-GDisplay *gdispGetDisplay(unsigned display) {
-	return (GDisplay *)gdriverGetInstance(GDRIVER_TYPE_DISPLAY, display);
-}
-
-void gdispSetDisplay(GDisplay *g) {
-	if (g) GDISP = g;
-}
-
-unsigned gdispGetDisplayCount(void) {
-	return gdriverInstanceCount(GDRIVER_TYPE_DISPLAY);
-}
-
-coord_t gdispGGetWidth(GDisplay *g)				{ return g->g.Width; }
-coord_t gdispGGetHeight(GDisplay *g)			{ return g->g.Height; }
-powermode_t gdispGGetPowerMode(GDisplay *g)		{ return g->g.Powermode; }
-orientation_t gdispGGetOrientation(GDisplay *g)	{ return g->g.Orientation; }
-uint8_t gdispGGetBacklight(GDisplay *g)			{ return g->g.Backlight; }
-uint8_t gdispGGetContrast(GDisplay *g)			{ return g->g.Contrast; }
-
-void gdispGFlush(GDisplay *g) {
-	#if GDISP_HARDWARE_FLUSH
-		#if GDISP_HARDWARE_FLUSH == HARDWARE_AUTODETECT
-			if (gvmt(g)->flush)
-		#endif
-		{
-			MUTEX_ENTER(g);
-			gdisp_lld_flush(g);
-			MUTEX_EXIT(g);
-		}
-	#else
-		(void) g;
-	#endif
-}
-
-#if GDISP_NEED_STREAMING
-	void gdispGStreamStart(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy) {
-		MUTEX_ENTER(g);
-
-		#if NEED_CLIPPING
-			#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-				if (!gvmt(g)->setclip)
-			#endif
-			// Test if the area is valid - if not then exit
-			if (x < g->clipx0 || x+cx > g->clipx1 || y < g->clipy0 || y+cy > g->clipy1) {
-				MUTEX_EXIT(g);
-				return;
-			}
-		#endif
-
-		g->flags |= GDISP_FLG_INSTREAM;
-
-		// Best is hardware streaming
-		#if GDISP_HARDWARE_STREAM_WRITE
-			#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-				if (gvmt(g)->writestart)
-			#endif
-			{
-				g->p.x = x;
-				g->p.y = y;
-				g->p.cx = cx;
-				g->p.cy = cy;
-				gdisp_lld_write_start(g);
-				#if GDISP_HARDWARE_STREAM_POS
-					#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
-						if (gvmt(g)->writepos)
-					#endif
-					gdisp_lld_write_pos(g);
-				#endif
-				return;
-			}
-		#endif
-
-		// Worst - save the parameters and use pixel drawing and/or area fills
-		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
-			// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
-			//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-			//	if (gvmt(g)->pixel)
-			//#endif
-			{
-				// Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position, cx = bufpos
-				g->p.x1 = g->p.x = x;
-				g->p.y1 = g->p.y = y;
-				g->p.x2 = x + cx;
-				g->p.y2 = y + cy;
-				#if (GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS) || GDISP_HARDWARE_FILLS
-					g->p.cx = 0;
-					g->p.cy = 1;
-				#endif
-				return;
-			}
-		#endif
-
-		// Don't release the mutex as gdispStreamEnd() will do that.
-	}
-
-	void gdispGStreamColor(GDisplay *g, color_t color) {
-		#if !GDISP_HARDWARE_STREAM_WRITE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS
-			coord_t	 sx1, sy1;
-		#endif
-
-		// Don't touch the mutex as we should already own it
-
-		// Ignore this call if we are not streaming
-		if (!(g->flags & GDISP_FLG_INSTREAM))
-			return;
-
-		// Best is hardware streaming
-		#if GDISP_HARDWARE_STREAM_WRITE
-			#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-				if (gvmt(g)->writestart)
-			#endif
-			{
-				g->p.color = color;
-				gdisp_lld_write_color(g);
-				return;
-			}
-		#endif
-
-		// Next best is to use bitfills with our line buffer
-		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS
-			#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
-				if (gvmt(g)->blit)
-			#endif
-			{
-				g->linebuf[g->p.cx++] = color;
-				if (g->p.cx >= GDISP_LINEBUF_SIZE) {
-					sx1 = g->p.x1;
-					sy1 = g->p.y1;
-					g->p.x1 = 0;
-					g->p.y1 = 0;
-					g->p.ptr = (void *)g->linebuf;
-					gdisp_lld_blit_area(g);
-					g->p.x1 = sx1;
-					g->p.y1 = sy1;
-					g->p.x += g->p.cx;
-					g->p.cx = 0;
-				}
-
-				// Just wrap at end-of-line and end-of-buffer
-				if (g->p.x+g->p.cx >= g->p.x2) {
-					if (g->p.cx) {
-						sx1 = g->p.x1;
-						sy1 = g->p.y1;
-						g->p.x1 = 0;
-						g->p.y1 = 0;
-						g->p.ptr = (void *)g->linebuf;
-						gdisp_lld_blit_area(g);
-						g->p.x1 = sx1;
-						g->p.y1 = sy1;
-						g->p.cx = 0;
-					}
-					g->p.x = g->p.x1;
-					if (++g->p.y >= g->p.y2)
-						g->p.y = g->p.y1;
-				}
-			}
-		#endif
-
-		// Only slightly better than drawing pixels is to look for runs and use fillarea
-		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS
-			// We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming.
-			#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-				if (gvmt(g)->fill)
-			#endif
-			{
-				if (!g->p.cx || g->p.color == color) {
-					g->p.cx++;
-					g->p.color = color;
-				} else {
-					if (g->p.cx == 1)
-						gdisp_lld_draw_pixel(g);
-					else
-						gdisp_lld_fill_area(g);
-					g->p.x += g->p.cx;
-					g->p.color = color;
-					g->p.cx = 1;
-				}
-				// Just wrap at end-of-line and end-of-buffer
-				if (g->p.x+g->p.cx >= g->p.x2) {
-					if (g->p.cx) {
-						if (g->p.cx == 1)
-							gdisp_lld_draw_pixel(g);
-						else
-							gdisp_lld_fill_area(g);
-						g->p.cx = 0;
-					}
-					g->p.x = g->p.x1;
-					if (++g->p.y >= g->p.y2)
-						g->p.y = g->p.y1;
-				}
-				return;
-			}
-		#endif
-
-		// Worst is using pixel drawing
-		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL
-			// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
-			//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-			//	if (gvmt(g)->pixel)
-			//#endif
-			{
-				g->p.color = color;
-				gdisp_lld_draw_pixel(g);
-
-				// Just wrap at end-of-line and end-of-buffer
-				if (++g->p.x >= g->p.x2) {
-					g->p.x = g->p.x1;
-					if (++g->p.y >= g->p.y2)
-						g->p.y = g->p.y1;
-				}
-				return;
-			}
-		#endif
-	}
-
-	void gdispGStreamStop(GDisplay *g) {
-		// Only release the mutex and end the stream if we are actually streaming.
-		if (!(g->flags & GDISP_FLG_INSTREAM))
-			return;
-
-		// Clear the flag
-		g->flags &= ~GDISP_FLG_INSTREAM;
-
-		// The cleanup below must match the streaming code above.
-
-		#if GDISP_HARDWARE_STREAM_WRITE
-			#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-				if (gvmt(g)->writestart)
-			#endif
-			{
-					gdisp_lld_write_stop(g);
-					autoflush_stopdone(g);
-					MUTEX_EXIT(g);
-					return;
-			}
-		#endif
-
-		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS
-			#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
-				if (gvmt(g)->blit)
-			#endif
-			{
-				if (g->p.cx) {
-					g->p.x1 = 0;
-					g->p.y1 = 0;
-					g->p.ptr = (void *)g->linebuf;
-					gdisp_lld_blit_area(g);
-				}
-				autoflush_stopdone(g);
-				MUTEX_EXIT(g);
-				return;
-			}
-		#endif
-
-		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS
-			// We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming.
-			#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-				if (gvmt(g)->fill)
-			#endif
-			{
-				if (g->p.cx) {
-					if (g->p.cx == 1)
-						gdisp_lld_draw_pixel(g);
-					else
-						gdisp_lld_fill_area(g);
-				}
-				autoflush_stopdone(g);
-				MUTEX_EXIT(g);
-				return;
-			}
-		#endif
-
-		#if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS != TRUE
-			{
-				autoflush_stopdone(g);
-				MUTEX_EXIT(g);
-			}
-		#endif
-	}
-#endif
-
-void gdispGDrawPixel(GDisplay *g, coord_t x, coord_t y, color_t color) {
-	MUTEX_ENTER(g);
-	g->p.x		= x;
-	g->p.y		= y;
-	g->p.color	= color;
-	drawpixel_clip(g);
-	autoflush(g);
-	MUTEX_EXIT(g);
-}
-
-void gdispGDrawLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) {
-	MUTEX_ENTER(g);
-	g->p.x = x0;
-	g->p.y = y0;
-	g->p.x1 = x1;
-	g->p.y1 = y1;
-	g->p.color = color;
-	line_clip(g);
-	autoflush(g);
-	MUTEX_EXIT(g);
-}
-
-void gdispGClear(GDisplay *g, color_t color) {
-	// Note - clear() ignores the clipping area. It clears the screen.
-	MUTEX_ENTER(g);
-
-	// Best is hardware accelerated clear
-	#if GDISP_HARDWARE_CLEARS
-		#if GDISP_HARDWARE_CLEARS == HARDWARE_AUTODETECT
-			if (gvmt(g)->clear)
-		#endif
-		{
-			g->p.color = color;
-			gdisp_lld_clear(g);
-			autoflush_stopdone(g);
-			MUTEX_EXIT(g);
-			return;
-		}
-	#endif
-
-	// Next best is hardware accelerated area fill
-	#if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS
-		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-			if (gvmt(g)->fill)
-		#endif
-		{
-			g->p.x = g->p.y = 0;
-			g->p.cx = g->g.Width;
-			g->p.cy = g->g.Height;
-			g->p.color = color;
-			gdisp_lld_fill_area(g);
-			autoflush_stopdone(g);
-			MUTEX_EXIT(g);
-			return;
-		}
-	#endif
-
-	// Next best is streaming
-	#if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
-		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-			if (gvmt(g)->writestart)
-		#endif
-		{
-			uint32_t	area;
-
-			g->p.x = g->p.y = 0;
-			g->p.cx = g->g.Width;
-			g->p.cy = g->g.Height;
-			g->p.color = color;
-			area = (uint32_t)g->p.cx * g->p.cy;
-
-			gdisp_lld_write_start(g);
-			#if GDISP_HARDWARE_STREAM_POS
-				#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
-					if (gvmt(g)->writepos)
-				#endif
-				gdisp_lld_write_pos(g);
-			#endif
-			for(; area; area--)
-				gdisp_lld_write_color(g);
-			gdisp_lld_write_stop(g);
-			autoflush_stopdone(g);
-			MUTEX_EXIT(g);
-			return;
-		}
-	#endif
-
-	// Worst is drawing pixels
-	#if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL
-		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
-		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-		//	if (gvmt(g)->pixel)
-		//#endif
-		{
-			g->p.color = color;
-			for(g->p.y = 0; g->p.y < g->g.Height; g->p.y++)
-				for(g->p.x = 0; g->p.x < g->g.Width; g->p.x++)
-					gdisp_lld_draw_pixel(g);
-			autoflush_stopdone(g);
-			MUTEX_EXIT(g);
-			return;
-		}
-	#endif
-}
-
-void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
-	MUTEX_ENTER(g);
-	g->p.x = x;
-	g->p.y = y;
-	g->p.cx = cx;
-	g->p.cy = cy;
-	g->p.color = color;
-	TEST_CLIP_AREA(g) {
-		fillarea(g);
-	}
-	autoflush_stopdone(g);
-	MUTEX_EXIT(g);
-}
-
-void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
-	MUTEX_ENTER(g);
-
-	#if NEED_CLIPPING
-		#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-			if (!gvmt(g)->setclip)
-		#endif
-		{
-			// This is a different clipping to fillarea(g) as it needs to take into account srcx,srcy
-			if (x < g->clipx0) { cx -= g->clipx0 - x; srcx += g->clipx0 - x; x = g->clipx0; }
-			if (y < g->clipy0) { cy -= g->clipy0 - y; srcy += g->clipy0 - x; y = g->clipy0; }
-			if (x+cx > g->clipx1)	cx = g->clipx1 - x;
-			if (y+cy > g->clipy1)	cy = g->clipy1 - y;
-			if (srcx+cx > srccx) cx = srccx - srcx;
-			if (cx <= 0 || cy <= 0) { MUTEX_EXIT(g); return; }
-		}
-	#endif
-
-	// Best is hardware bitfills
-	#if GDISP_HARDWARE_BITFILLS
-		#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
-			if (gvmt(g)->blit)
-		#endif
-		{
-			g->p.x = x;
-			g->p.y = y;
-			g->p.cx = cx;
-			g->p.cy = cy;
-			g->p.x1 = srcx;
-			g->p.y1 = srcy;
-			g->p.x2 = srccx;
-			g->p.ptr = (void *)buffer;
-			gdisp_lld_blit_area(g);
-			autoflush_stopdone(g);
-			MUTEX_EXIT(g);
-			return;
-		}
-	#endif
-
-	// Next best is hardware streaming
-	#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
-		#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-			if (gvmt(g)->writestart)
-		#endif
-		{
-			// Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap
-			buffer += srcy*srccx+srcx;
-			srcx = x + cx;
-			srcy = y + cy;
-			srccx -= cx;
-
-			g->p.x = x;
-			g->p.y = y;
-			g->p.cx = cx;
-			g->p.cy = cy;
-			gdisp_lld_write_start(g);
-			#if GDISP_HARDWARE_STREAM_POS
-				#if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT
-					if (gvmt(g)->writepos)
-				#endif
-				gdisp_lld_write_pos(g);
-			#endif
-			for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) {
-				for(g->p.x = x; g->p.x < srcx; g->p.x++) {
-					g->p.color = *buffer++;
-					gdisp_lld_write_color(g);
-				}
-			}
-			gdisp_lld_write_stop(g);
-			autoflush_stopdone(g);
-			MUTEX_EXIT(g);
-			return;
-		}
-	#endif
-
-	// Only slightly better than drawing pixels is to look for runs and use fill area
-	#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS
-		// We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming.
-		#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-			if (gvmt(g)->fill)
-		#endif
-		{
-			// Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap
-			buffer += srcy*srccx+srcx;
-			srcx = x + cx;
-			srcy = y + cy;
-			srccx -= cx;
-
-			g->p.cy = 1;
-			for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) {
-				for(g->p.x=x; g->p.x < srcx; g->p.x += g->p.cx) {
-					g->p.cx=1;
-					g->p.color = *buffer++;
-					while(g->p.x+g->p.cx < srcx && *buffer == g->p.color) {
-						g->p.cx++;
-						buffer++;
-					}
-					if (g->p.cx == 1) {
-						gdisp_lld_draw_pixel(g);
-					} else {
-						gdisp_lld_fill_area(g);
-					}
-				}
-			}
-			autoflush_stopdone(g);
-			MUTEX_EXIT(g);
-			return;
-		}
-	#endif
-
-	// Worst is drawing pixels
-	#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL
-		// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
-		//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-		//	if (gvmt(g)->pixel)
-		//#endif
-		{
-			// Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap
-			buffer += srcy*srccx+srcx;
-			srcx = x + cx;
-			srcy = y + cy;
-			srccx -= cx;
-
-			for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) {
-				for(g->p.x=x; g->p.x < srcx; g->p.x++) {
-					g->p.color = *buffer++;
-					gdisp_lld_draw_pixel(g);
-				}
-			}
-			autoflush_stopdone(g);
-			MUTEX_EXIT(g);
-			return;
-		}
-	#endif
-}
-
-#if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION
-	void gdispGSetClip(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy) {
-		MUTEX_ENTER(g);
-
-		// Best is using hardware clipping
-		#if GDISP_HARDWARE_CLIP
-			#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-				if (gvmt(g)->setclip)
-			#endif
-			{
-				g->p.x = x;
-				g->p.y = y;
-				g->p.cx = cx;
-				g->p.cy = cy;
-				gdisp_lld_set_clip(g);
-			}
-			#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-				else
-			#endif
-		#endif
-
-		// Worst is using software clipping
-		#if GDISP_HARDWARE_CLIP != TRUE
-			{
-				if (x < 0) { cx += x; x = 0; }
-				if (y < 0) { cy += y; y = 0; }
-				if (cx <= 0 || cy <= 0 || x >= g->g.Width || y >= g->g.Height) { MUTEX_EXIT(g); return; }
-				g->clipx0 = x;
-				g->clipy0 = y;
-				g->clipx1 = x+cx;	if (g->clipx1 > g->g.Width) g->clipx1 = g->g.Width;
-				g->clipy1 = y+cy;	if (g->clipy1 > g->g.Height) g->clipy1 = g->g.Height;
-			}
-		#endif
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_CIRCLE
-	void gdispGDrawCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color) {
-		coord_t a, b, P;
-
-		MUTEX_ENTER(g);
-
-		// Calculate intermediates
-		a = 1;
-		b = radius;
-		P = 4 - radius;
-		g->p.color = color;
-
-		// Away we go using Bresenham's circle algorithm
-		// Optimized to prevent double drawing
-		g->p.x = x; g->p.y = y + b; drawpixel_clip(g);
-		g->p.x = x; g->p.y = y - b; drawpixel_clip(g);
-		g->p.x = x + b; g->p.y = y; drawpixel_clip(g);
-		g->p.x = x - b; g->p.y = y; drawpixel_clip(g);
-		do {
-			g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g);
-			g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g);
-			g->p.x = x + b; g->p.y = y + a; drawpixel_clip(g);
-			g->p.x = x - b; g->p.y = y + a; drawpixel_clip(g);
-			g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g);
-			g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g);
-			g->p.x = x + b; g->p.y = y - a; drawpixel_clip(g);
-			g->p.x = x - b; g->p.y = y - a; drawpixel_clip(g);
-			if (P < 0)
-				P += 3 + 2*a++;
-			else
-				P += 5 + 2*(a++ - b--);
-		} while(a < b);
-		g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g);
-		g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g);
-		g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g);
-		g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g);
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_CIRCLE
-	void gdispGFillCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color) {
-		coord_t a, b, P;
-
-		MUTEX_ENTER(g);
-
-		// Calculate intermediates
-		a = 1;
-		b = radius;
-		P = 4 - radius;
-		g->p.color = color;
-
-		// Away we go using Bresenham's circle algorithm
-		// This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value
-		g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
-		g->p.y = y+b; g->p.x = x; drawpixel_clip(g);
-		g->p.y = y-b; g->p.x = x; drawpixel_clip(g);
-		do {
-			g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
-			g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
-			if (P < 0) {
-				P += 3 + 2*a++;
-			} else {
-				g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);
-				g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);
-				P += 5 + 2*(a++ - b--);
-			}
-		} while(a < b);
-		g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
-		g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_ELLIPSE
-	void gdispGDrawEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
-		coord_t	dx, dy;
-		int32_t	a2, b2;
-		int32_t	err, e2;
-
-		MUTEX_ENTER(g);
-
-		// Calculate intermediates
-		dx = 0;
-		dy = b;
-		a2 = a*a;
-		b2 = b*b;
-		err = b2-(2*b-1)*a2;
-		g->p.color = color;
-
-		// Away we go using Bresenham's ellipse algorithm
-		do {
-			g->p.x = x + dx; g->p.y = y + dy; drawpixel_clip(g);
-			g->p.x = x - dx; g->p.y = y + dy; drawpixel_clip(g);
-			g->p.x = x - dx; g->p.y = y - dy; drawpixel_clip(g);
-			g->p.x = x + dx; g->p.y = y - dy; drawpixel_clip(g);
-
-			e2 = 2*err;
-			if(e2 <  (2*dx+1)*b2) {
-				dx++;
-				err += (2*dx+1)*b2;
-			}
-			if(e2 > -(2*dy-1)*a2) {
-				dy--;
-				err -= (2*dy-1)*a2;
-			}
-		} while(dy >= 0);
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_ELLIPSE
-	void gdispGFillEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color) {
-		coord_t	dx, dy;
-		int32_t	a2, b2;
-		int32_t	err, e2;
-
-		MUTEX_ENTER(g);
-
-		// Calculate intermediates
-		dx = 0;
-		dy = b;
-		a2 = a*a;
-		b2 = b*b;
-		err = b2-(2*b-1)*a2;
-		g->p.color = color;
-
-		// Away we go using Bresenham's ellipse algorithm
-		// This is optimized to prevent overdrawing by drawing a line only when a y is about to change value
-		do {
-			e2 = 2*err;
-			if(e2 <  (2*dx+1)*b2) {
-				dx++;
-				err += (2*dx+1)*b2;
-			}
-			if(e2 > -(2*dy-1)*a2) {
-				g->p.y = y + dy; g->p.x = x - dx; g->p.x1 = x + dx; hline_clip(g);
-				if (y) { g->p.y = y - dy; g->p.x = x - dx; g->p.x1 = x + dx; hline_clip(g); }
-				dy--;
-				err -= (2*dy-1)*a2;
-			}
-		} while(dy >= 0);
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_ARCSECTORS
-	void gdispGDrawArcSectors(GDisplay *g, coord_t x, coord_t y, coord_t radius, uint8_t sectors, color_t color) {
-		coord_t a, b, P;
-
-		MUTEX_ENTER(g);
-
-		// Calculate intermediates
-		a = 1;              // x in many explanations
-		b = radius;         // y in many explanations
-		P = 4 - radius;
-		g->p.color = color;
-
-		// Away we go using Bresenham's circle algorithm
-		// Optimized to prevent double drawing
-		if (sectors & 0x06) { g->p.x = x; g->p.y = y - b; drawpixel_clip(g); }				// Upper upper
-		if (sectors & 0x60) { g->p.x = x; g->p.y = y + b; drawpixel_clip(g); }				// Lower lower
-		if (sectors & 0x81) { g->p.x = x + b; g->p.y = y; drawpixel_clip(g); }				// Right right
-		if (sectors & 0x18) { g->p.x = x - b; g->p.y = y; drawpixel_clip(g); }				// Left left
-
-		do {
-			if (sectors & 0x01) { g->p.x = x + b; g->p.y = y - a; drawpixel_clip(g); }		// Upper right right
-			if (sectors & 0x02) { g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g); }		// Upper upper right
-			if (sectors & 0x04) { g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g); }		// Upper upper left
-			if (sectors & 0x08) { g->p.x = x - b; g->p.y = y - a; drawpixel_clip(g); }		// Upper left  left
-			if (sectors & 0x10) { g->p.x = x - b; g->p.y = y + a; drawpixel_clip(g); }		// Lower left  left
-			if (sectors & 0x20) { g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g); }		// Lower lower left
-			if (sectors & 0x40) { g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g); }		// Lower lower right
-			if (sectors & 0x80) { g->p.x = x + b; g->p.y = y + a; drawpixel_clip(g); }		// Lower right right
-			if (P < 0)
-				P += 3 + 2*a++;
-			else
-				P += 5 + 2*(a++ - b--);
-		} while(a < b);
-
-		if (sectors & 0xC0) { g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g); }			// Lower right
-		if (sectors & 0x03) { g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g); }			// Upper right
-		if (sectors & 0x30) { g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g); }			// Lower left
-		if (sectors & 0x0C) { g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g); }			// Upper left
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_ARCSECTORS
-	void gdispGFillArcSectors(GDisplay *g, coord_t x, coord_t y, coord_t radius, uint8_t sectors, color_t color) {
-		coord_t a, b, P;
-
-		MUTEX_ENTER(g);
-
-		// Calculate intermediates
-		a = 1;              // x in many explanations
-		b = radius;         // y in many explanations
-		P = 4 - radius;
-		g->p.color = color;
-
-		// Away we go using Bresenham's circle algorithm
-		// Optimized to prevent double drawing
-		if (sectors & 0x06) { g->p.x = x; g->p.y = y - b; drawpixel_clip(g); }					// Upper upper
-		if (sectors & 0x60) { g->p.x = x; g->p.y = y + b; drawpixel_clip(g); }					// Lower lower
-		if (sectors & 0x81) {																	// Center right
-			g->p.y = y; g->p.x = x; g->p.x1 = x + b;
-			if (sectors & 0x18) g->p.x -= b;													// Left right
-			hline_clip(g);
-		} else if (sectors & 0x18) {															// Left center
-			g->p.x = x - b; g->p.x1 = x; g->p.y = y;
-			hline_clip(g);
-		}
-
-		do {
-			// Top half
-			switch(sectors & 0x0F) {
-			case 0x01:
-				g->p.y = y - a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x02:
-				g->p.y = y - b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				break;
-			case 0x03:
-				g->p.y = y - b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x04:
-				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				break;
-			case 0x05:
-				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y - a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x06:
-				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				break;
-			case 0x07:
-				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x08:
-				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
-				break;
-			case 0x09:
-				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0A:
-				g->p.y = y - b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				break;
-			case 0x0B:
-				g->p.y = y - b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0C:
-				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x; hline_clip(g);
-				break;
-			case 0x0D:
-				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x; hline_clip(g);
-				g->p.y = y - a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0E:
-				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x + a; hline_clip(g);
-				break;
-			case 0x0F:
-				g->p.y = y - b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y - a; g->p.x = x - b; g->p.x1 = x + b; hline_clip(g);
-				break;
-			}
-
-			// Bottom half
-			switch((sectors & 0xF0)>>4) {
-			case 0x01:
-				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
-				break;
-			case 0x02:
-				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				break;
-			case 0x03:
-				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x; hline_clip(g);
-				break;
-			case 0x04:
-				g->p.y = y + b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				break;
-			case 0x05:
-				g->p.y = y + b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				break;
-			case 0x06:
-				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				break;
-			case 0x07:
-				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x + a; hline_clip(g);
-				break;
-			case 0x08:
-				g->p.y = y + a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x09:
-				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0A:
-				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y + a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0B:
-				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x; hline_clip(g);
-				g->p.y = y + a; g->p.x = x + a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0C:
-				g->p.y = y + b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0D:
-				g->p.y = y + b; g->p.x = x; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x - a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0E:
-				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - a; g->p.x1 = x + b; hline_clip(g);
-				break;
-			case 0x0F:
-				g->p.y = y + b; g->p.x = x - a; g->p.x1 = x + a; hline_clip(g);
-				g->p.y = y + a; g->p.x = x - b; g->p.x1 = x + b; hline_clip(g);
-				break;
-			}
-
-			if (P < 0)
-				P += 3 + 2*a++;
-			else
-				P += 5 + 2*(a++ - b--);
-		} while(a < b);
-
-		// Top half
-		if (sectors & 0x02)			{ g->p.y = y - a; g->p.x = x; g->p.x1 = x + a; hline_clip(g); }
-		else if (sectors & 0x01)	{ g->p.y = y - a; g->p.x = x + a; drawpixel_clip(g); }
-		if (sectors & 0x04)			{ g->p.y = y - a; g->p.x = x - a; g->p.x1 = x; hline_clip(g); }
-		else if (sectors & 0x08)	{ g->p.y = y - a; g->p.x = x - a; drawpixel_clip(g); }
-
-		// Bottom half
-		if (sectors & 0x40)			{ g->p.y = y + a; g->p.x = x; g->p.x1 = x + a; hline_clip(g); }
-		else if (sectors & 0x80)	{ g->p.y = y + a; g->p.x = x + a; drawpixel_clip(g); }
-		if (sectors & 0x20)			{ g->p.y = y + a; g->p.x = x - a; g->p.x1 = x; hline_clip(g); }
-		else if (sectors & 0x10)	{ g->p.y = y + a; g->p.x = x - a; drawpixel_clip(g); }
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_ARC
-	#if (!GMISC_NEED_FIXEDTRIG && !GMISC_NEED_FASTTRIG) || !GFX_USE_GMISC
-		#include <math.h>
-	#endif
-
-	void gdispGDrawArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
-		coord_t a, b, P, sedge, eedge;
-		uint8_t	full, sbit, ebit, tbit;
-
-		// Normalize the angles
-		if (start < 0)
-			start -= (start/360-1)*360;
-		else if (start >= 360)
-			start %= 360;
-		if (end < 0)
-			end -= (end/360-1)*360;
-		else if (end >= 360)
-			end %= 360;
-
-		sbit = 1<<(start/45);
-		ebit = 1<<(end/45);
-		full = 0;
-		if (start == end) {
-			full = 0xFF;
-		} else if (end < start) {
-			for(tbit=sbit<<1; tbit; tbit<<=1) full |= tbit;
-			for(tbit=ebit>>1; tbit; tbit>>=1) full |= tbit;
-		} else if (sbit < 0x80) {
-			for(tbit=sbit<<1; tbit < ebit; tbit<<=1) full |= tbit;
-		}
-		tbit = start%45 == 0 ? sbit : 0;
-
-		MUTEX_ENTER(g);
-		g->p.color = color;
-
-		if (full) {
-			// Draw full sectors
-			// Optimized to prevent double drawing
-			a = 1;
-			b = radius;
-			P = 4 - radius;
-			if (full & 0x60) { g->p.y = y+b; g->p.x = x; drawpixel_clip(g); }
-			if (full & 0x06) { g->p.y = y-b; g->p.x = x; drawpixel_clip(g); }
-			if (full & 0x81) { g->p.y = y; g->p.x = x+b; drawpixel_clip(g); }
-			if (full & 0x18) { g->p.y = y; g->p.x = x-b; drawpixel_clip(g); }
-			do {
-				if (full & 0x01) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); }
-				if (full & 0x02) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
-				if (full & 0x04) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
-				if (full & 0x08) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); }
-				if (full & 0x10) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); }
-				if (full & 0x20) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
-				if (full & 0x40) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
-				if (full & 0x80) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); }
-				if (P < 0)
-					P += 3 + 2*a++;
-				else
-					P += 5 + 2*(a++ - b--);
-			} while(a < b);
-			if (full & 0xC0) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
-			if (full & 0x0C) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
-			if (full & 0x03) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
-			if (full & 0x30) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
-			if (full == 0xFF) {
-				autoflush(g);
-				MUTEX_EXIT(g);
-				return;
-			}
-		}
-
-		#if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG
-			sedge = NONFIXED(radius * ((sbit & 0x99) ? ffsin(start) : ffcos(start)) + FIXED0_5);
-			eedge = NONFIXED(radius * ((ebit & 0x99) ? ffsin(end) : ffcos(end)) + FIXED0_5);
-		#elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG
-			sedge = round(radius * ((sbit & 0x99) ? fsin(start) : fcos(start)));
-			eedge = round(radius * ((ebit & 0x99) ? fsin(end) : fcos(end)));
-		#else
-			sedge = round(radius * ((sbit & 0x99) ? sin(start*M_PI/180) : cos(start*M_PI/180)));
-			eedge = round(radius * ((ebit & 0x99) ? sin(end*M_PI/180) : cos(end*M_PI/180)));
-		#endif
-		if (sbit & 0xB4) sedge = -sedge;
-		if (ebit & 0xB4) eedge = -eedge;
-
-		if (sbit != ebit) {
-			// Draw start and end sectors
-			// Optimized to prevent double drawing
-			a = 1;
-			b = radius;
-			P = 4 - radius;
-			if ((sbit & 0x20) || (tbit & 0x40) || (ebit & 0x40)) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); }
-			if ((sbit & 0x02) || (tbit & 0x04) || (ebit & 0x04)) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); }
-			if ((sbit & 0x80) || (tbit & 0x01) || (ebit & 0x01)) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); }
-			if ((sbit & 0x08) || (tbit & 0x10) || (ebit & 0x10)) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); }
-			do {
-				if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); }
-				if (((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
-				if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
-				if (((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); }
-				if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); }
-				if (((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
-				if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
-				if (((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); }
-				if (P < 0)
-					P += 3 + 2*a++;
-				else
-					P += 5 + 2*(a++ - b--);
-			} while(a < b);
-			if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge) || ((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge))
-				{ g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
-			if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge) || ((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge))
-				{ g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
-			if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge) || ((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge))
-				{ g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
-			if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge) || ((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge))
-				{ g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
-		} else if (end < start) {
-			// Draw start/end sector where it is a non-internal angle
-			// Optimized to prevent double drawing
-			a = 1;
-			b = radius;
-			P = 4 - radius;
-			if ((sbit & 0x60) || (tbit & 0xC0)) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); }
-			if ((sbit & 0x06) || (tbit & 0x0C)) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); }
-			if ((sbit & 0x81) || (tbit & 0x03)) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); }
-			if ((sbit & 0x18) || (tbit & 0x30)) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); }
-			do {
-				if ((sbit & 0x01) && (a >= sedge || a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); }
-				if ((sbit & 0x02) && (a <= sedge || a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
-				if ((sbit & 0x04) && (a >= sedge || a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
-				if ((sbit & 0x08) && (a <= sedge || a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); }
-				if ((sbit & 0x10) && (a >= sedge || a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); }
-				if ((sbit & 0x20) && (a <= sedge || a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
-				if ((sbit & 0x40) && (a >= sedge || a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
-				if ((sbit & 0x80) && (a <= sedge || a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); }
-				if (P < 0)
-					P += 3 + 2*a++;
-				else
-					P += 5 + 2*(a++ - b--);
-			} while(a < b);
-			if (((sbit & 0x04) && (a >= sedge || a <= eedge)) || ((sbit & 0x08) && (a <= sedge || a >= eedge)))
-				{ g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
-			if (((sbit & 0x40) && (a >= sedge || a <= eedge)) || ((sbit & 0x80) && (a <= sedge || a >= eedge)))
-				{ g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
-			if (((sbit & 0x01) && (a >= sedge || a <= eedge)) || ((sbit & 0x02) && (a <= sedge || a >= eedge)))
-				{ g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
-			if (((sbit & 0x10) && (a >= sedge || a <= eedge)) || ((sbit & 0x20) && (a <= sedge || a >= eedge)))
-				{ g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
-		} else {
-			// Draw start/end sector where it is a internal angle
-			// Optimized to prevent double drawing
-			a = 1;
-			b = radius;
-			P = 4 - radius;
-			if (((sbit & 0x20) && !eedge) || ((sbit & 0x40) && !sedge)) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); }
-			if (((sbit & 0x02) && !eedge) || ((sbit & 0x04) && !sedge)) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); }
-			if (((sbit & 0x80) && !eedge) || ((sbit & 0x01) && !sedge)) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); }
-			if (((sbit & 0x08) && !eedge) || ((sbit & 0x10) && !sedge)) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); }
-			do {
-				if (((sbit & 0x01) && a >= sedge && a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); }
-				if (((sbit & 0x02) && a <= sedge && a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
-				if (((sbit & 0x04) && a >= sedge && a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
-				if (((sbit & 0x08) && a <= sedge && a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); }
-				if (((sbit & 0x10) && a >= sedge && a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); }
-				if (((sbit & 0x20) && a <= sedge && a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
-				if (((sbit & 0x40) && a >= sedge && a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
-				if (((sbit & 0x80) && a <= sedge && a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); }
-				if (P < 0)
-					P += 3 + 2*a++;
-				else
-					P += 5 + 2*(a++ - b--);
-			} while(a < b);
-			if (((sbit & 0x04) && a >= sedge && a <= eedge) || ((sbit & 0x08) && a <= sedge && a >= eedge))
-				{ g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); }
-			if (((sbit & 0x40) && a >= sedge && a <= eedge) || ((sbit & 0x80) && a <= sedge && a >= eedge))
-				{ g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); }
-			if (((sbit & 0x01) && a >= sedge && a <= eedge) || ((sbit & 0x02) && a <= sedge && a >= eedge))
-				{ g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); }
-			if (((sbit & 0x10) && a >= sedge && a <= eedge) || ((sbit & 0x20) && a <= sedge && a >= eedge))
-				{ g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); }
-		}
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_ARC
-	void gdispGFillArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) {
-		coord_t a, b, P;
-		coord_t	sy, ey;
-		fixed	sxa, sxb, sxd, exa, exb, exd;
-		uint8_t	qtr;
-
-		MUTEX_ENTER(g);
-
-		// Do the trig to get the formulas for the start and end lines.
-		sxa = exa = FIXED(x)+FIXED0_5;
-		#if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG
-			sxb = radius*ffcos(start);	sy = -NONFIXED(radius*ffsin(start) + FIXED0_5);
-			exb = radius*ffcos(end);	ey = -NONFIXED(radius*ffsin(end) + FIXED0_5);
-		#elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG
-			sxb = FP2FIXED(radius*fcos(start));	sy = -round(radius*fsin(start));
-			exb = FP2FIXED(radius*fcos(end));	ey = -round(radius*fsin(end));
-		#else
-			sxb = FP2FIXED(radius*cos(start*M_PI/180));	sy = -round(radius*sin(start*M_PI/180));
-			exb = FP2FIXED(radius*cos(end*M_PI/180));	ey = -round(radius*sin(end*M_PI/180));
-		#endif
-		sxd = sy ? sxb/sy : sxb;
-		exd = ey ? exb/ey : exb;
-
-		// Calculate which quarters and which direction we are traveling
-		qtr = 0;
-		if (sxb > 0)	qtr |= 0x01;		// S1=0001(1), S2=0000(0), S3=0010(2), S4=0011(3)
-		if (sy > 0) 	qtr |= 0x02;
-		if (exb > 0)	qtr |= 0x04;		// E1=0100(4), E2=0000(0), E3=1000(8), E4=1100(12)
-		if (ey > 0) 	qtr |= 0x08;
-		if (sy > ey)	qtr |= 0x10;		// order of start and end lines
-
-		// Calculate intermediates
-		a = 1;
-		b = radius;
-		P = 4 - radius;
-		g->p.color = color;
-		sxb += sxa;
-		exb += exa;
-
-		// Away we go using Bresenham's circle algorithm
-		// This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value
-
-		switch(qtr) {
-		case 0:		// S2E2 sy <= ey
-		case 1:		// S1E2 sy <= ey
-			if (ey && sy) {
-				g->p.x = x; g->p.x1 = x;									// E2S
-				sxa -= sxd; exa -= exd;
-			} else if (sy) {
-				g->p.x = x-b; g->p.x1 = x;								// C2S
-				sxa -= sxd;
-			} else if (ey) {
-				g->p.x = x; g->p.x1 = x+b;								// E2C
-				exa -= exd;
-			} else {
-				g->p.x = x-b; g->p.x1 = x+b;								// C2C
-			}
-			g->p.y = y;
-			hline_clip(g);
-			do {
-				if (-a >= ey) {
-					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g);		// E2S
-					sxa -= sxd; exa -= exd;
-				} else if (-a >= sy) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
-					sxa -= sxd;
-				} else if (qtr & 1) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-				}
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					if (-b >= ey) {
-						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = NONFIXED(sxb); hline_clip(g);	// E2S
-						sxb += sxd; exb += exd;
-					} else if (-b >= sy) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);			// C2S
-						sxb += sxd;
-					} else if (qtr & 1) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
-					}
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			if (-a >= ey) {
-				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g);			// E2S
-			} else if (-a >= sy) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);					// C2S
-			} else if (qtr & 1) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-			}
-			break;
-
-		case 2:		// S3E2 sy <= ey
-		case 3:		// S4E2 sy <= ey
-		case 6:		// S3E1 sy <= ey
-		case 7:		// S4E1 sy <= ey
-		case 18:	// S3E2 sy > ey
-		case 19:	// S4E2 sy > ey
-		case 22:	// S3E1 sy > ey
-		case 23:	// S4E1 sy > ey
-			g->p.y = y; g->p.x = x; g->p.x1 = x+b; hline_clip(g);								// SE2C
-			sxa += sxd; exa -= exd;
-			do {
-				if (-a >= ey) {
-					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);		// E2C
-					exa -= exd;
-				} else if (!(qtr & 4)) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);					// C2C
-				}
-				if (a <= sy) {
-					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);		// S2C
-					sxa += sxd;
-				} else if (!(qtr & 1)) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);					// C2C
-				}
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					if (-b >= ey) {
-						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);		// E2C
-						exb += exd;
-					} else if (!(qtr & 4)) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);					// C2C
-					}
-					if (b <= sy) {
-						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);		// S2C
-						sxb -= sxd;
-					} else if (!(qtr & 1)) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); 				// C2C
-					}
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			if (-a >= ey) {
-				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
-			} else if (!(qtr & 4)) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-			}
-			if (a <= sy) {
-				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+a; hline_clip(g);				// S2C
-			} else if (!(qtr & 1)) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+a; hline_clip(g);							// C2C
-			}
-			break;
-
-		case 4:		// S2E1 sy <= ey
-		case 5:		// S1E1 sy <= ey
-			g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
-			do {
-				if (-a >= ey) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
-					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
-					sxa -= sxd; exa -= exd;
-				} else if (-a >= sy) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
-					sxa -= sxd;
-				} else if (qtr & 1) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-				}
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					if (-b >= ey) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);			// C2S
-						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);			// E2C
-						sxb += sxd; exb += exd;
-					} else if (-b >= sy) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);			// C2S
-						sxb += sxd;
-					} else if (qtr & 1) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
-					}
-					g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);							// C2C
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			if (-a >= ey) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);					// C2S
-				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);					// E2C
-			} else if (-a >= sy) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);					// C2S
-			} else if (qtr & 1) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-			}
-			g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);									// C2C
-			break;
-
-		case 8:		// S2E3 sy <= ey
-		case 9:		// S1E3 sy <= ey
-		case 12:	// S2E4 sy <= ey
-		case 13:	// S1E4 sy <= ey
-		case 24:	// S2E3 sy > ey
-		case 25:	// S1E3 sy > ey
-		case 28:	// S2E3 sy > ey
-		case 29:	// S1E3 sy > ey
-			g->p.y = y; g->p.x = x-b; g->p.x1 = x; hline_clip(g);								// C2SE
-			sxa -= sxd; exa += exd;
-			do {
-				if (-a >= sy) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);		// C2S
-					sxa -= sxd;
-				} else if (qtr & 1) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);					// C2C
-				}
-				if (a <= ey) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);		// C2E
-					exa += exd;
-				} else if (qtr & 4) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);					// C2C
-				}
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					if (-b >= sy) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);		// C2S
-						sxb += sxd;
-					} else if (qtr & 1) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);					// C2C
-					}
-					if (b <= ey) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);		// C2E
-						exb -= exd;
-					} else if (qtr & 4) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); 				// C2C
-					}
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			if (-a >= sy) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
-			} else if (qtr & 1) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-			}
-			if (a <= ey) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
-			} else if (qtr & 4) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+a; hline_clip(g);							// C2C
-			}
-			break;
-
-		case 10:	// S3E3 sy <= ey
-		case 14:	// S3E4 sy <= ey
-			g->p.y = y; g->p.x = x; drawpixel_clip(g);													// S2E
-			sxa += sxd; exa += exd;
-			do {
-				if (a <= sy) {
-					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g);		// S2E
-					sxa += sxd; exa += exd;
-				} else if (a <= ey) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
-					exa += exd;
-				} else if (qtr & 4) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-				}
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					if (b <= sy) {
-						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = NONFIXED(exb); hline_clip(g);		// S2E
-						sxb -= sxd; exb -= exd;
-					} else if (b <= ey) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);				// C2E
-						exb -= exd;
-					} else if (qtr & 4) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);							// C2C
-					}
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			if (a <= sy) {
-				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g);		// S2E
-			} else if (a <= ey) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
-			} else if (qtr & 4) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-			}
-			break;
-
-		case 11:	// S4E3 sy <= ey
-		case 15:	// S4E4 sy <= ey
-			g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
-			do {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-				if (a <= sy) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
-					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
-					sxa += sxd; exa += exd;
-				} else if (a <= ey) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
-					exa += exd;
-				} else if (qtr & 4) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-				}
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);							// C2C
-					if (b <= sy) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);			// C2E
-						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);			// S2C
-						sxb -= sxd; exb -= exd;
-					} else if (b <= ey) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);			// C2E
-						exb -= exd;
-					} else if (qtr & 4) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
-					}
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
-			if (a <= sy) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);					// C2E
-				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);					// S2C
-			} else if (a <= ey) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);					// C2E
-			} else if (qtr & 4) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-			}
-			break;
-
-		case 16:	// S2E2	sy > ey
-		case 20:	// S2E1 sy > ey
-			g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
-			sxa -= sxd; exa -= exd;
-			do {
-				if (-a >= sy) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);				// C2S
-					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
-					sxa -= sxd; exa -= exd;
-				} else if (-a >= ey) {
-					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
-					exa -= exd;
-				} else if (!(qtr & 4)){
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); 						// C2C
-				}
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); 							// C2C
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					if (-b >= sy) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g);			// C2S
-						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);			// E2C
-						sxb += sxd; exb += exd;
-					} else if (-b >= ey) {
-						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);			// E2C
-						exb += exd;
-					} else if (!(qtr & 4)){
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); 					// C2C
-					}
-					g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); 						// C2C
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			if (-a >= sy) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g);					// C2S
-				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);					// E2C
-			} else if (-a >= ey) {
-				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);					// E2C
-			} else if (!(qtr & 4)){
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); 							// C2C
-			}
-			g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); 								// C2C
-			break;
-
-		case 17:	// S1E2 sy > ey
-		case 21:	// S1E1 sy > ey
-			if (sy) {
-				g->p.x = x; g->p.x1 = x;																// E2S
-				sxa -= sxd; exa -= exd;
-			} else {
-				g->p.x = x; g->p.x1 = x+b;															// E2C
-				exa -= exd;
-			}
-			g->p.y = y;
-			hline_clip(g);
-			do {
-				if (-a >= sy) {
-					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g);		// E2S
-					sxa -= sxd; exa -= exd;
-				} else if (-a >= ey) {
-					g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);				// E2C
-					exa -= exd;
-				} else if (!(qtr & 4)) {
-					g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-				}
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					if (-b >= sy) {
-						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = NONFIXED(sxb); hline_clip(g);	// E2S
-						sxb += sxd; exb += exd;
-					} else if (-b >= ey) {
-						g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g);			// E2C
-						exb += exd;
-					} else if (!(qtr & 4)) {
-						g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
-					}
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			if (-a >= sy) {
-				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g);			// E2S
-			} else if (-a >= ey) {
-				g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g);					// E2C
-			} else if (!(qtr & 4)) {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-			}
-			break;
-
-		case 26:	// S3E3 sy > ey
-		case 27:	// S4E3 sy > ey
-			g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
-			do {
-				g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-				if (a <= ey) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);				// C2E
-					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
-					sxa += sxd; exa += exd;
-				} else if (a <= sy) {
-					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
-					sxa += sxd;
-				} else if (!(qtr & 1)) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-				}
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);							// C2C
-					if (b <= ey) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g);			// C2E
-						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);			// S2C
-						sxb -= sxd; exb -= exd;
-					} else if (b <= sy) {
-						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);			// S2C
-						sxb -= sxd;
-					} else if (!(qtr & 1)) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
-					}
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);									// C2C
-			if (a <= ey) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g);					// C2E
-				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);					// S2C
-			} else if (a <= sy) {
-				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);					// S2C
-			} else if (!(qtr & 4)) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-			}
-			break;
-
-		case 30:	// S3E4 sy > ey
-		case 31:	// S4E4 sy > ey
-			do {
-				if (a <= ey) {
-					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g);		// S2E
-					sxa += sxd; exa += exd;
-				} else if (a <= sy) {
-					g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
-					sxa += sxd;
-				} else if (!(qtr & 1)) {
-					g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);							// C2C
-				}
-				if (P < 0) {
-					P += 3 + 2*a++;
-				} else {
-					if (b <= ey) {
-						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = NONFIXED(exb); hline_clip(g);	// S2E
-						sxb -= sxd; exb -= exd;
-					} else if (b <= sy) {
-						g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g);			// S2C
-						sxb -= sxd;
-					} else if (!(qtr & 1)) {
-						g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g);						// C2C
-					}
-					P += 5 + 2*(a++ - b--);
-				}
-			} while(a < b);
-			if (a <= ey) {
-				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);				// S2C
-			} else if (a <= sy) {
-				g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g);					// S2C
-			} else if (!(qtr & 4)) {
-				g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g);								// C2C
-			}
-			break;
-		}
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_ARC || GDISP_NEED_ARCSECTORS
-	void gdispGDrawRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
-		if (2*radius > cx || 2*radius > cy) {
-			gdispGDrawBox(g, x, y, cx, cy, color);
-			return;
-		}
-
-		#if GDISP_NEED_ARCSECTORS
-			gdispGDrawArcSectors(g, x+radius, y+radius, radius, 0x0C, color);
-			gdispGDrawArcSectors(g, x+cx-1-radius, y+radius, radius, 0x03, color);
-			gdispGDrawArcSectors(g, x+cx-1-radius, y+cy-1-radius, radius, 0xC0, color);
-			gdispGDrawArcSectors(g, x+radius, y+cy-1-radius, radius, 0x30, color);
-		#else
-			gdispGDrawArc(g, x+radius, y+radius, radius, 90, 180, color);
-			gdispGDrawArc(g, x+cx-1-radius, y+radius, radius, 0, 90, color);
-			gdispGDrawArc(g, x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
-			gdispGDrawArc(g, x+radius, y+cy-1-radius, radius, 180, 270, color);
-		#endif
-		gdispGDrawLine(g, x+radius+1, y, x+cx-2-radius, y, color);
-		gdispGDrawLine(g, x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color);
-		gdispGDrawLine(g, x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color);
-		gdispGDrawLine(g, x, y+radius+1, x, y+cy-2-radius, color);
-	}
-#endif
-
-#if GDISP_NEED_ARC || GDISP_NEED_ARCSECTORS
-	void gdispGFillRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
-		coord_t radius2;
-
-		radius2 = radius*2;
-		if (radius2 > cx || radius2 > cy) {
-			gdispGFillArea(g, x, y, cx, cy, color);
-			return;
-		}
-		#if GDISP_NEED_ARCSECTORS
-			gdispGFillArcSectors(g, x+radius, y+radius, radius, 0x0C, color);
-			gdispGFillArcSectors(g, x+cx-1-radius, y+radius, radius, 0x03, color);
-			gdispGFillArcSectors(g, x+cx-1-radius, y+cy-1-radius, radius, 0xC0, color);
-			gdispGFillArcSectors(g, x+radius, y+cy-1-radius, radius, 0x30, color);
-		#else
-			gdispGFillArc(g, x+radius, y+radius, radius, 90, 180, color);
-			gdispGFillArc(g, x+cx-1-radius, y+radius, radius, 0, 90, color);
-			gdispGFillArc(g, x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
-			gdispGFillArc(g, x+radius, y+cy-1-radius, radius, 180, 270, color);
-		#endif
-		gdispGFillArea(g, x+radius+1, y, cx-radius2, radius, color);
-		gdispGFillArea(g, x+radius+1, y+cy-radius, cx-radius2, radius, color);
-		gdispGFillArea(g, x, y+radius, cx, cy-radius2, color);
-	}
-#endif
-
-#if GDISP_NEED_PIXELREAD
-	color_t gdispGGetPixelColor(GDisplay *g, coord_t x, coord_t y) {
-		color_t		c;
-
-		/* Always synchronous as it must return a value */
-		MUTEX_ENTER(g);
-		#if GDISP_HARDWARE_PIXELREAD
-			#if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT
-				if (gvmt(g)->get)
-			#endif
-			{
-				// Best is direct pixel read
-				g->p.x = x;
-				g->p.y = y;
-				c = gdisp_lld_get_pixel_color(g);
-				MUTEX_EXIT(g);
-				return c;
-			}
-		#endif
-		#if GDISP_HARDWARE_PIXELREAD != TRUE && GDISP_HARDWARE_STREAM_READ
-			#if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT
-				if (gvmt(g)->readcolor)
-			#endif
-			{
-				// Next best is hardware streaming
-				g->p.x = x;
-				g->p.y = y;
-				g->p.cx = 1;
-				g->p.cy = 1;
-				gdisp_lld_read_start(g);
-				c = gdisp_lld_read_color(g);
-				gdisp_lld_read_stop(g);
-				MUTEX_EXIT(g);
-				return c;
-			}
-		#endif
-		#if GDISP_HARDWARE_PIXELREAD != TRUE && GDISP_HARDWARE_STREAM_READ != TRUE
-			#if !GDISP_HARDWARE_PIXELREAD && !GDISP_HARDWARE_STREAM_READ
-				// Worst is "not possible"
-				#error "GDISP: GDISP_NEED_PIXELREAD has been set but there is no hardware support for reading the display"
-			#endif
-			MUTEX_EXIT(g);
-			return 0;
-		#endif
-	}
-#endif
-
-#if GDISP_NEED_SCROLL
-	void gdispGVerticalScroll(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) {
-		coord_t		abslines;
-		#if GDISP_HARDWARE_SCROLL != TRUE
-			coord_t 	fy, dy, ix, fx, i, j;
-		#endif
-
-		MUTEX_ENTER(g);
-		#if NEED_CLIPPING
-			#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-				if (!gvmt(g)->setclip)
-			#endif
-			{
-				if (x < g->clipx0) { cx -= g->clipx0 - x; x = g->clipx0; }
-				if (y < g->clipy0) { cy -= g->clipy0 - y; y = g->clipy0; }
-				if (!lines || cx <= 0 || cy <= 0 || x >= g->clipx1 || y >= g->clipy1) { MUTEX_EXIT(g); return; }
-				if (x+cx > g->clipx1)	cx = g->clipx1 - x;
-				if (y+cy > g->clipy1)	cy = g->clipy1 - y;
-			}
-		#endif
-
-		abslines = lines < 0 ? -lines : lines;
-		if (abslines >= cy) {
-			abslines = cy;
-			cy = 0;
-		} else {
-			// Best is hardware scroll
-			#if GDISP_HARDWARE_SCROLL
-				#if GDISP_HARDWARE_SCROLL == HARDWARE_AUTODETECT
-					if (gvmt(g)->vscroll)
-				#endif
-				{
-					g->p.x = x;
-					g->p.y = y;
-					g->p.cx = cx;
-					g->p.cy = cy;
-					g->p.y1 = lines;
-					g->p.color = bgcolor;
-					gdisp_lld_vertical_scroll(g);
-					cy -= abslines;
-				}
-				#if GDISP_HARDWARE_SCROLL == HARDWARE_AUTODETECT
-					else
-				#endif
-			#elif GDISP_LINEBUF_SIZE == 0
-				#error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support and GDISP_LINEBUF_SIZE is zero."
-			#endif
-
-			// Scroll Emulation
-			#if GDISP_HARDWARE_SCROLL != TRUE
-				{
-					cy -= abslines;
-					if (lines < 0) {
-						fy = y+cy-1;
-						dy = -1;
-					} else {
-						fy = y;
-						dy = 1;
-					}
-					// Move the screen - one line at a time
-					for(i = 0; i < cy; i++, fy += dy) {
-
-						// Handle where the buffer is smaller than a line
-						for(ix=0; ix < cx; ix += GDISP_LINEBUF_SIZE) {
-
-							// Calculate the data we can move in one operation
-							fx = cx - ix;
-							if (fx > GDISP_LINEBUF_SIZE)
-								fx = GDISP_LINEBUF_SIZE;
-
-							// Read one line of data from the screen
-
-							// Best line read is hardware streaming
-							#if GDISP_HARDWARE_STREAM_READ
-								#if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT
-									if (gvmt(g)->readstart)
-								#endif
-								{
-									g->p.x = x+ix;
-									g->p.y = fy+lines;
-									g->p.cx = fx;
-									g->p.cy = 1;
-									gdisp_lld_read_start(g);
-									for(j=0; j < fx; j++)
-										g->linebuf[j] = gdisp_lld_read_color(g);
-									gdisp_lld_read_stop(g);
-								}
-								#if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT
-									else
-								#endif
-							#endif
-
-							// Next best line read is single pixel reads
-							#if GDISP_HARDWARE_STREAM_READ != TRUE && GDISP_HARDWARE_PIXELREAD
-								#if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT
-									if (gvmt(g)->get)
-								#endif
-								{
-									for(j=0; j < fx; j++) {
-										g->p.x = x+ix+j;
-										g->p.y = fy+lines;
-										g->linebuf[j] = gdisp_lld_get_pixel_color(g);
-									}
-								}
-								#if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT
-									else {
-										// Worst is "not possible"
-										MUTEX_EXIT(g);
-										return;
-									}
-								#endif
-							#endif
-
-							// Worst is "not possible"
-							#if !GDISP_HARDWARE_STREAM_READ && !GDISP_HARDWARE_PIXELREAD
-								#error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support for scrolling or reading pixels."
-							#endif
-
-							// Write that line to the new location
-
-							// Best line write is hardware bitfills
-							#if GDISP_HARDWARE_BITFILLS
-								#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
-									if (gvmt(g)->blit)
-								#endif
-								{
-									g->p.x = x+ix;
-									g->p.y = fy;
-									g->p.cx = fx;
-									g->p.cy = 1;
-									g->p.x1 = 0;
-									g->p.y1 = 0;
-									g->p.x2 = fx;
-									g->p.ptr = (void *)g->linebuf;
-									gdisp_lld_blit_area(g);
-								}
-								#if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT
-									else
-								#endif
-							#endif
-
-							// Next best line write is hardware streaming
-							#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE
-								#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-									if (gvmt(g)->writestart)
-								#endif
-								{
-									g->p.x = x+ix;
-									g->p.y = fy;
-									g->p.cx = fx;
-									g->p.cy = 1;
-									gdisp_lld_write_start(g);
-									#if GDISP_HARDWARE_STREAM_POS
-										gdisp_lld_write_pos(g);
-									#endif
-									for(j = 0; j < fx; j++) {
-										g->p.color = g->linebuf[j];
-										gdisp_lld_write_color(g);
-									}
-									gdisp_lld_write_stop(g);
-								}
-								#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT
-									else
-								#endif
-							#endif
-
-							// Next best line write is drawing pixels in combination with filling
-							#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS && GDISP_HARDWARE_DRAWPIXEL
-								// We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming.
-								#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-									if (gvmt(g)->fill)
-								#endif
-								{
-									g->p.y = fy;
-									g->p.cy = 1;
-									g->p.x = x+ix;
-									g->p.cx = 1;
-									for(j = 0; j < fx; ) {
-										g->p.color = g->linebuf[j];
-										if (j + g->p.cx < fx && g->linebuf[j] == g->linebuf[j + g->p.cx])
-											g->p.cx++;
-										else if (g->p.cx == 1) {
-											gdisp_lld_draw_pixel(g);
-											j++;
-											g->p.x++;
-										} else {
-											gdisp_lld_fill_area(g);
-											j += g->p.cx;
-											g->p.x += g->p.cx;
-											g->p.cx = 1;
-										}
-									}
-								}
-								#if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT
-									else
-								#endif
-							#endif
-
-							// Worst line write is drawing pixels
-							#if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL
-								// The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming
-								//#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT
-								//	if (gvmt(g)->pixel)
-								//#endif
-								{
-									g->p.y = fy;
-									for(g->p.x = x+ix, j = 0; j < fx; g->p.x++, j++) {
-										g->p.color = g->linebuf[j];
-										gdisp_lld_draw_pixel(g);
-									}
-								}
-							#endif
-						}
-					}
-				}
-			#endif
-		}
-
-		/* fill the remaining gap */
-		g->p.x = x;
-		g->p.y = lines > 0 ? (y+cy) : y;
-		g->p.cx = cx;
-		g->p.cy = abslines;
-		g->p.color = bgcolor;
-		fillarea(g);
-		autoflush_stopdone(g);
-		MUTEX_EXIT(g);
-	}
-#endif
-
-#if GDISP_NEED_CONTROL
-	#if GDISP_HARDWARE_CONTROL
-		void gdispGControl(GDisplay *g, unsigned what, void *value) {
-			#if GDISP_HARDWARE_CONTROL == HARDWARE_AUTODETECT
-				if (!gvmt(g)->control)
-					return;
-			#endif
-			MUTEX_ENTER(g);
-			g->p.x = what;
-			g->p.ptr = value;
-			if (what == GDISP_CONTROL_ORIENTATION) {
-				switch ((orientation_t) value) {
-				case GDISP_ROTATE_LANDSCAPE:
-					g->p.ptr = g->g.Width >= g->g.Height ? (void *)GDISP_ROTATE_0 : (void *)GDISP_ROTATE_90;
-					break;
-				case GDISP_ROTATE_PORTRAIT:
-					g->p.ptr = g->g.Width >= g->g.Height ? (void *)GDISP_ROTATE_90 : (void *)GDISP_ROTATE_0;
-					break;
-				default:
-					break;
-				}
-			}
-			gdisp_lld_control(g);
-			#if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION
-				if (what == GDISP_CONTROL_ORIENTATION) {
-					// Best is hardware clipping
-					#if GDISP_HARDWARE_CLIP
-						#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-							if (gvmt(g)->setclip)
-						#endif
-						{
-							g->p.x = 0;
-							g->p.y = 0;
-							g->p.cx = g->g.Width;
-							g->p.cy = g->g.Height;
-							gdisp_lld_set_clip(g);
-						}
-						#if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT
-							else
-						#endif
-					#endif
-
-					// Worst is software clipping
-					#if GDISP_HARDWARE_CLIP != TRUE
-						{
-							g->clipx0 = 0;
-							g->clipy0 = 0;
-							g->clipx1 = g->g.Width;
-							g->clipy1 = g->g.Height;
-						}
-					#endif
-				}
-			#endif
-			MUTEX_EXIT(g);
-		}
-	#else
-		void gdispGControl(GDisplay *g, unsigned what, void *value) {
-			(void)g;
-			(void)what;
-			(void)value;
-			/* Ignore everything */
-		}
-	#endif
-#endif
-
-#if GDISP_NEED_QUERY
-	#if GDISP_HARDWARE_QUERY
-		void *gdispGQuery(GDisplay *g, unsigned what) {
-			void *res;
-
-			#if GDISP_HARDWARE_QUERY == HARDWARE_AUTODETECT
-				if (!gvmt(g)->query)
-					return -1;
-			#endif
-			MUTEX_ENTER(g);
-			g->p.x = (coord_t)what;
-			res = gdisp_lld_query(g);
-			MUTEX_EXIT(g);
-			return res;
-		}
-	#else
-		void *gdispGQuery(GDisplay *g, unsigned what) {
-			(void) what;
-			return (void *)-1;
-		}
-	#endif
-#endif
-
-/*===========================================================================*/
-/* High Level Driver Routines.                                               */
-/*===========================================================================*/
-
-void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
-	if (cx <= 0 || cy <= 0) return;
-	cx = x+cx-1; cy = y+cy-1;			// cx, cy are now the end point.
-
-	MUTEX_ENTER(g);
-
-	g->p.color = color;
-
-	if (cx - x > 2) {
-		g->p.x = x; g->p.y = y; g->p.x1 = cx; hline_clip(g);
-		if (y != cy) {
-			g->p.x = x; g->p.y = cy; g->p.x1 = cx; hline_clip(g);
-			if (cy - y > 2) {
-				y++; cy--;
-				g->p.x = x; g->p.y = y; g->p.y1 = cy; vline_clip(g);
-				g->p.x = cx; g->p.y = y; g->p.y1 = cy; vline_clip(g);
-			}
-		}
-	} else {
-		g->p.x = x; g->p.y = y; g->p.y1 = cy; vline_clip(g);
-		if (x != cx) {
-			g->p.x = cx; g->p.y = y; g->p.y1 = cy; vline_clip(g);
-		}
-	}
-
-	autoflush(g);
-	MUTEX_EXIT(g);
-}
-
-#if GDISP_NEED_CONVEX_POLYGON
-	void gdispGDrawPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) {
-		const point	*epnt, *p;
-
-		epnt = &pntarray[cnt-1];
-
-		MUTEX_ENTER(g);
-		g->p.color = color;
-		for(p = pntarray; p < epnt; p++) {
-			g->p.x=tx+p->x; g->p.y=ty+p->y; g->p.x1=tx+p[1].x; g->p.y1=ty+p[1].y; line_clip(g);
-		}
-		g->p.x=tx+p->x; g->p.y=ty+p->y; g->p.x1=tx+pntarray->x; g->p.y1=ty+pntarray->y; line_clip(g);
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-
-	void gdispGFillConvexPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) {
-		const point	*lpnt, *rpnt, *epnts;
-		fixed		lx, rx, lk, rk;
-		coord_t		y, ymax, lxc, rxc;
-
-		epnts = &pntarray[cnt-1];
-
-		/* Find a top point */
-		rpnt = pntarray;
-		for(lpnt=pntarray+1; lpnt <= epnts; lpnt++) {
-			if (lpnt->y < rpnt->y)
-				rpnt = lpnt;
-		}
-		lx = rx = FIXED(rpnt->x);
-		y = rpnt->y;
-
-		/* Work out the slopes of the two attached line segs */
-		for (lpnt = rpnt <= pntarray ? epnts : rpnt-1; lpnt->y == y; cnt--) {
-			if (!cnt) return;
-			lx = FIXED(lpnt->x);
-			lpnt = lpnt <= pntarray ? epnts : lpnt-1;
-		}
-		for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) {
-			if (!cnt) return;
-			rx = FIXED(rpnt->x);
-			rpnt = rpnt >= epnts ? pntarray : rpnt+1;
-		}
-		lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y);
-		rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y);
-
-		MUTEX_ENTER(g);
-		g->p.color = color;
-		while(1) {
-			/* Determine our boundary */
-			ymax = rpnt->y < lpnt->y ? rpnt->y : lpnt->y;
-
-			/* Scan down the line segments until we hit a boundary */
-			for(; y < ymax; y++) {
-				lxc = NONFIXED(lx);
-				rxc = NONFIXED(rx);
-				/*
-				 * Doesn't print the right hand point in order to allow polygon joining.
-				 * Also ensures that we draw from left to right with the minimum number
-				 * of pixels.
-				 */
-				if (lxc < rxc) {
-					g->p.x=tx+lxc; g->p.y=ty+y; g->p.x1=tx+rxc-1; hline_clip(g);
-				} else if (lxc > rxc) {
-					g->p.x=tx+rxc; g->p.y=ty+y; g->p.x1=tx+lxc-1; hline_clip(g);
-				}
-
-				lx += lk;
-				rx += rk;
-			}
-
-			if (!cnt) {
-				autoflush(g);
-				MUTEX_EXIT(g);
-				return;
-			}
-			cnt--;
-
-			/* Replace the appropriate point */
-			if (ymax == lpnt->y) {
-				for (lpnt = lpnt <= pntarray ? epnts : lpnt-1; lpnt->y == y; cnt--) {
-					if (!cnt) {
-						autoflush(g);
-						MUTEX_EXIT(g);
-						return;
-					}
-					lx = FIXED(lpnt->x);
-					lpnt = lpnt <= pntarray ? epnts : lpnt-1;
-				}
-				lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y);
-			} else {
-				for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) {
-					if (!cnt) {
-						autoflush(g);
-						MUTEX_EXIT(g);
-						return;
-					}
-					rx = FIXED(rpnt->x);
-					rpnt = rpnt >= epnts ? pntarray : rpnt+1;
-				}
-				rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y);
-			}
-		}
-	}
-
-	static int32_t rounding_div(const int32_t n, const int32_t d)
-	{
-		if ((n < 0) != (d < 0))
-			return (n - d/2) / d;
-		else
-			return (n + d/2) / d;
-	}
-
-	/* Find a vector (nx, ny) that is perpendicular to (dx, dy) and has length
-	 * equal to 'norm'. */
-	static void get_normal_vector(coord_t dx, coord_t dy, coord_t norm, coord_t *nx, coord_t *ny)
-	{
-		int32_t dx2, dy2, len_sq, norm_sq, norm_sq2;
-		int div, step, best, delta, abs_delta;
-
-		dx2 = dx; dy2 = dy;
-		norm_sq = (int32_t)norm * norm;
-		norm_sq2 = norm_sq * 512;
-
-		/* Scale dx2 and dy2 so that
-		 *     len_sq / 2 <= norm_sq * 512 <= len_sq * 2.
-		 * The scaling by 512 is to yield higher accuracy in division later. */
-		len_sq = dx2 * dx2 + dy2 * dy2;
-
-		if (len_sq < norm_sq2)
-		{
-			while (len_sq && len_sq < norm_sq2)
-			{
-				len_sq <<= 2; dx2 <<= 1; dy2 <<= 1;
-			}
-		}
-		else if (len_sq > norm_sq2)
-		{
-			while (len_sq && len_sq > norm_sq2)
-			{
-				len_sq >>= 2; dx2 >>= 1; dy2 >>= 1;
-			}
-		}
-
-		/* Now find the divider div so that
-		 *     len_sq / div^2 == norm_sq   i.e.  div = sqrt(len_sq / norm_sq)
-		 *
-		 * This is done using bisection search to avoid the need for floating
-		 * point sqrt.
-		 *
-		 * Based on previous scaling, we know that
-		 *     len_sq / 2 <= norm_sq * 512   <=>   div <= sqrt(1024) = 32
-		 *     len_sq * 2 >= norm_sq * 512   <=>   div >= sqrt(256) = 16
-		 */
-		div = 24; step = 8;
-		best = 256;
-
-		for (;;)
-		{
-			dx = dx2 / div;
-			dy = dy2 / div;
-			len_sq = dx*dx + dy*dy;
-
-			delta = len_sq - norm_sq;
-
-			abs_delta = (delta >= 0) ? delta : -delta;
-
-			if (abs_delta < best)
-			{
-				*nx = dy;
-				*ny = -dx;
-				best = abs_delta;
-			}
-
-			if (delta > 0)
-				div += step;
-			else if (delta < 0)
-				div -= step;
-			else if (delta == 0)
-				break;
-
-			if (step == 0)
-				break;
-			else
-				step >>= 1; /* Do one round with step = 0 to calculate final result. */
-		}
-	}
-
-	void gdispGDrawThickLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color, coord_t width, bool_t round) {
-		coord_t dx, dy, nx = 0, ny = 0;
-
-		/* Compute the direction vector for the line */
-		dx = x1 - x0;
-		dy = y1 - y0;
-
-		/* Draw a small dot if the line length is zero. */
-		if (dx == 0 && dy == 0)
-			dx += 1;
-
-		/* Compute a normal vector with length 'width'. */
-		get_normal_vector(dx, dy, width, &nx, &ny);
-
-		/* Handle 1px wide lines gracefully */
-		if (nx == 0 && ny == 0)
-			nx = 1;
-
-		/* Offset the x0,y0 by half the width of the line. This way we
-		 * can keep the width of the line accurate even if it is not evenly
-		 * divisible by 2.
-		 */
-		{
-			x0 -= rounding_div(nx, 2);
-			y0 -= rounding_div(ny, 2);
-		}
-
-		/* Fill in the point array */
-		if (!round) {
-			/* We use 4 points for the basic line shape:
-			 *
-			 *  pt1                                      pt2
-			 * (+n) ------------------------------------ (d+n)
-			 *   |                                       |
-			 * (0,0) ----------------------------------- (d)
-			 *  pt0                                      pt3
-			 */
-			point pntarray[4];
-
-			pntarray[0].x = 0;
-			pntarray[0].y = 0;
-			pntarray[1].x = nx;
-			pntarray[1].y = ny;
-			pntarray[2].x = dx + nx;
-			pntarray[2].y = dy + ny;
-			pntarray[3].x = dx;
-			pntarray[3].y = dy;
-
-			gdispGFillConvexPoly(g, x0, y0, pntarray, 4, color);
-		} else {
-			/* We use 4 points for basic shape, plus 4 extra points for ends:
-			 *
-			 *           pt3 ------------------ pt4
-			 *          /                         \
-			 *        pt2                        pt5
-			 *         |                          |
-			 *        pt1                        pt6
-			 *         \                         /
-			 *          pt0 -------------------pt7
-			 */
-			point pntarray[8];
-			coord_t nx2, ny2;
-
-			/* Magic numbers:
-			 * 75/256  = sin(45) / (1 + sqrt(2))		diagonal octagon segments
-			 * 106/256 = 1 / (1 + sqrt(2))				octagon side
-			 * 53/256  = 0.5 / (1 + sqrt(2))			half of octagon side
-			 * 150/256 = 1 - 1 / (1 + sqrt(2))	  		octagon height minus one side
-			 */
-
-			/* Rotate the normal vector 45 deg counter-clockwise and reduce
-			 * to 1 / (1 + sqrt(2)) length, for forming octagonal ends. */
-			nx2 = rounding_div((nx * 75 + ny * 75), 256);
-			ny2 = rounding_div((-nx * 75 + ny * 75), 256);
-
-			/* Offset and extend the line so that the center of the octagon
-			 * is at the specified points. */
-			x0 += ny * 53 / 256;
-			y0 -= nx * 53 / 256;
-			dx -= ny * 106 / 256;
-			dy += nx * 106 / 256;
-
-			/* Now fill in the points by summing the calculated vectors. */
-			pntarray[0].x = 0;
-			pntarray[0].y = 0;
-			pntarray[1].x = nx2;
-			pntarray[1].y = ny2;
-			pntarray[2].x = nx2 + nx * 106/256;
-			pntarray[2].y = ny2 + ny * 106/256;
-			pntarray[3].x = nx;
-			pntarray[3].y = ny;
-			pntarray[4].x = dx + nx;
-			pntarray[4].y = dy + ny;
-			pntarray[5].x = dx + nx - nx2;
-			pntarray[5].y = dy + ny - ny2;
-			pntarray[6].x = dx + nx * 150/256 - nx2;
-			pntarray[6].y = dy + ny * 150/256 - ny2;
-			pntarray[7].x = dx;
-			pntarray[7].y = dy;
-
-			gdispGFillConvexPoly(g, x0, y0, pntarray, 8, color);
-		}
-	}
-#endif
-
-#if GDISP_NEED_TEXT
-	#include "mcufont/mcufont.h"
-
-	#if GDISP_NEED_ANTIALIAS && GDISP_HARDWARE_PIXELREAD
-		static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
-			#define GD	((GDisplay *)state)
-			if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x+count <= GD->t.clipx0 || x >= GD->t.clipx1)
-				return;
-			if (x < GD->t.clipx0) {
-				count -= GD->t.clipx0 - x;
-				x = GD->t.clipx0;
-			}
-			if (x+count > GD->t.clipx1)
-				count = GD->t.clipx1 - x;
-			if (alpha == 255) {
-				GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color;
-				hline_clip(GD);
-			} else {
-				for (; count; count--, x++) {
-					GD->p.x = x; GD->p.y = y;
-					GD->p.color = gdispBlendColor(GD->t.color, gdisp_lld_get_pixel_color(GD), alpha);
-					drawpixel_clip(GD);
-				}
-			}
-			#undef GD
-		}
-	#else
-		static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
-			#define GD	((GDisplay *)state)
-			if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x+count <= GD->t.clipx0 || x >= GD->t.clipx1)
-				return;
-			if (x < GD->t.clipx0) {
-				count -= GD->t.clipx0 - x;
-				x = GD->t.clipx0;
-			}
-			if (x+count > GD->t.clipx1)
-				count = GD->t.clipx1 - x;
-			if (alpha > 0x80) {			// A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased
-				GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color;
-				hline_clip(GD);
-			}
-			#undef GD
-		}
-	#endif
-
-	#if GDISP_NEED_ANTIALIAS
-		static void fillcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) {
-			#define GD	((GDisplay *)state)
-			if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x+count <= GD->t.clipx0 || x >= GD->t.clipx1)
-				return;
-			if (x < GD->t.clipx0) {
-				count -= GD->t.clipx0 - x;
-				x = GD->t.clipx0;
-			}
-			if (x+count > GD->t.clipx1)
-				count = GD->t.clipx1 - x;
-			if (alpha == 255) {
-				GD->p.color = GD->t.color;
-			} else {
-				GD->p.color = gdispBlendColor(GD->t.color, GD->t.bgcolor, alpha);
-			}
-			GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1;
-			hline_clip(GD);
-			#undef GD
-		}
-	#else
-		#define fillcharline	drawcharline
-	#endif
-
-	/* Callback to render characters. */
-	static uint8_t drawcharglyph(int16_t x, int16_t y, mf_char ch, void *state) {
-		#define GD	((GDisplay *)state)
-			return mf_render_character(GD->t.font, x, y, ch, drawcharline, state);
-		#undef GD
-	}
-
-	/* Callback to render characters. */
-	static uint8_t fillcharglyph(int16_t x, int16_t y, mf_char ch, void *state) {
-		#define GD	((GDisplay *)state)
-			return mf_render_character(GD->t.font, x, y, ch, fillcharline, state);
-		#undef GD
-	}
-
-	void gdispGDrawChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color) {
-		MUTEX_ENTER(g);
-		g->t.font = font;
-		g->t.clipx0 = x;
-		g->t.clipy0 = y;
-		g->t.clipx1 = x + mf_character_width(font, c) + font->baseline_x;
-		g->t.clipy1 = y + font->height;
-		g->t.color = color;
-		mf_render_character(font, x, y, c, drawcharline, g);
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-
-	void gdispGFillChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) {
-		MUTEX_ENTER(g);
-		g->p.cx = mf_character_width(font, c) + font->baseline_x;
-		g->p.cy = font->height;
-		g->t.font = font;
-		g->t.clipx0 = g->p.x = x;
-		g->t.clipy0 = g->p.y = y;
-		g->t.clipx1 = g->p.x+g->p.cx;
-		g->t.clipy1 = g->p.y+g->p.cy;
-		g->t.color = color;
-		g->t.bgcolor = g->p.color = bgcolor;
-
-		TEST_CLIP_AREA(g) {
-			fillarea(g);
-			mf_render_character(font, x, y, c, fillcharline, g);
-		}
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-
-	void gdispGDrawString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color) {
-		MUTEX_ENTER(g);
-		g->t.font = font;
-		g->t.clipx0 = x;
-		g->t.clipy0 = y;
-		g->t.clipx1 = x + mf_get_string_width(font, str, 0, 0);
-		g->t.clipy1 = y + font->height;
-		g->t.color = color;
-
-		mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, g);
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-
-	void gdispGFillString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) {
-		MUTEX_ENTER(g);
-		g->p.cx = mf_get_string_width(font, str, 0, 0);
-		g->p.cy = font->height;
-		g->t.font = font;
-		g->t.clipx0 = g->p.x = x;
-		g->t.clipy0 = g->p.y = y;
-		g->t.clipx1 = g->p.x+g->p.cx;
-		g->t.clipy1 = g->p.y+g->p.cy;
-		g->t.color = color;
-		g->t.bgcolor = g->p.color = bgcolor;
-
-		TEST_CLIP_AREA(g) {
-			fillarea(g);
-			mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, g);
-		}
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-
-	void gdispGDrawStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) {
-		MUTEX_ENTER(g);
-		g->t.font = font;
-		g->t.clipx0 = x;
-		g->t.clipy0 = y;
-		g->t.clipx1 = x+cx;
-		g->t.clipy1 = y+cy;
-		g->t.color = color;
-
-		/* Select the anchor position */
-		switch(justify) {
-		case justifyCenter:
-			x += (cx + 1) / 2;
-			break;
-		case justifyRight:
-			x += cx;
-			break;
-		default:	// justifyLeft
-			x += font->baseline_x;
-			break;
-		}
-		y += (cy+1 - font->height)/2;
-
-		mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, g);
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-
-	void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) {
-		MUTEX_ENTER(g);
-		g->p.cx = cx;
-		g->p.cy = cy;
-		g->t.font = font;
-		g->t.clipx0 = g->p.x = x;
-		g->t.clipy0 = g->p.y = y;
-		g->t.clipx1 = x+cx;
-		g->t.clipy1 = y+cy;
-		g->t.color = color;
-		g->t.bgcolor = g->p.color = bgcolor;
-
-		TEST_CLIP_AREA(g) {
-
-			// background fill
-			fillarea(g);
-
-			/* Select the anchor position */
-			switch(justify) {
-			case justifyCenter:
-				x += (cx + 1) / 2;
-				break;
-			case justifyRight:
-				x += cx;
-				break;
-			default:	// justifyLeft
-				x += font->baseline_x;
-				break;
-			}
-			y += (cy+1 - font->height)/2;
-
-			/* Render */
-			mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, g);
-		}
-
-		autoflush(g);
-		MUTEX_EXIT(g);
-	}
-
-	coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) {
-		/* No mutex required as we only read static data */
-		switch(metric) {
-		case fontHeight:			return font->height;
-		case fontDescendersHeight:	return font->height - font->baseline_y;
-		case fontLineSpacing:		return font->line_height;
-		case fontCharPadding:		return 0;
-		case fontMinWidth:			return font->min_x_advance;
-		case fontMaxWidth:			return font->max_x_advance;
-		}
-		return 0;
-	}
-
-	coord_t gdispGetCharWidth(char c, font_t font) {
-		/* No mutex required as we only read static data */
-		return mf_character_width(font, c);
-	}
-
-	coord_t gdispGetStringWidth(const char* str, font_t font) {
-		if (!str)
-			return 0;
-
-		/* No mutex required as we only read static data */
-		return mf_get_string_width(font, str, 0, 0);
-	}
-#endif
-
-color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha)
-{
-	uint16_t fg_ratio = alpha + 1;
-	uint16_t bg_ratio = 256 - alpha;
-	uint16_t r, g, b;
-
-	r = RED_OF(fg) * fg_ratio;
-	g = GREEN_OF(fg) * fg_ratio;
-	b = BLUE_OF(fg) * fg_ratio;
-
-	r += RED_OF(bg) * bg_ratio;
-	g += GREEN_OF(bg) * bg_ratio;
-	b += BLUE_OF(bg) * bg_ratio;
-
-	r >>= 8;
-	g >>= 8;
-	b >>= 8;
-
-	return RGB2COLOR(r, g, b);
-}
-
-color_t gdispContrastColor(color_t color) {
-	uint16_t r, g, b;
-
-	r = RED_OF(color) > 128 ? 0 : 255;
-	g = GREEN_OF(color) > 128 ? 0 : 255;
-	b = BLUE_OF(color) > 128 ? 0 : 255;
-
-	return RGB2COLOR(r, g, b);
-}
-
-#if (!defined(gdispPackPixels) && !defined(GDISP_PIXELFORMAT_CUSTOM))
-	void gdispPackPixels(pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color) {
-		/* No mutex required as we only read static data */
-		#if defined(GDISP_PIXELFORMAT_RGB888)
-			#error "GDISP: Packed pixels not supported yet"
-		#elif defined(GDISP_PIXELFORMAT_RGB444)
-			#error "GDISP: Packed pixels not supported yet"
-		#elif defined(GDISP_PIXELFORMAT_RGB666)
-			#error "GDISP: Packed pixels not supported yet"
-		#elif
-			#error "GDISP: Unsupported packed pixel format"
-		#endif
-	}
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
diff --git a/src/gdisp/gdisp_image.c b/src/gdisp/gdisp_image.c
index 2851a7c8..35020634 100644
--- a/src/gdisp/gdisp_image.c
+++ b/src/gdisp/gdisp_image.c
@@ -5,13 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gdisp/gdisp_image.c
- * @brief   GDISP generic image code.
- *
- * @defgroup Image Image
- * @ingroup GDISP
- */
 #include "gfx.h"
 
 #if GFX_USE_GDISP && GDISP_NEED_IMAGE
@@ -230,4 +223,3 @@ void gdispImageFree(gdispImage *img, void *ptr, size_t sz) {
 }
 
 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE */
-/** @} */
diff --git a/src/gdisp/gdisp_image_bmp.c b/src/gdisp/gdisp_image_bmp.c
index d4507ee2..9fc0e13a 100644
--- a/src/gdisp/gdisp_image_bmp.c
+++ b/src/gdisp/gdisp_image_bmp.c
@@ -5,42 +5,10 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gdisp/gdisp_image_bmp.c
- * @brief   GDISP native image code.
- *
- * @defgroup Image Image
- * @ingroup GDISP
- */
 #include "gfx.h"
 
 #if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_BMP
 
-#ifndef GDISP_NEED_IMAGE_BMP_1
-	#define GDISP_NEED_IMAGE_BMP_1		TRUE
-#endif
-#ifndef GDISP_NEED_IMAGE_BMP_4
-	#define GDISP_NEED_IMAGE_BMP_4		TRUE
-#endif
-#ifndef GDISP_NEED_IMAGE_BMP_4_RLE
-	#define GDISP_NEED_IMAGE_BMP_4_RLE	TRUE
-#endif
-#ifndef GDISP_NEED_IMAGE_BMP_8
-	#define GDISP_NEED_IMAGE_BMP_8		TRUE
-#endif
-#ifndef GDISP_NEED_IMAGE_BMP_8_RLE
-	#define GDISP_NEED_IMAGE_BMP_8_RLE	TRUE
-#endif
-#ifndef GDISP_NEED_IMAGE_BMP_16
-	#define GDISP_NEED_IMAGE_BMP_16		TRUE
-#endif
-#ifndef GDISP_NEED_IMAGE_BMP_24
-	#define GDISP_NEED_IMAGE_BMP_24		TRUE
-#endif
-#ifndef GDISP_NEED_IMAGE_BMP_32
-	#define GDISP_NEED_IMAGE_BMP_32		TRUE
-#endif
-
 /**
  * Helper Routines Needed
  */
@@ -901,4 +869,3 @@ delaytime_t gdispImageNext_BMP(gdispImage *img) {
 }
 
 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_BMP */
-/** @} */
diff --git a/src/gdisp/gdisp_image_gif.c b/src/gdisp/gdisp_image_gif.c
index 8ea9beb2..d5c6b3ca 100644
--- a/src/gdisp/gdisp_image_gif.c
+++ b/src/gdisp/gdisp_image_gif.c
@@ -5,13 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gdisp/gdisp_image_gif.c
- * @brief   GDISP native image code.
- *
- * @defgroup Image Image
- * @ingroup GDISP
-*/
 #include "gfx.h"
 
 #if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_GIF
@@ -1205,4 +1198,3 @@ delaytime_t gdispImageNext_GIF(gdispImage *img) {
 }
 
 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_GIF */
-/** @} */
diff --git a/src/gdisp/gdisp_image_jpg.c b/src/gdisp/gdisp_image_jpg.c
index f20884bc..02ec9a8f 100644
--- a/src/gdisp/gdisp_image_jpg.c
+++ b/src/gdisp/gdisp_image_jpg.c
@@ -5,10 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gdisp/gdisp_image_jpg.c
- * @brief   GDISP native image code.
- */
 #include "gfx.h"
 
 #if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_JPG
@@ -16,4 +12,3 @@
 #error "JPG support not implemented yet"
 
 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_JPG */
-/** @} */
diff --git a/src/gdisp/gdisp_image_native.c b/src/gdisp/gdisp_image_native.c
index 21dcb0fc..ec22f386 100644
--- a/src/gdisp/gdisp_image_native.c
+++ b/src/gdisp/gdisp_image_native.c
@@ -5,10 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gdisp/gdisp_image_native.c
- * @brief   GDISP native image code.
- */
 #include "gfx.h"
 
 #if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_NATIVE
@@ -142,4 +138,3 @@ delaytime_t gdispImageNext_NATIVE(gdispImage *img) {
 }
 
 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_NATIVE */
-/** @} */
diff --git a/src/gdisp/gdisp_image_png.c b/src/gdisp/gdisp_image_png.c
index 5d2c1450..6538b2ff 100644
--- a/src/gdisp/gdisp_image_png.c
+++ b/src/gdisp/gdisp_image_png.c
@@ -5,10 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gdisp/gdisp_image_png.c
- * @brief   GDISP native image code.
- */
 #include "gfx.h"
 
 #if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_PNG
@@ -16,4 +12,3 @@
 #error "PNG support not implemented yet"
 
 #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_PNG */
-/** @} */
diff --git a/src/gdisp/gdisp_options.h b/src/gdisp/gdisp_options.h
new file mode 100644
index 00000000..51d759d8
--- /dev/null
+++ b/src/gdisp/gdisp_options.h
@@ -0,0 +1,445 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gdisp/gdisp_options.h
+ * @brief   GDISP sub-system options header file.
+ *
+ * @addtogroup GDISP
+ * @{
+ */
+
+#ifndef _GDISP_OPTIONS_H
+#define _GDISP_OPTIONS_H
+
+/**
+ * @name    GDISP Functionality to be included
+ * @{
+ */
+	/**
+	 * @brief   Should drawing operations be automatically flushed.
+	 * @details	Defaults to FALSE
+	 * @note	If set to FALSE and the controller requires flushing
+	 * 			then the application must manually call @p gdispGFlush().
+	 * 			Setting this to TRUE causes GDISP to automatically flush
+	 * 			after each drawing operation. Note this may be slow but enables
+	 * 			an application to avoid having to manually call the flush routine.
+	 * @note	If TRUE and GDISP_NEED_TIMERFLUSH is also TRUE, this takes precedence.
+	 * @note	Most controllers don't need flushing which is why this is set to
+	 * 			FALSE by default.
+	 */
+	#ifndef GDISP_NEED_AUTOFLUSH
+		#define GDISP_NEED_AUTOFLUSH			FALSE
+	#endif
+	/**
+	 * @brief   Should drawing operations be automatically flushed on a timer.
+	 * @details	Defaults to FALSE, Can be set to FALSE or a timer period in milliseconds.
+	 * @note	The period should not be set too short or it will consume all your CPU. A
+	 * 			value between 250 and 500 milliseconds would probably be suitable.
+	 * @note	If TRUE and GDISP_NEED_AUTOFLUSH is also TRUE, this is ineffective.
+	 * @note	Most controllers don't need flushing which is why this is set to
+	 * 			FALSE by default.
+	 */
+	#ifndef GDISP_NEED_TIMERFLUSH
+		#define GDISP_NEED_TIMERFLUSH			FALSE
+	#endif
+	/**
+	 * @brief   Should all operations be clipped to the screen and colors validated.
+	 * @details	Defaults to TRUE.
+	 * @note    If this is FALSE, any operations that extend beyond the
+	 *          edge of the screen will have undefined results. Any
+	 *			out-of-range colors will produce undefined results.
+	 * @note	This should always be left as the default (TRUE) unless you
+	 * 			are a maniac for speed and you have thoroughly tested your code
+	 * 			and it never overwrites the edges of the screen.
+	 * @note	Setting GDISP_NEED_CLIP to TRUE internally uses the same mechanism
+	 * 			as this validation. There is no advantage in setting this FALSE if
+	 * 			GDISP_NEED_CLIP is TRUE.
+	 */
+	#ifndef GDISP_NEED_VALIDATION
+		#define GDISP_NEED_VALIDATION			TRUE
+	#endif
+	/**
+	 * @brief   Are clipping functions needed.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_CLIP
+		#define GDISP_NEED_CLIP					TRUE
+	#endif
+	/**
+	 * @brief   Streaming functions are needed
+	 * @details	Defaults to FALSE.
+	 */
+	#ifndef GDISP_NEED_STREAMING
+		#define GDISP_NEED_STREAMING			FALSE
+	#endif
+	/**
+	 * @brief   Are text functions needed.
+	 * @details	Defaults to FALSE
+	 * @note	You must also define at least one font.
+	 */
+	#ifndef GDISP_NEED_TEXT
+		#define GDISP_NEED_TEXT					FALSE
+	#endif
+	/**
+	 * @brief   Are circle functions needed.
+	 * @details	Defaults to FALSE
+	 * @note	Uses integer algorithms only. It does not use any trig or floating point.
+	 */
+	#ifndef GDISP_NEED_CIRCLE
+		#define GDISP_NEED_CIRCLE				FALSE
+	#endif
+	/**
+	 * @brief   Are ellipse functions needed.
+	 * @details	Defaults to FALSE
+	 * @note	Uses integer algorithms only. It does not use any trig or floating point.
+	 */
+	#ifndef GDISP_NEED_ELLIPSE
+		#define GDISP_NEED_ELLIPSE				FALSE
+	#endif
+	/**
+	 * @brief   Are arc sector functions needed.
+	 * @details	Defaults to FALSE
+	 * @note	Uses integer algorithms only. It does not use any trig or floating point.
+	 */
+	#ifndef GDISP_NEED_ARCSECTORS
+		#define GDISP_NEED_ARCSECTORS			FALSE
+	#endif
+	/**
+	 * @brief   Are arc functions needed.
+	 * @details	Defaults to FALSE
+	 * @note	This can be compiled using fully integer mathematics by
+	 * 			defining GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG as TRUE.
+	 * @note	This can be compiled to use floating point but no trig functions
+	 * 			by defining GFX_USE_GMISC and GMISC_NEED_FASTTRIG as TRUE.
+	 * @note	If neither of the above are defined it requires the maths library
+	 * 			to be included in the link to provide floating point and trig support.
+	 * 			ie  include -lm in your compiler flags.
+	 */
+	#ifndef GDISP_NEED_ARC
+		#define GDISP_NEED_ARC					FALSE
+	#endif
+	/**
+	 * @brief   Are convex polygon functions needed.
+	 * @details	Defaults to FALSE
+	 * @note	Convex polygons are those that have no internal angles. That is;
+	 * 			you can draw a line from any point on the polygon to any other point
+	 * 			on the polygon without it going outside the polygon.
+	 */
+	#ifndef GDISP_NEED_CONVEX_POLYGON
+		#define GDISP_NEED_CONVEX_POLYGON		FALSE
+	#endif
+	/**
+	 * @brief   Are scrolling functions needed.
+	 * @details	Defaults to FALSE
+	 * @note	This function must be supported by the low level GDISP driver
+	 * 			you have included in your project. If it isn't, defining this
+	 * 			option will cause a compile error.
+	 */
+	#ifndef GDISP_NEED_SCROLL
+		#define GDISP_NEED_SCROLL				FALSE
+	#endif
+	/**
+	 * @brief   Is the capability to read pixels back needed.
+	 * @details	Defaults to FALSE
+	 * @note	This function must be supported by the low level GDISP driver
+	 * 			you have included in your project. If it isn't, defining this
+	 * 			option will cause a compile error.
+	 */
+	#ifndef GDISP_NEED_PIXELREAD
+		#define GDISP_NEED_PIXELREAD			FALSE
+	#endif
+	/**
+	 * @brief   Control some aspect of the hardware operation.
+	 * @details	Defaults to FALSE
+	 * @note	This allows control of hardware specific features such as
+	 * 			screen rotation, backlight levels, contrast etc
+	 */
+	#ifndef GDISP_NEED_CONTROL
+		#define GDISP_NEED_CONTROL				FALSE
+	#endif
+	/**
+	 * @brief   Query some aspect of the hardware operation.
+	 * @details	Defaults to FALSE
+	 * @note	This allows query of hardware specific features
+	 */
+	#ifndef GDISP_NEED_QUERY
+		#define GDISP_NEED_QUERY				FALSE
+	#endif
+	/**
+	 * @brief   Is the image interface required.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_IMAGE
+		#define GDISP_NEED_IMAGE				FALSE
+	#endif
+	/**
+	 * @brief   Is the image interface required.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_PIXMAP
+		#define GDISP_NEED_PIXMAP				FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GDISP Multi-Threading Options
+ * @{
+ */
+	/**
+	 * @brief   Do the drawing functions need to be thread-safe.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_MULTITHREAD
+		#define GDISP_NEED_MULTITHREAD			FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GDISP Optional Parameters
+ * @{
+ */
+	/**
+	 * @brief	Should the startup logo be displayed
+	 *
+	 * @details Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_STARTUP_LOGO
+		#define GDISP_NEED_STARTUP_LOGO 		TRUE
+	#endif
+	/**
+	 * @brief	Define the initial background color for all displays in the system.
+	 */
+	#ifndef GDISP_STARTUP_COLOR
+		#define GDISP_STARTUP_COLOR				Black
+	#endif
+	/**
+	 * @brief	Define the default orientation for all displays in the system.
+	 * @note	GDISP_NEED_CONTROL must also be set (and the hardware must support it)
+	 * @note	If not specified then displays default to the native hardware orientation
+	 */
+	// #define GDISP_DEFAULT_ORIENTATION		GDISP_ROTATE_LANDSCAPE
+	/**
+	 * @brief   The size of pixel buffer (in pixels) used for optimization.
+	 * @details	Set to zero to guarantee disabling of the buffer.
+	 * @note	Depending on the driver and what operations the application
+	 * 			needs, this buffer may never be allocated.
+	 * @note	Setting the size to zero may cause some operations to not
+	 * 			compile eg. Scrolling if there is no hardware scroll support.
+	 * @note	Increasing the size will speedup certain operations
+	 * 			at the expense of RAM.
+	 * @note	Currently only used to support scrolling on hardware without
+	 * 			scrolling support, and to increase the speed of streaming
+	 * 			operations on non-streaming hardware where there is a
+	 * 			hardware supported bit-blit.
+	 */
+	#ifndef GDISP_LINEBUF_SIZE
+		#define GDISP_LINEBUF_SIZE				128
+	#endif
+/**
+ * @}
+ *
+ * @name    GDISP Multiple Display Support
+ * @{
+ */
+	/**
+	 * @brief   The total number of displays using the default driver.
+	 * @note	If you want to use multiple displays either set GDISP_TOTAL_DISPLAYS or GDISP_DRIVER_LIST
+	 *          but not both.
+	 */
+	#ifndef GDISP_TOTAL_DISPLAYS
+		#define GDISP_TOTAL_DISPLAYS		1
+	#endif
+	#if defined(__DOXYGEN__)
+		/**
+		 * @brief   The list of display drivers.
+		 * @note	Replace this example with your own definition in your gfxconf.h file. See the gdisp_lld.c
+		 *          in each driver (near the top) to get the name of the VMT for a driver.
+		 * @note    The same driver can occur more than once in the list to create an extra instance of that driver.
+		 * @note    If defining this you must also define GDISP_PIXELFORMAT for your application to use.
+         *          Choose a value that is most common accross all your drivers for efficiency.
+         * @note    If using this you may optionally define the GDISP_HARDWARE_xxx values as either TRUE or FALSE.
+         *          Doing this causes GDISP to assume that all (TRUE) or none (FALSE) of the listed drivers have that
+         *          capability. This can help improve drawing speed and efficiency.
+		 */
+		#define GDISP_DRIVER_LIST		  GDISPVMT_Win32, GDISPVMT_SSD1963
+	#endif
+/**
+ * @}
+ *
+ * @name    GDISP Image Options
+ * @pre		GDISP_NEED_IMAGE must be TRUE
+ * @{
+ */
+	/**
+	 * @brief   Is native image decoding required.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_IMAGE_NATIVE
+		#define GDISP_NEED_IMAGE_NATIVE			FALSE
+	#endif
+	/**
+	 * @brief   Is GIF image decoding required.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_IMAGE_GIF
+		#define GDISP_NEED_IMAGE_GIF			FALSE
+	#endif
+	/**
+	 * @brief   Is BMP image decoding required.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP
+		#define GDISP_NEED_IMAGE_BMP			FALSE
+	#endif
+	/**
+	 * @brief   Is JPG image decoding required.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_IMAGE_JPG
+		#define GDISP_NEED_IMAGE_JPG			FALSE
+	#endif
+	/**
+	 * @brief   Is PNG image decoding required.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_IMAGE_PNG
+		#define GDISP_NEED_IMAGE_PNG			FALSE
+	#endif
+	/**
+	 * @brief   Is memory accounting required during image decoding.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_IMAGE_ACCOUNTING
+		#define GDISP_NEED_IMAGE_ACCOUNTING		FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GDISP BMP Image Options
+ * @pre		GDISP_NEED_IMAGE and GDISP_NEED_IMAGE_BMP must be TRUE
+ * @{
+ */
+	/**
+	 * @brief   Is BMP 1 bit per pixel (monochrome/2 color) image decoding required.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP_1
+		#define GDISP_NEED_IMAGE_BMP_1		TRUE
+	#endif
+	/**
+	 * @brief   Is BMP 4 bits per pixel (16 color) image decoding required.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP_4
+		#define GDISP_NEED_IMAGE_BMP_4		TRUE
+	#endif
+	/**
+	 * @brief   Is BMP 4 bits per pixel (16 color) with RLE compression image decoding required.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP_4_RLE
+		#define GDISP_NEED_IMAGE_BMP_4_RLE	TRUE
+	#endif
+	/**
+	 * @brief   Is BMP 8 bits per pixel (256 color) image decoding required.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP_8
+		#define GDISP_NEED_IMAGE_BMP_8		TRUE
+	#endif
+	/**
+	 * @brief   Is BMP 8 bits per pixel (256 color) with RLE compression image decoding required.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP_8_RLE
+		#define GDISP_NEED_IMAGE_BMP_8_RLE	TRUE
+	#endif
+	/**
+	 * @brief   Is BMP 16 bits per pixel (65536 color) image decoding required.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP_16
+		#define GDISP_NEED_IMAGE_BMP_16		TRUE
+	#endif
+	/**
+	 * @brief   Is BMP 24 bits per pixel (true-color) image decoding required.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP_24
+		#define GDISP_NEED_IMAGE_BMP_24		TRUE
+	#endif
+	/**
+	 * @brief   Is BMP 32 bits per pixel (true-color) image decoding required.
+	 * @details	Defaults to TRUE
+	 */
+	#ifndef GDISP_NEED_IMAGE_BMP_32
+		#define GDISP_NEED_IMAGE_BMP_32		TRUE
+	#endif
+/**
+ * @}
+ *
+ * @name	GDISP Text Rendering Options
+ * @{
+ */
+	/**
+	 * @brief	Enable UTF-8 support for text rendering.
+	 * @details Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_UTF8
+		#define GDISP_NEED_UTF8					FALSE
+	#endif
+	/**
+	 * @brief	Enable kerning for font rendering (improves character placement).
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_TEXT_KERNING
+		#define GDISP_NEED_TEXT_KERNING			FALSE
+	#endif
+	/**
+	 * @brief	Enable antialiased font support
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GDISP_NEED_ANTIALIAS
+		#define GDISP_NEED_ANTIALIAS			FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name	GDISP Pixmap Options
+ * @{
+ */
+	#ifndef GDISP_NEED_PIXMAP_IMAGE
+		#define GDISP_NEED_PIXMAP_IMAGE			FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GDISP Optional Low Level Driver Defines
+ * @{
+ */
+	/**
+	 * @brief   Set the screen height and width.
+	 * @note	Ignored by some low level GDISP drivers, optional for others.
+	 * @note	Where these values are allowed, a default is always provided be the low level driver.
+	 * @note	The list of GDISP low level drivers that allow these to be set are...
+	 *				WIN32, SSD1289, SSD1963, TestStub
+	 */
+	/* #define GDISP_SCREEN_WIDTH		nnnn */
+	/* #define GDISP_SCREEN_HEIGHT		nnnn */
+	/**
+	 * @brief   Define which bus interface to use.
+	 * @details	Only required by the SSD1963 driver.
+	 * @note	This will be replaced eventually by board definition files
+	 */
+	// #define GDISP_USE_FSMC
+	// #define GDISP_USE_GPIO
+/** @} */
+
+#endif /* _GDISP_OPTIONS_H */
+/** @} */
+
diff --git a/src/gdisp/gdisp_pixmap.c b/src/gdisp/gdisp_pixmap.c
index d088a57b..b6226289 100644
--- a/src/gdisp/gdisp_pixmap.c
+++ b/src/gdisp/gdisp_pixmap.c
@@ -39,8 +39,8 @@
 	#error "GDISP Pixmap: Pixmap's do not currently support the specified GDISP_LLD_PIXELFORMAT"
 #endif
 
-#include "src/gdisp/driver.h"
-#include "src/gdriver/sys_defs.h"
+#include "src/gdisp/gdisp_driver.h"
+#include "src/gdriver/gdriver.h"
 
 typedef struct pixmap {
 	#if GDISP_NEED_PIXMAP_IMAGE
diff --git a/src/gdisp/gdisp_rules.h b/src/gdisp/gdisp_rules.h
new file mode 100644
index 00000000..3e5051e5
--- /dev/null
+++ b/src/gdisp/gdisp_rules.h
@@ -0,0 +1,89 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gdisp/gdisp_rules.h
+ * @brief   GDISP safety rules header file.
+ *
+ * @addtogroup GDISP
+ * @{
+ */
+
+#ifndef _GDISP_RULES_H
+#define _GDISP_RULES_H
+
+#if GFX_USE_GDISP
+	#if !GFX_USE_GDRIVER
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GDISP: GFX_USE_GDRIVER is required. GFX_USE_GDRIVER has turned on for you."
+		#endif
+		#undef GFX_USE_GDRIVER
+		#define GFX_USE_GDRIVER				TRUE
+	#endif
+	#if defined(GDISP_DRIVER_LIST)
+        #if GDISP_TOTAL_DISPLAYS != 1
+            #error "GDISP Multiple Drivers: You can't specify both GDISP_TOTAL_DISPLAYS and GDISP_DRIVER_LIST"
+        #endif
+		#ifndef GDISP_PIXELFORMAT
+			#error "GDISP Multiple Drivers: You must specify a value for GDISP_PIXELFORMAT when using GDISP_DRIVER_LIST"
+		#endif
+	#endif
+	#if GDISP_NEED_AUTOFLUSH && GDISP_NEED_TIMERFLUSH
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GDISP: Both GDISP_NEED_AUTOFLUSH and GDISP_NEED_TIMERFLUSH has been set. GDISP_NEED_TIMERFLUSH has disabled for you."
+		#endif
+		#undef GDISP_NEED_TIMERFLUSH
+		#define GDISP_NEED_TIMERFLUSH		FALSE
+	#endif
+	#if GDISP_NEED_TIMERFLUSH
+		#if GDISP_NEED_TIMERFLUSH < 50 || GDISP_NEED_TIMERFLUSH > 1200
+			#error "GDISP: GDISP_NEED_TIMERFLUSH has been set to an invalid value (FALSE, 50-1200)."
+		#endif
+		#if !GFX_USE_GTIMER
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GDISP: GDISP_NEED_TIMERFLUSH has been set but GFX_USE_GTIMER has not been set. It has been turned on for you."
+			#endif
+			#undef GFX_USE_GTIMER
+			#define GFX_USE_GTIMER				TRUE
+			#undef GDISP_NEED_MULTITHREAD
+			#define GDISP_NEED_MULTITHREAD		TRUE
+		#endif
+	#endif
+	#if GDISP_NEED_ANTIALIAS && !GDISP_NEED_PIXELREAD
+		#if GDISP_HARDWARE_PIXELREAD
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GDISP: GDISP_NEED_ANTIALIAS has been set but GDISP_NEED_PIXELREAD has not. It has been turned on for you."
+			#endif
+			#undef GDISP_NEED_PIXELREAD
+			#define GDISP_NEED_PIXELREAD	TRUE
+		#else
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GDISP: GDISP_NEED_ANTIALIAS has been set but your hardware does not support reading back pixels. Anti-aliasing will only occur for filled characters."
+			#endif
+		#endif
+	#endif
+	#if (defined(GDISP_INCLUDE_FONT_SMALL) && GDISP_INCLUDE_FONT_SMALL) || (defined(GDISP_INCLUDE_FONT_LARGER) && GDISP_INCLUDE_FONT_LARGER)
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GDISP: An old font (Small or Larger) has been defined. A single default font of UI2 has been added instead."
+			#warning "GDISP: Please see <$(GFXLIB)/include/gdisp/fonts/fonts.h> for a list of available font names."
+		#endif
+		#undef GDISP_INCLUDE_FONT_UI2
+		#define GDISP_INCLUDE_FONT_UI2		TRUE
+	#endif
+	#if GDISP_NEED_IMAGE
+		#if !GFX_USE_GFILE
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GDISP: GFX_USE_GFILE is required when GDISP_NEED_IMAGE is TRUE. It has been turned on for you."
+			#endif
+			#undef GFX_USE_GFILE
+			#define GFX_USE_GFILE	TRUE
+		#endif
+	#endif
+#endif
+
+#endif /* _GDISP_RULES_H */
+/** @} */
diff --git a/src/gdisp/sys_defs.h b/src/gdisp/sys_defs.h
deleted file mode 100644
index 6b77bab8..00000000
--- a/src/gdisp/sys_defs.h
+++ /dev/null
@@ -1,1124 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gdisp/sys_defs.h
- * @brief   GDISP Graphic Driver subsystem header file.
- *
- * @addtogroup GDISP
- *
- * @brief		Module to interface graphic / pixel oriented displays
- *
- * @details		The GDISP module provides high level abstraction to interface pixel oriented graphic displays.
- *
- * @pre			GFX_USE_GDISP must be set to TRUE in gfxconf.h
- *
- * @note		Each drawing routine supports a gdispXXXX and a gdispGXXXX function. The difference is that the
- * 				gdispXXXX function does not require a display to be specified. Note there is a slight anomaly
- * 				in the naming with gdispGBlitArea() vs gdispBlitAreaEx() and gdispBlitArea(), the latter of
- * 				which is now deprecated.
- * @{
- */
-
-#ifndef _GDISP_H
-#define _GDISP_H
-
-#include "gfx.h"
-
-/* This type definition is defined here as it gets used in other gfx sub-systems even
- * if GFX_USE_GDISP is FALSE.
- */
-
-/**
- * @brief   The type for a coordinate or length on the screen.
- */
-typedef int16_t	coord_t;
-
-#if GFX_USE_GDISP || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-/**
- * @brief   Type for a 2D point on the screen.
- */
-typedef struct point { coord_t x, y; } point, point_t;
-/**
- * @brief   Type for the text justification.
- */
-typedef enum justify { justifyLeft=0, justifyCenter=1, justifyRight=2 } justify_t;
-/**
- * @brief   Type for the font metric.
- */
-typedef enum fontmetric { fontHeight, fontDescendersHeight, fontLineSpacing, fontCharPadding, fontMinWidth, fontMaxWidth } fontmetric_t;
-/**
- * @brief   The type of a font.
- */
-typedef const struct mf_font_s* font_t;
-/**
- * @brief   Type for the screen orientation.
- * @note	GDISP_ROTATE_LANDSCAPE and GDISP_ROTATE_PORTRAIT are internally converted to the
- * 			most appropriate other orientation.
- */
-typedef enum orientation { GDISP_ROTATE_0=0, GDISP_ROTATE_90=90, GDISP_ROTATE_180=180, GDISP_ROTATE_270=270, GDISP_ROTATE_PORTRAIT=1000,  GDISP_ROTATE_LANDSCAPE=1001 } orientation_t;
-/**
- * @brief   Type for the available power modes for the screen.
- */
-typedef enum powermode { powerOff, powerSleep, powerDeepSleep, powerOn } powermode_t;
-
-/*
- * Our black box display structure.
- */
-typedef struct GDisplay		GDisplay;
-
-/**
- * @brief   The default screen to use for the gdispXXXX calls.
- * @note	This is set by default to the first display in the system. You can change
- * 			it by calling @p gdispGSetDisplay().
- */
-extern GDisplay	*GDISP;
-
-/*===========================================================================*/
-/* Constants.                                                                */
-/*===========================================================================*/
-
-/**
- * @brief   Driver Control Constants
- * @details	Unsupported control codes are ignored.
- * @note	The value parameter should always be typecast to (void *).
- * @note	There are some predefined and some specific to the low level driver.
- * @note	GDISP_CONTROL_POWER			- Takes a gdisp_powermode_t
- * 			GDISP_CONTROL_ORIENTATION	- Takes a gdisp_orientation_t
- * 			GDISP_CONTROL_BACKLIGHT -	 Takes an int from 0 to 100. For a driver
- * 											that only supports off/on anything other
- * 											than zero is on.
- * 			GDISP_CONTROL_CONTRAST		- Takes an int from 0 to 100.
- * 			GDISP_CONTROL_LLD			- Low level driver control constants start at
- * 											this value.
- */
-#define GDISP_CONTROL_POWER			0
-#define GDISP_CONTROL_ORIENTATION	1
-#define GDISP_CONTROL_BACKLIGHT		2
-#define GDISP_CONTROL_CONTRAST		3
-#define GDISP_CONTROL_LLD			1000
-
-/*===========================================================================*/
-/* Defines relating to the display hardware									 */
-/*===========================================================================*/
-
-#if !defined(GDISP_DRIVER_LIST)
-	// Pull in the default hardware configuration for a single controller.
-	// If we have multiple controllers the settings must be set in the
-	// users gfxconf.h file.
-	#include "gdisp_lld_config.h"
-
-	// Unless the user has specified a specific pixel format, use
-	// the native format for the controller.
-	#if !defined(GDISP_PIXELFORMAT) && defined(GDISP_LLD_PIXELFORMAT)
-		#define GDISP_PIXELFORMAT 			GDISP_LLD_PIXELFORMAT
-	#endif
-#endif
-
-/**
- * @name    GDISP pixel format choices
- * @{
- */
-	/**
-	 * @brief   The pixel format.
-	 * @details	It generally defaults to the hardware pixel format.
-	 * @note	This doesn't need to match the hardware pixel format.
-	 * 			It is definitely more efficient when it does.
-	 * @note	When GDISP_DRIVER_LIST is defined, this must
-	 * 			be explicitly defined and you should ensure the best match
-	 * 			with your hardware across all devices.
-	 */
-	#ifndef GDISP_PIXELFORMAT
-		#define GDISP_PIXELFORMAT 			GDISP_PIXELFORMAT_ERROR
-	#endif
-	/**
-	 * @brief   Do pixels require packing for a blit
-	 * @note	Is only valid for a pixel format that doesn't fill it's datatype. eg formats:
-	 *				GDISP_PIXELFORMAT_RGB888
-	 *				GDISP_PIXELFORMAT_RGB444
-	 *				GDISP_PIXELFORMAT_RGB666
-	 *				GDISP_PIXELFORMAT_CUSTOM
-	 * @note	Very few cases should actually require packed pixels as the low
-	 *				level driver can also pack on the fly as it is sending it
-	 *				to the graphics device.
-	 * @note	Packed pixels are not really supported at this point.
-	 */
-	#ifndef GDISP_PACKED_PIXELS
-		#define GDISP_PACKED_PIXELS			FALSE
-	#endif
-
-	/**
-	 * @brief   Do lines of pixels require packing for a blit
-	 * @note	Ignored if GDISP_PACKED_PIXELS is FALSE
-	 */
-	#ifndef GDISP_PACKED_LINES
-		#define GDISP_PACKED_LINES			FALSE
-	#endif
-/** @} */
-
-/*===========================================================================*/
-/* Defines related to the pixel format										 */
-/*===========================================================================*/
-
-/* Load our color definitions and pixel formats */
-#include "gdisp_colors.h"
-
-/**
- * @brief   The type of a pixel.
- */
-typedef color_t		pixel_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Color Utility Functions */
-
-/**
- * @brief   Blend 2 colors according to the alpha
- * @return	The combined color
- *
- * @param[in] fg		The foreground color
- * @param[in] bg		The background color
- * @param[in] alpha		The alpha value (0-255). 0 is all background, 255 is all foreground.
- *
- * @api
- */
-color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha);
-
-/**
- * @brief   Find a contrasting color
- * @return	The contrasting color
- *
- * @param[in] color		The color to contrast
- *
- * @api
- */
-color_t gdispContrastColor(color_t color);
-
-/* Base Functions */
-
-/**
- * @brief   Get the specified display
- * @return	The pointer to the display or NULL if the display doesn't exist
- * @note	The GDISP variable contains the display used by the gdispXxxx routines
- * 			as opposed to the gdispGXxxx routines which take an explicit display
- * 			parameter.
- * @note	Displays are numbered from 0 to @p gdispGetDisplayCount() - 1
- *
- * @param[in] display	The display number (0..n)
- *
- * @api
- */
-GDisplay *gdispGetDisplay(unsigned display);
-
-/**
- * @brief   Set the current default display to the specified display
- * @note	The default display is used for the gdispXxxx functions.
- * @note	The default display is contained in the variable GDISP. Using
- * 			this function to set it protects against it being set to a NULL
- * 			value.
- * @note	If a NULL is passed for the dispay this call is ignored.
- *
- * @param[in] g 	The display to use
- *
- * @api
- */
-void gdispSetDisplay(GDisplay *g);
-
-/**
- * @brief   Get the count of currently active displays
- * @return  The count of displays currently in the system
- *
- * @note	Displays are numbered from 0 to @p gdispGetDisplayCount() - 1
- */
-unsigned gdispGetDisplayCount(void);
-
-/* Property Functions */
-
-/**
- * @brief   Get the display width in pixels.
- *
- * @param[in] g 		The display to use
- *
- * @return	The width of the display
- *
- * @api
- */
-coord_t gdispGGetWidth(GDisplay *g);
-#define gdispGetWidth()								gdispGGetWidth(GDISP)
-
-/**
- * @brief   Get the display height in pixels.
- *
- * @param[in] g 		The display to use
- *
- * @return	The height of the display
- *
- * @api
- */
-coord_t gdispGGetHeight(GDisplay *g);
-#define gdispGetHeight()							gdispGGetHeight(GDISP)
-
-/**
- * @brief   Get the current display power mode.
- *
- * @param[in] g 		The display to use
- *
- * @return	The current power mode
- *
- * @api
- */
-powermode_t gdispGGetPowerMode(GDisplay *g);
-#define gdispGetPowerMode()							gdispGGetPowerMode(GDISP)
-
-/**
- * @brief   Get the current display orientation.
- *
- * @param[in] g 		The display to use
- *
- * @return	The current orientation
- *
- * @api
- */
-orientation_t gdispGGetOrientation(GDisplay *g);
-#define gdispGetOrientation()						gdispGGetOrientation(GDISP)
-
-/**
- * @brief   Get the current display backlight brightness.
- *
- * @param[in] g 		The display to use
- *
- * @return	The current backlight value
- *
- * @api
- */
-uint8_t gdispGGetBacklight(GDisplay *g);
-#define gdispGetBacklight()							gdispGGetBacklight(GDISP)
-
-/**
- * @brief   Get the current display contrast.
- *
- * @param[in] g 		The display to use
- *
- * @return	The current contrast value
- *
- * @api
- */
-uint8_t gdispGGetContrast(GDisplay *g);
-#define gdispGetContrast()							gdispGGetContrast(GDISP)
-
-/* Drawing Functions */
-
-/**
- * @brief   Flush current drawing operations to the display
- * @note	Some low level drivers do not update the display until
- * 			the display is flushed. For others it is optional but can
- * 			help prevent tearing effects. For some it is ignored.
- * 			Calling it at the end of a logic set of drawing operations
- * 			in your application will ensure controller portability. If you
- * 			know your controller does not need to be flushed there is no
- * 			need to call it (which is in reality most controllers).
- * @note	Even for displays that require flushing, there is no need to
- * 			call this function if GDISP_NEED_AUTOFLUSH is TRUE.
- * 			Calling it again won't hurt though.
- *
- *
- * @param[in] g 	The display to use
- *
- * @api
- */
-void gdispGFlush(GDisplay *g);
-#define gdispFlush()									gdispGFlush(GDISP)
-
-/**
- * @brief   Clear the display to the specified color.
- *
- * @param[in] g 	The display to use
- * @param[in] color The color to use when clearing the screen
- *
- * @api
- */
-void gdispGClear(GDisplay *g, color_t color);
-#define gdispClear(c)									gdispGClear(GDISP, c)
-
-/**
- * @brief   Set a pixel in the specified color.
- *
- * @param[in] g 	The display to use
- * @param[in] x,y   The position to set the pixel.
- * @param[in] color The color to use
- *
- * @api
- */
-void gdispGDrawPixel(GDisplay *g, coord_t x, coord_t y, color_t color);
-#define gdispDrawPixel(x,y,c)							gdispGDrawPixel(GDISP,x,y,c)
-
-/**
- * @brief   Draw a line.
- *
- * @param[in] g 	The display to use
- * @param[in] x0,y0		The start position
- * @param[in] x1,y1 	The end position
- * @param[in] color		The color to use
- *
- * @api
- */
-void gdispGDrawLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
-#define gdispDrawLine(x0,y0,x1,y1,c)					gdispGDrawLine(GDISP,x0,y0,x1,y1,c)
-
-/**
- * @brief   Fill an area with a color.
- *
- * @param[in] g 		The display to use
- * @param[in] x,y		The start position
- * @param[in] cx,cy		The size of the box (outside dimensions)
- * @param[in] color		The color to use
- *
- * @api
- */
-void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
-#define gdispFillArea(x,y,cx,cy,c)						gdispGFillArea(GDISP,x,y,cx,cy,c)
-
-/**
- * @brief   Fill an area using the supplied bitmap.
- * @details The bitmap is in the pixel format specified by the low level driver
- * @note	If a packed pixel format is used and the width doesn't
- *			match a whole number of bytes, the next line will start on a
- *			non-byte boundary (no end-of-line padding).
- * @note	If GDISP_NEED_ASYNC is defined then the buffer must be static
- * 			or at least retained until this call has finished the blit. You can
- * 			tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE.
- *
- * @param[in] g 		The display to use
- * @param[in] x,y		The start position
- * @param[in] cx,cy		The size of the filled area
- * @param[in] srcx,srcy The bitmap position to start the fill form
- * @param[in] srccx		The width of a line in the bitmap
- * @param[in] buffer	The bitmap in the driver's pixel format
- *
- * @api
- */
-void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer);
-#define gdispBlitAreaEx(x,y,cx,cy,sx,sy,rx,b)			gdispGBlitArea(GDISP,x,y,cx,cy,sx,sy,rx,b)
-
-/**
- * @brief   Draw a rectangular box.
- *
- * @param[in] g 		The display to use
- * @param[in] x,y		The start position
- * @param[in] cx,cy		The size of the box (outside dimensions)
- * @param[in] color		The color to use
- *
- * @api
- */
-void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
-#define gdispDrawBox(x,y,cx,cy,c)						gdispGDrawBox(GDISP,x,y,cx,cy,c)
-
-/* Streaming Functions */
-
-#if GDISP_NEED_STREAMING || defined(__DOXYGEN__)
-	/**
-	 * @brief   Start a streaming operation.
-	 * @details Stream data to a window on the display sequentially and very fast.
-	 * @pre		GDISP_NEED_STREAMING must be TRUE in your gfxconf.h
-	 * @note	While streaming is in operation - no other calls to GDISP functions
-	 * 			can be made (with the exception of @p gdispBlendColor() and streaming
-	 * 			functions). If a call is made (eg in a multi-threaded application) the other
-	 * 			call is blocked waiting for the streaming operation to finish.
-	 * @note	@p gdispStreamStop() must be called to finish the streaming operation.
-	 * @note	If more data is written than the defined area then the results are unspecified.
-	 * 			Some drivers may wrap back to the beginning of the area, others may just
-	 * 			ignore subsequent data.
-	 * @note	Unlike most operations that clip the defined area to the display to generate
-	 * 			a smaller active area, this call will just silently fail if any of the stream
-	 * 			region lies outside the current clipping area.
-	 * @note	A streaming operation may be terminated early (without writing to every location
-	 * 			in the stream area) by calling @p gdispStreamStop().
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The start position
-	 * @param[in] cx,cy		The size of the streamable area
-	 *
-	 * @api
-	 */
-	void gdispGStreamStart(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy);
-	#define gdispStreamStart(x,y,cx,cy)						gdispGStreamStart(GDISP,x,y,cx,cy)
-
-	/**
-	 * @brief   Send pixel data to the stream.
-	 * @details Write a pixel to the next position in the streamed area and increment the position
-	 * @pre		GDISP_NEED_STREAMING must be TRUE in your gfxconf.h
-	 * @pre		@p gdispStreamStart() has been called.
-	 * @note	If the gdispStreamStart() has not been called (or failed due to clipping), the
-	 * 			data provided here is simply thrown away.
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] color		The color of the pixel to write
-	 *
-	 * @api
-	 */
-	void gdispGStreamColor(GDisplay *g, color_t color);
-	#define gdispStreamColor(c)								gdispGStreamColor(GDISP,c)
-
-	/**
-	 * @brief   Finish the current streaming operation.
-	 * @details	Completes the current streaming operation and allows other GDISP calls to operate again.
-	 * @pre		GDISP_NEED_STREAMING must be TRUE in your gfxconf.h
-	 * @pre		@p gdispStreamStart() has been called.
-	 * @note	If the gdispStreamStart() has not been called (or failed due to clipping), this
-	 * 			call is simply ignored.
-	 *
-	 * @param[in] g 		The display to use
-	 *
-	 * @api
-	 */
-	void gdispGStreamStop(GDisplay *g);
-	#define gdispStreamStop()								gdispGStreamStop(GDISP)
-#endif
-
-/* Clipping Functions */
-
-#if GDISP_NEED_CLIP || defined(__DOXYGEN__)
-	/**
-	 * @brief   Clip all drawing to the defined area.
-	 * @pre		GDISP_NEED_CLIP must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The start position
-	 * @param[in] cx,cy		The size of the clip area
-	 *
-	 * @api
-	 */
-	void gdispGSetClip(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy);
-	#define gdispSetClip(x,y,cx,cy)							gdispGSetClip(GDISP,x,y,cx,cy)
-#endif
-
-/* Circle Functions */
-
-#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__)
-	/**
-	 * @brief   Draw a circle.
-	 * @pre		GDISP_NEED_CIRCLE must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The center of the circle
-	 * @param[in] radius	The radius of the circle
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGDrawCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color);
-	#define gdispDrawCircle(x,y,r,c)						gdispGDrawCircle(GDISP,x,y,r,c)
-
-	/**
-	 * @brief   Draw a filled circle.
-	 * @pre		GDISP_NEED_CIRCLE must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The center of the circle
-	 * @param[in] radius	The radius of the circle
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGFillCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color);
-	#define gdispFillCircle(x,y,r,c)						gdispGFillCircle(GDISP,x,y,r,c)
-#endif
-
-/* Ellipse Functions */
-
-#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__)
-	/**
-	 * @brief   Draw an ellipse.
-	 * @pre		GDISP_NEED_ELLIPSE must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The center of the ellipse
-	 * @param[in] a,b		The dimensions of the ellipse
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGDrawEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
-	#define gdispDrawEllipse(x,y,a,b,c)						gdispGDrawEllipse(GDISP,x,y,a,b,c)
-
-	/**
-	 * @brief   Draw a filled ellipse.
-	 * @pre		GDISP_NEED_ELLIPSE must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The center of the ellipse
-	 * @param[in] a,b		The dimensions of the ellipse
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGFillEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
-	#define gdispFillEllipse(x,y,a,b,c)						gdispGFillEllipse(GDISP,x,y,a,b,c)
-#endif
-
-/* Arc Functions */
-#if GDISP_NEED_ARCSECTORS || defined(__DOXYGEN__)
-	/**
-	 * @brief	Draw a selection of 45 degree arcs of a circle
-	 * @pre		GDISP_NEED_ARCSECTORS must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The center of the circle
-	 * @param[in] radius	The radius of the circle
-	 * @param[in] sectors	Bits determine which sectors are drawn.
-	 * 						Bits go anti-clockwise from the 0 degree mark (y = 0, x is positive), as follows:
-	 *  						bit 0 - upper right right		  -----
-	 *  						bit 1 - upper upper right		 /2   1\
-	 *  						bit 2 - upper upper left		/3     0\
-	 *  						bit 3 - upper left  left		\4     7/
-	 *  						bit 4 - lower left  left		 \5   6/
-	 *  						bit 5 - lower lower left		  -----
-	 *  						bit 6 - lower lower right
-	 *  						bit 7 - lower left  left
-	 * @param[in] color		The color to use
-	 *
-	 * @note	This is a more limited versions of the general arc drawing routine. It
-	 * 			doesn't require trig libraries or tables or floating point and is smaller in code size.
-	 * 			There is probably little point in including both this and the general
-	 * 			arc routine as the general arc routine can do everything this can do.
-	 *
-	 * @api
-	 */
-	void gdispGDrawArcSectors(GDisplay *g, coord_t x, coord_t y, coord_t radius, uint8_t sectors, color_t color);
-	#define gdispDrawArcSectors(x,y,r,s,c)						gdispGDrawArcSectors(GDISP,x,y,r,s,c)
-
-	/**
-	 * @brief	Fill a selection of 45 degree arcs of a circle
-	 * @pre		GDISP_NEED_ARCSECTORS must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The center of the circle
-	 * @param[in] radius	The radius of the circle
-	 * @param[in] sectors	Bits determine which sectors are drawn.
-	 * 						Bits go anti-clockwise from the 0 degree mark (y = 0, x is positive), as follows:
-	 *  						bit 0 - upper right right		  -----
-	 *  						bit 1 - upper upper right		 /2   1\
-	 *  						bit 2 - upper upper left		/3     0\
-	 *  						bit 3 - upper left  left		\4     7/
-	 *  						bit 4 - lower left  left		 \5   6/
-	 *  						bit 5 - lower lower left		  -----
-	 *  						bit 6 - lower lower right
-	 *  						bit 7 - lower left  left
-	 * @param[in] color		The color to use
-	 *
-	 * @note	This is a more limited versions of the general arc filling routine. It
-	 * 			doesn't require trig libraries or tables or floating point and is smaller in code size.
-	 * 			There is probably little point in including both this and the general
-	 * 			arc routine as the general arc routine can do everything this can do.
-	 *
-	 * @api
-	 */
-	void gdispGFillArcSectors(GDisplay *g, coord_t x, coord_t y, coord_t radius, uint8_t sectors, color_t color);
-	#define gdispFillArcSectors(x,y,r,s,c)						gdispGFillArcSectors(GDISP,x,y,r,s,c)
-#endif
-
-#if GDISP_NEED_ARC || defined(__DOXYGEN__)
-	/*
-	 * @brief	Draw an arc.
-	 * @pre		GDISP_NEED_ARC must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x0,y0		The center point
-	 * @param[in] radius	The radius of the arc
-	 * @param[in] start		The start angle (0 to 360)
-	 * @param[in] end		The end angle (0 to 360)
-	 * @param[in] color		The color of the arc
-	 *
-	 * @note		If you are just doing 45 degree angles consider using @p gdispDrawArcSectors() instead.
-	 * @note		This routine requires trig support. It can either come from your C runtime library
-	 * 				cos() and sin() which requires floating point support (and is slow), or you can define GFX_USE_GMISC
-	 * 				and either GMISC_NEED_FIXEDTRIG or GMISC_NEED_FASTTRIG.
-	 * 				GMISC_NEED_FASTTRIG uses table based floating point trig operations.
-	 * 				GMISC_NEED_FIXEDTRIG uses fixed point integer trig operations.
-	 * 				Note accuracy on both the table based options are more than adequate for the one degree
-	 * 				resolution provided by these arc routines. Both are much faster than your C runtime library.
-	 *
-	 * @api
-	 */
-	void gdispGDrawArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
-	#define gdispDrawArc(x,y,r,s,e,c)						gdispGDrawArc(GDISP,x,y,r,s,e,c)
-
-	/*
-	 * @brief	Draw a filled arc.
-	 * @pre		GDISP_NEED_ARC must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x0,y0		The center point
-	 * @param[in] radius	The radius of the arc
-	 * @param[in] start		The start angle (0 to 360)
-	 * @param[in] end		The end angle (0 to 360)
-	 * @param[in] color		The color of the arc
-	 *
-	 * @note		If you are just doing 45 degree angles consider using @p gdispFillArcSectors() instead.
-	 * @note		This routine requires trig support. It can either come from your C runtime library
-	 * 				cos() and sin() which requires floating point support (and is slow), or you can define GFX_USE_GMISC
-	 * 				and either GMISC_NEED_FIXEDTRIG or GMISC_NEED_FASTTRIG.
-	 * 				GMISC_NEED_FASTTRIG uses table based floating point trig operations.
-	 * 				GMISC_NEED_FIXEDTRIG uses fixed point integer trig operations.
-	 * 				Note accuracy on both the table based options are more than adequate for the one degree
-	 * 				resolution provided by these arc routines. Both are much faster than your C runtime library.
-	 *
-	 * @api
-	 */
-	void gdispGFillArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
-	#define gdispFillArc(x,y,r,s,e,c)						gdispGFillArc(GDISP,x,y,r,s,e,c)
-#endif
-
-/* Read a pixel Function */
-
-#if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__)
-	/**
-	 * @brief   Get the color of a pixel.
-	 * @return  The color of the pixel.
-	 * @pre		GDISP_NEED_PIXELREAD must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The position of the pixel
-	 *
-	 * @api
-	 */
-	color_t gdispGGetPixelColor(GDisplay *g, coord_t x, coord_t y);
-	#define gdispGetPixelColor(x,y)							gdispGGetPixelColor(GDISP,x,y)
-#endif
-
-/* Scrolling Function - clears the area scrolled out */
-
-#if GDISP_NEED_SCROLL || defined(__DOXYGEN__)
-	/**
-	 * @brief   Scroll vertically a section of the screen.
-	 * @pre		GDISP_NEED_SCROLL must be set to TRUE in gfxconf.h
-	 * @note    Optional.
-	 * @note    If lines is >= cy, it is equivelent to a area fill with bgcolor.
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x, y		The start of the area to be scrolled
-	 * @param[in] cx, cy	The size of the area to be scrolled
-	 * @param[in] lines		The number of lines to scroll (Can be positive or negative)
-	 * @param[in] bgcolor	The color to fill the newly exposed area.
-	 *
-	 * @api
-	 */
-	void gdispGVerticalScroll(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor);
-	#define gdispVerticalScroll(x,y,cx,cy,l,b)				gdispGVerticalScroll(GDISP,x,y,cx,cy,l,b)
-#endif
-
-/* Set driver specific control */
-
-#if GDISP_NEED_CONTROL || defined(__DOXYGEN__)
-	/**
-	 * @brief   Control hardware specific parts of the display. eg powermodes, backlight etc
-	 * @pre		GDISP_NEED_CONTROL must be TRUE in your gfxconf.h
-	 * @note    Depending on the hardware implementation this function may not
-	 *          support some codes. They will be ignored.
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] what		what you want to control
-	 * @param[in] value		The value to be assigned
-	 *
-	 * @api
-	 */
-	void gdispGControl(GDisplay *g, unsigned what, void *value);
-	#define gdispControl(w,v)								gdispGControl(GDISP,w,v)
-#endif
-
-/* Query driver specific data */
-
-#if GDISP_NEED_QUERY || defined(__DOXYGEN__)
-	/**
-	 * @brief   Query a property of the display.
-	 * @pre		GDISP_NEED_QUERY must be TRUE in your gfxconf.h
-	 * @note    The result must be typecast to the correct type.
-	 * @note    An unsupported query will return (void *)-1.
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] what		What to query
-	 *
-	 * @api
-	 */
-	void *gdispGQuery(GDisplay *g, unsigned what);
-	#define gdispQuery(w)									gdispGQuery(GDISP,w)
-#endif
-
-#if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__)
-	/**
-	 * @brief   Draw an enclosed polygon (convex, non-convex or complex).
-	 * @pre		GDISP_NEED_CONVEX_POLYGON must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] tx, ty	Transform all points in pntarray by tx, ty
-	 * @param[in] pntarray	An array of points
-	 * @param[in] cnt		The number of points in the array
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGDrawPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color);
-	#define gdispDrawPoly(x,y,p,i,c)						gdispGDrawPoly(GDISP,x,y,p,i,c)
-
-	/**
-	 * @brief   Fill a convex polygon
-	 * @details Doesn't handle non-convex or complex polygons.
-	 * @pre		GDISP_NEED_CONVEX_POLYGON must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] tx, ty	Transform all points in pntarray by tx, ty
-	 * @param[in] pntarray	An array of points
-	 * @param[in] cnt		The number of points in the array
-	 * @param[in] color		The color to use
-	 *
-	 * @note	Convex polygons are those that have no internal angles. That is;
-	 * 			you can draw a line from any point on the polygon to any other point
-	 * 			on the polygon without it going outside the polygon. In our case we generalise
-	 * 			this a little by saying that an infinite horizontal line (at any y value) will cross
-	 * 			no more than two edges on the polygon. Some non-convex polygons do fit this criteria
-	 * 			and can therefore be drawn.
-	 * @note	This routine is designed to be very efficient with even simple display hardware.
-	 *
-	 * @api
-	 */
-	void gdispGFillConvexPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color);
-	#define gdispFillConvexPoly(x,y,p,i,c)					gdispGFillConvexPoly(GDISP,x,y,p,i,c)
-
-	/**
-	 * @brief   Draw a line with a specified thickness
-	 * @details The line thickness is specified in pixels. The line ends can
-	 *          be selected to be either flat or round.
-	 * @pre		GDISP_NEED_CONVEX_POLYGON must be TRUE in your gfxconf.h
-	 * @note	Uses gdispGFillConvexPoly() internally to perform the drawing.
-	 *
-	 * @param[in] g			The display to use
-	 * @param[in] x0,y0		The start position
-	 * @param[in] x1,y1		The end position
-	 * @param[in] color		The color to use
-	 * @param[in] width		The width of the line
-	 * @param[in] round		Use round ends for the line
-	 *
-	 * @api
-	 */
-	void gdispGDrawThickLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color, coord_t width, bool_t round);
-	#define gdispDrawThickLine(x0,y0,x1,y1,c,w,r)			gdispGDrawThickLine(GDISP,x0,y0,x1,y1,c,w,r)
-#endif
-
-/* Text Functions */
-
-#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
-	/**
-	 * @brief   Draw a text character.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The position for the text
-	 * @param[in] c			The character to draw
-	 * @param[in] font		The font to use
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGDrawChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color);
-	#define	gdispDrawChar(x,y,s,f,c)						gdispGDrawChar(GDISP,x,y,s,f,c)
-
-	/**
-	 * @brief   Draw a text character with a filled background.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The position for the text
-	 * @param[in] c			The character to draw
-	 * @param[in] font		The font to use
-	 * @param[in] color		The color to use
-	 * @param[in] bgcolor	The background color to use
-	 *
-	 * @api
-	 */
-	void gdispGFillChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor);
-	#define	gdispFillChar(x,y,s,f,c,b)						gdispGFillChar(GDISP,x,y,s,f,c,b)
-
-	/**
-	 * @brief   Draw a text string.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The position for the text
-	 * @param[in] str		The string to draw
-	 * @param[in] font		The font to use
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGDrawString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color);
-	#define	gdispDrawString(x,y,s,f,c)						gdispGDrawString(GDISP,x,y,s,f,c)
-
-	/**
-	 * @brief   Draw a text string.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The position for the text
-	 * @param[in] str		The string to draw
-	 * @param[in] font		The font to use
-	 * @param[in] color		The color to use
-	 * @param[in] bgcolor	The background color to use
-	 *
-	 * @api
-	 */
-	void gdispGFillString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor);
-	#define	gdispFillString(x,y,s,f,c,b)					gdispGFillString(GDISP,x,y,s,f,c,b)
-
-	/**
-	 * @brief   Draw a text string vertically centered within the specified box.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
-	 * @param[in] cx,cy		The width and height of the box
-	 * @param[in] str		The string to draw
-	 * @param[in] font		The font to use
-	 * @param[in] color		The color to use
-	 * @param[in] justify	Justify the text left, center or right within the box
-	 *
-	 * @api
-	 */
-	void gdispGDrawStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify);
-	#define	gdispDrawStringBox(x,y,cx,cy,s,f,c,j)			gdispGDrawStringBox(GDISP,x,y,cx,cy,s,f,c,j)
-
-	/**
-	 * @brief   Draw a text string vertically centered within the specified box. The box background is filled with the specified background color.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 * @note    The entire box is filled
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
-	 * @param[in] cx,cy		The width and height of the box
-	 * @param[in] str		The string to draw
-	 * @param[in] font		The font to use
-	 * @param[in] color		The color to use
-	 * @param[in] bgColor	The background color to use
-	 * @param[in] justify	Justify the text left, center or right within the box
-	 *
-	 * @api
-	 */
-	void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgColor, justify_t justify);
-	#define	gdispFillStringBox(x,y,cx,cy,s,f,c,b,j)			gdispGFillStringBox(GDISP,x,y,cx,cy,s,f,c,b,j)
-
-	/**
-	 * @brief   Get a metric of a font.
-	 * @return  The metric requested in pixels.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] font    The font to test
-	 * @param[in] metric  The metric to measure
-	 *
-	 * @api
-	 */
-	coord_t gdispGetFontMetric(font_t font, fontmetric_t metric);
-
-	/**
-	 * @brief   Get the pixel width of a character.
-	 * @return  The width of the character in pixels. Does not include any between character padding.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] c       The character to draw
-	 * @param[in] font    The font to use
-	 *
-	 * @api
-	 */
-	coord_t gdispGetCharWidth(char c, font_t font);
-
-	/**
-	 * @brief   Get the pixel width of a string.
-	 * @return  The width of the string in pixels.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] str     The string to measure
-	 * @param[in] font    The font to use
-	 *
-	 * @api
-	 */
-	coord_t gdispGetStringWidth(const char* str, font_t font);
-
-	/**
-	 * @brief	Find a font and return it.
-	 * @details	The supplied name is matched against the font name. A '*' will replace 0 or more characters.
-	 * @return	Returns a font or NULL if no matching font could be found.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] name		The font name to find.
-	 *
-	 * @note				Wildcard matching will match the shortest possible match.
-	 *
-	 * @api
-	 */
-	font_t gdispOpenFont(const char *name);
-
-	/**
-	 * @brief	Release a font after use.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] font		The font to release.
-	 *
-	 * @api
-	 */
-	void gdispCloseFont(font_t font);
-
-	/**
-	 * @brief	Make a scaled copy of an existing font.
-	 * @details	Allocates memory for new font metadata using gfxAlloc, remember to close font after use!
-	 * @return	A new font or NULL if out of memory.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] font	The base font to use.
-	 * @param[in] scale_x	The scale factor in horizontal direction.
-	 * @param[in] scale_y	The scale factor in vertical direction.
-	 */
-	font_t gdispScaleFont(font_t font, uint8_t scale_x, uint8_t scale_y);
-
-	/**
-	 * @brief	Get the name of the specified font.
-	 * @returns	The name of the font.
-	 * @pre		GDISP_NEED_TEXT must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] font		The font to get the name for.
-	 *
-	 * @api
-	 */
-	const char *gdispGetFontName(font_t font);
-#endif
-
-/* Extra Arc Functions */
-
-#if GDISP_NEED_ARC || GDISP_NEED_ARCSECTORS || defined(__DOXYGEN__)
-	/**
-	 * @brief   Draw a rectangular box with rounded corners
-	 * @pre		GDISP_NEED_ARC or GDISP_NEED_ARCSECTORS must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The start position
-	 * @param[in] cx,cy		The size of the box (outside dimensions)
-	 * @param[in] radius	The radius of the rounded corners
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGDrawRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color);
-	#define gdispDrawRoundedBox(x,y,cx,cy,r,c)		gdispGDrawRoundedBox(GDISP,x,y,cx,cy,r,c)
-
-	/**
-	 * @brief   Draw a filled rectangular box with rounded corners
-	 * @pre		GDISP_NEED_ARC or GDISP_NEED_ARCSECTORS must be TRUE in your gfxconf.h
-	 *
-	 * @param[in] g 		The display to use
-	 * @param[in] x,y		The start position
-	 * @param[in] cx,cy		The size of the box (outside dimensions)
-	 * @param[in] radius	The radius of the rounded corners
-	 * @param[in] color		The color to use
-	 *
-	 * @api
-	 */
-	void gdispGFillRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color);
-	#define gdispFillRoundedBox(x,y,cx,cy,r,c)		gdispGFillRoundedBox(GDISP,x,y,cx,cy,r,c)
-#endif
-
-/*
- * Macro definitions
- */
-
-/* Now obsolete functions */
-#define gdispBlitArea(x, y, cx, cy, buffer)			gdispGBlitArea(GDISP, x, y, cx, cy, 0, 0, cx, buffer)
-
-/* Macro definitions for common gets and sets */
-
-/**
- * @brief   Set the display power mode.
- * @note    Ignored if not supported by the display.
- *
- * @param[in] g 			The display to use
- * @param[in] powerMode		The new power mode
- *
- * @api
- */
-#define gdispGSetPowerMode(g, powerMode)			gdispGControl((g), GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode))
-#define gdispSetPowerMode(powerMode)				gdispGControl(GDISP, GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode))
-
-/**
- * @brief   Set the display orientation.
- * @note    Ignored if not supported by the display.
- *
- * @param[in] g 					The display to use
- * @param[in] newOrientation		The new orientation
- *
- * @api
- */
-#define gdispGSetOrientation(g, newOrientation)		gdispGControl((g), GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation))
-#define gdispSetOrientation(newOrientation)			gdispGControl(GDISP, GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation))
-
-/**
- * @brief   Set the display backlight.
- * @note    Ignored if not supported by the display.
- *
- * @param[in] g 			The display to use
- * @param[in] percent		The new brightness (0 - 100%)
- *
- * @note	For displays that only support backlight off and on,
- * 			0 = off, anything else = on
- *
- * @api
- */
-#define gdispGSetBacklight(g, percent)				gdispGControl((g), GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent))
-#define gdispSetBacklight(percent)					gdispGControl(GDISP, GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent))
-
-/**
- * @brief   Set the display contrast.
- * @note    Ignored if not supported by the display.
- *
- * @param[in] g 			The display to use
- * @param[in] percent		The new contrast (0 - 100%)
- *
- * @api
- */
-#define gdispGSetContrast(g, percent)				gdispGControl((g), GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent))
-#define gdispSetContrast(percent)					gdispGControl(GDISP, GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent))
-
-/* More interesting macros */
-
-/**
- * @brief   Reset the clip area to the full screen
- *
- * @param[in] g 		The display to use
- *
- * @api
- */
-#define gdispGUnsetClip(g)							gdispGSetClip((g),0,0,gdispGGetWidth(g),gdispGGetHeight(g))
-#define gdispUnsetClip()							gdispGUnsetClip(GDISP)
-
-#ifdef __cplusplus
-}
-#endif
-
-#if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
-	#include "gdisp_image.h"
-#endif
-#if GDISP_NEED_PIXMAP || defined(__DOXYGEN__)
-	#include "gdisp_pixmap.h"
-#endif
-
-
-#endif /* GFX_USE_GDISP */
-
-#endif /* _GDISP_H */
-/** @} */
diff --git a/src/gdisp/sys_make.mk b/src/gdisp/sys_make.mk
deleted file mode 100644
index 34710597..00000000
--- a/src/gdisp/sys_make.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gdisp/gdisp_gdisp.c \
-			$(GFXLIB)/src/gdisp/gdisp_fonts.c \
-			$(GFXLIB)/src/gdisp/gdisp_pixmap.c \
-			$(GFXLIB)/src/gdisp/gdisp_image.c \
-			$(GFXLIB)/src/gdisp/gdisp_image_native.c \
-			$(GFXLIB)/src/gdisp/gdisp_image_gif.c \
-			$(GFXLIB)/src/gdisp/gdisp_image_bmp.c \
-			$(GFXLIB)/src/gdisp/gdisp_image_jpg.c \
-			$(GFXLIB)/src/gdisp/gdisp_image_png.c
-			
-MFDIR = $(GFXLIB)/src/gdisp/mcufont
-include $(GFXLIB)/src/gdisp/mcufont/mcufont.mk
-GFXINC += $(MFDIR)
-GFXSRC += $(MFSRC)
diff --git a/src/gdisp/sys_options.h b/src/gdisp/sys_options.h
deleted file mode 100644
index ebb054e1..00000000
--- a/src/gdisp/sys_options.h
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gdisp/sys_options.h
- * @brief   GDISP sub-system options header file.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#ifndef _GDISP_OPTIONS_H
-#define _GDISP_OPTIONS_H
-
-/**
- * @name    GDISP Functionality to be included
- * @{
- */
-	/**
-	 * @brief   Should drawing operations be automatically flushed.
-	 * @details	Defaults to FALSE
-	 * @note	If set to FALSE and the controller requires flushing
-	 * 			then the application must manually call @p gdispGFlush().
-	 * 			Setting this to TRUE causes GDISP to automatically flush
-	 * 			after each drawing operation. Note this may be slow but enables
-	 * 			an application to avoid having to manually call the flush routine.
-	 * @note	If TRUE and GDISP_NEED_TIMERFLUSH is also TRUE, this takes precedence.
-	 * @note	Most controllers don't need flushing which is why this is set to
-	 * 			FALSE by default.
-	 */
-	#ifndef GDISP_NEED_AUTOFLUSH
-		#define GDISP_NEED_AUTOFLUSH			FALSE
-	#endif
-	/**
-	 * @brief   Should drawing operations be automatically flushed on a timer.
-	 * @details	Defaults to FALSE, Can be set to FALSE or a timer period in milliseconds.
-	 * @note	The period should not be set too short or it will consume all your CPU. A
-	 * 			value between 250 and 500 milliseconds would probably be suitable.
-	 * @note	If TRUE and GDISP_NEED_AUTOFLUSH is also TRUE, this is ineffective.
-	 * @note	Most controllers don't need flushing which is why this is set to
-	 * 			FALSE by default.
-	 */
-	#ifndef GDISP_NEED_TIMERFLUSH
-		#define GDISP_NEED_TIMERFLUSH			FALSE
-	#endif
-	/**
-	 * @brief   Should all operations be clipped to the screen and colors validated.
-	 * @details	Defaults to TRUE.
-	 * @note    If this is FALSE, any operations that extend beyond the
-	 *          edge of the screen will have undefined results. Any
-	 *			out-of-range colors will produce undefined results.
-	 * @note	This should always be left as the default (TRUE) unless you
-	 * 			are a maniac for speed and you have thoroughly tested your code
-	 * 			and it never overwrites the edges of the screen.
-	 * @note	Setting GDISP_NEED_CLIP to TRUE internally uses the same mechanism
-	 * 			as this validation. There is no advantage in setting this FALSE if
-	 * 			GDISP_NEED_CLIP is TRUE.
-	 */
-	#ifndef GDISP_NEED_VALIDATION
-		#define GDISP_NEED_VALIDATION			TRUE
-	#endif
-	/**
-	 * @brief   Are clipping functions needed.
-	 * @details	Defaults to TRUE
-	 */
-	#ifndef GDISP_NEED_CLIP
-		#define GDISP_NEED_CLIP					TRUE
-	#endif
-	/**
-	 * @brief   Streaming functions are needed
-	 * @details	Defaults to FALSE.
-	 */
-	#ifndef GDISP_NEED_STREAMING
-		#define GDISP_NEED_STREAMING			FALSE
-	#endif
-	/**
-	 * @brief   Are text functions needed.
-	 * @details	Defaults to FALSE
-	 * @note	You must also define at least one font.
-	 */
-	#ifndef GDISP_NEED_TEXT
-		#define GDISP_NEED_TEXT					FALSE
-	#endif
-	/**
-	 * @brief   Are circle functions needed.
-	 * @details	Defaults to FALSE
-	 * @note	Uses integer algorithms only. It does not use any trig or floating point.
-	 */
-	#ifndef GDISP_NEED_CIRCLE
-		#define GDISP_NEED_CIRCLE				FALSE
-	#endif
-	/**
-	 * @brief   Are ellipse functions needed.
-	 * @details	Defaults to FALSE
-	 * @note	Uses integer algorithms only. It does not use any trig or floating point.
-	 */
-	#ifndef GDISP_NEED_ELLIPSE
-		#define GDISP_NEED_ELLIPSE				FALSE
-	#endif
-	/**
-	 * @brief   Are arc sector functions needed.
-	 * @details	Defaults to FALSE
-	 * @note	Uses integer algorithms only. It does not use any trig or floating point.
-	 */
-	#ifndef GDISP_NEED_ARCSECTORS
-		#define GDISP_NEED_ARCSECTORS			FALSE
-	#endif
-	/**
-	 * @brief   Are arc functions needed.
-	 * @details	Defaults to FALSE
-	 * @note	This can be compiled using fully integer mathematics by
-	 * 			defining GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG as TRUE.
-	 * @note	This can be compiled to use floating point but no trig functions
-	 * 			by defining GFX_USE_GMISC and GMISC_NEED_FASTTRIG as TRUE.
-	 * @note	If neither of the above are defined it requires the maths library
-	 * 			to be included in the link to provide floating point and trig support.
-	 * 			ie  include -lm in your compiler flags.
-	 */
-	#ifndef GDISP_NEED_ARC
-		#define GDISP_NEED_ARC					FALSE
-	#endif
-	/**
-	 * @brief   Are convex polygon functions needed.
-	 * @details	Defaults to FALSE
-	 * @note	Convex polygons are those that have no internal angles. That is;
-	 * 			you can draw a line from any point on the polygon to any other point
-	 * 			on the polygon without it going outside the polygon.
-	 */
-	#ifndef GDISP_NEED_CONVEX_POLYGON
-		#define GDISP_NEED_CONVEX_POLYGON		FALSE
-	#endif
-	/**
-	 * @brief   Are scrolling functions needed.
-	 * @details	Defaults to FALSE
-	 * @note	This function must be supported by the low level GDISP driver
-	 * 			you have included in your project. If it isn't, defining this
-	 * 			option will cause a compile error.
-	 */
-	#ifndef GDISP_NEED_SCROLL
-		#define GDISP_NEED_SCROLL				FALSE
-	#endif
-	/**
-	 * @brief   Is the capability to read pixels back needed.
-	 * @details	Defaults to FALSE
-	 * @note	This function must be supported by the low level GDISP driver
-	 * 			you have included in your project. If it isn't, defining this
-	 * 			option will cause a compile error.
-	 */
-	#ifndef GDISP_NEED_PIXELREAD
-		#define GDISP_NEED_PIXELREAD			FALSE
-	#endif
-	/**
-	 * @brief   Control some aspect of the hardware operation.
-	 * @details	Defaults to FALSE
-	 * @note	This allows control of hardware specific features such as
-	 * 			screen rotation, backlight levels, contrast etc
-	 */
-	#ifndef GDISP_NEED_CONTROL
-		#define GDISP_NEED_CONTROL				FALSE
-	#endif
-	/**
-	 * @brief   Query some aspect of the hardware operation.
-	 * @details	Defaults to FALSE
-	 * @note	This allows query of hardware specific features
-	 */
-	#ifndef GDISP_NEED_QUERY
-		#define GDISP_NEED_QUERY				FALSE
-	#endif
-	/**
-	 * @brief   Is the image interface required.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_IMAGE
-		#define GDISP_NEED_IMAGE				FALSE
-	#endif
-	/**
-	 * @brief   Is the image interface required.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_PIXMAP
-		#define GDISP_NEED_PIXMAP				FALSE
-	#endif
-/**
- * @}
- *
- * @name    GDISP Multi-Threading Options
- * @{
- */
-	/**
-	 * @brief   Do the drawing functions need to be thread-safe.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_MULTITHREAD
-		#define GDISP_NEED_MULTITHREAD			FALSE
-	#endif
-/**
- * @}
- *
- * @name    GDISP Optional Parameters
- * @{
- */
-	/**
-	 * @brief	Should the startup logo be displayed
-	 *
-	 * @details Defaults to TRUE
-	 */
-	#ifndef GDISP_NEED_STARTUP_LOGO
-		#define GDISP_NEED_STARTUP_LOGO 		TRUE
-	#endif
-	/**
-	 * @brief	Define the initial background color for all displays in the system.
-	 */
-	#ifndef GDISP_STARTUP_COLOR
-		#define GDISP_STARTUP_COLOR				Black
-	#endif
-	/**
-	 * @brief	Define the default orientation for all displays in the system.
-	 * @note	GDISP_NEED_CONTROL must also be set (and the hardware must support it)
-	 * @note	If not specified then displays default to the native hardware orientation
-	 */
-	// #define GDISP_DEFAULT_ORIENTATION		GDISP_ROTATE_LANDSCAPE
-	/**
-	 * @brief   The size of pixel buffer (in pixels) used for optimization.
-	 * @details	Set to zero to guarantee disabling of the buffer.
-	 * @note	Depending on the driver and what operations the application
-	 * 			needs, this buffer may never be allocated.
-	 * @note	Setting the size to zero may cause some operations to not
-	 * 			compile eg. Scrolling if there is no hardware scroll support.
-	 * @note	Increasing the size will speedup certain operations
-	 * 			at the expense of RAM.
-	 * @note	Currently only used to support scrolling on hardware without
-	 * 			scrolling support, and to increase the speed of streaming
-	 * 			operations on non-streaming hardware where there is a
-	 * 			hardware supported bit-blit.
-	 */
-	#ifndef GDISP_LINEBUF_SIZE
-		#define GDISP_LINEBUF_SIZE				128
-	#endif
-/**
- * @}
- *
- * @name    GDISP Multiple Display Support
- * @{
- */
-	/**
-	 * @brief   The total number of displays using the default driver.
-	 * @note	If you want to use multiple displays either set GDISP_TOTAL_DISPLAYS or GDISP_DRIVER_LIST
-	 *          but not both.
-	 */
-	#ifndef GDISP_TOTAL_DISPLAYS
-		#define GDISP_TOTAL_DISPLAYS		1
-	#endif
-	#if defined(__DOXYGEN__)
-		/**
-		 * @brief   The list of display drivers.
-		 * @note	Replace this example with your own definition in your gfxconf.h file. See the gdisp_lld.c
-		 *          in each driver (near the top) to get the name of the VMT for a driver.
-		 * @note    The same driver can occur more than once in the list to create an extra instance of that driver.
-		 * @note    If defining this you must also define GDISP_PIXELFORMAT for your application to use.
-         *          Choose a value that is most common accross all your drivers for efficiency.
-         * @note    If using this you may optionally define the GDISP_HARDWARE_xxx values as either TRUE or FALSE.
-         *          Doing this causes GDISP to assume that all (TRUE) or none (FALSE) of the listed drivers have that
-         *          capability. This can help improve drawing speed and efficiency.
-		 */
-		#define GDISP_DRIVER_LIST		  GDISPVMT_Win32, GDISPVMT_SSD1963
-	#endif
-/**
- * @}
- *
- * @name    GDISP Image Options
- * @pre		GDISP_NEED_IMAGE must be TRUE
- * @{
- */
-	/**
-	 * @brief   Is native image decoding required.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_IMAGE_NATIVE
-		#define GDISP_NEED_IMAGE_NATIVE			FALSE
-	#endif
-	/**
-	 * @brief   Is GIF image decoding required.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_IMAGE_GIF
-		#define GDISP_NEED_IMAGE_GIF			FALSE
-	#endif
-	/**
-	 * @brief   Is BMP image decoding required.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_IMAGE_BMP
-		#define GDISP_NEED_IMAGE_BMP			FALSE
-	#endif
-	/**
-	 * @brief   Is JPG image decoding required.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_IMAGE_JPG
-		#define GDISP_NEED_IMAGE_JPG			FALSE
-	#endif
-	/**
-	 * @brief   Is PNG image decoding required.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_IMAGE_PNG
-		#define GDISP_NEED_IMAGE_PNG			FALSE
-	#endif
-	/**
-	 * @brief   Is memory accounting required during image decoding.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_IMAGE_ACCOUNTING
-		#define GDISP_NEED_IMAGE_ACCOUNTING		FALSE
-	#endif
-/**
- * @}
- *
- * @name	GDISP Text Rendering Options
- * @{
- */
-	/**
-	 * @brief	Enable UTF-8 support for text rendering.
-	 * @details Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_UTF8
-		#define GDISP_NEED_UTF8					FALSE
-	#endif
-	/**
-	 * @brief	Enable kerning for font rendering (improves character placement).
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_TEXT_KERNING
-		#define GDISP_NEED_TEXT_KERNING			FALSE
-	#endif
-	/**
-	 * @brief	Enable antialiased font support
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GDISP_NEED_ANTIALIAS
-		#define GDISP_NEED_ANTIALIAS			FALSE
-	#endif
-/**
- * @}
- *
- * @name	GDISP Pixmap Options
- * @{
- */
-	#ifndef GDISP_NEED_PIXMAP_IMAGE
-		#define GDISP_NEED_PIXMAP_IMAGE			FALSE
-	#endif
-/**
- * @}
- *
- * @name    GDISP Optional Low Level Driver Defines
- * @{
- */
-	/**
-	 * @brief   Set the screen height and width.
-	 * @note	Ignored by some low level GDISP drivers, optional for others.
-	 * @note	Where these values are allowed, a default is always provided be the low level driver.
-	 * @note	The list of GDISP low level drivers that allow these to be set are...
-	 *				WIN32, SSD1289, SSD1963, TestStub
-	 */
-	/* #define GDISP_SCREEN_WIDTH		nnnn */
-	/* #define GDISP_SCREEN_HEIGHT		nnnn */
-	/**
-	 * @brief   Define which bus interface to use.
-	 * @details	Only required by the SSD1963 driver.
-	 * @note	This will be replaced eventually by board definition files
-	 */
-	// #define GDISP_USE_FSMC
-	// #define GDISP_USE_GPIO
-/** @} */
-
-#endif /* _GDISP_OPTIONS_H */
-/** @} */
-
diff --git a/src/gdisp/sys_rules.h b/src/gdisp/sys_rules.h
deleted file mode 100644
index 79df2d88..00000000
--- a/src/gdisp/sys_rules.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gdisp/sys_rules.h
- * @brief   GDISP safety rules header file.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#ifndef _GDISP_RULES_H
-#define _GDISP_RULES_H
-
-#if GFX_USE_GDISP
-	#if !GFX_USE_GDRIVER
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GDISP: GFX_USE_GDRIVER is required. GFX_USE_GDRIVER has turned on for you."
-		#endif
-		#undef GFX_USE_GDRIVER
-		#define GFX_USE_GDRIVER				TRUE
-	#endif
-	#if defined(GDISP_DRIVER_LIST)
-        #if GDISP_TOTAL_DISPLAYS != 1
-            #error "GDISP Multiple Drivers: You can't specify both GDISP_TOTAL_DISPLAYS and GDISP_DRIVER_LIST"
-        #endif
-		#ifndef GDISP_PIXELFORMAT
-			#error "GDISP Multiple Drivers: You must specify a value for GDISP_PIXELFORMAT when using GDISP_DRIVER_LIST"
-		#endif
-	#endif
-	#if GDISP_NEED_AUTOFLUSH && GDISP_NEED_TIMERFLUSH
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GDISP: Both GDISP_NEED_AUTOFLUSH and GDISP_NEED_TIMERFLUSH has been set. GDISP_NEED_TIMERFLUSH has disabled for you."
-		#endif
-		#undef GDISP_NEED_TIMERFLUSH
-		#define GDISP_NEED_TIMERFLUSH		FALSE
-	#endif
-	#if GDISP_NEED_TIMERFLUSH
-		#if GDISP_NEED_TIMERFLUSH < 50 || GDISP_NEED_TIMERFLUSH > 1200
-			#error "GDISP: GDISP_NEED_TIMERFLUSH has been set to an invalid value (FALSE, 50-1200)."
-		#endif
-		#if !GFX_USE_GTIMER
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GDISP: GDISP_NEED_TIMERFLUSH has been set but GFX_USE_GTIMER has not been set. It has been turned on for you."
-			#endif
-			#undef GFX_USE_GTIMER
-			#define GFX_USE_GTIMER				TRUE
-			#undef GDISP_NEED_MULTITHREAD
-			#define GDISP_NEED_MULTITHREAD		TRUE
-		#endif
-	#endif
-	#if GDISP_NEED_ANTIALIAS && !GDISP_NEED_PIXELREAD
-		#if GDISP_HARDWARE_PIXELREAD
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GDISP: GDISP_NEED_ANTIALIAS has been set but GDISP_NEED_PIXELREAD has not. It has been turned on for you."
-			#endif
-			#undef GDISP_NEED_PIXELREAD
-			#define GDISP_NEED_PIXELREAD	TRUE
-		#else
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GDISP: GDISP_NEED_ANTIALIAS has been set but your hardware does not support reading back pixels. Anti-aliasing will only occur for filled characters."
-			#endif
-		#endif
-	#endif
-	#if (defined(GDISP_INCLUDE_FONT_SMALL) && GDISP_INCLUDE_FONT_SMALL) || (defined(GDISP_INCLUDE_FONT_LARGER) && GDISP_INCLUDE_FONT_LARGER)
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GDISP: An old font (Small or Larger) has been defined. A single default font of UI2 has been added instead."
-			#warning "GDISP: Please see <$(GFXLIB)/include/gdisp/fonts/fonts.h> for a list of available font names."
-		#endif
-		#undef GDISP_INCLUDE_FONT_UI2
-		#define GDISP_INCLUDE_FONT_UI2		TRUE
-	#endif
-	#if GDISP_NEED_IMAGE
-		#if !GFX_USE_GFILE
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GDISP: GFX_USE_GFILE is required when GDISP_NEED_IMAGE is TRUE. It has been turned on for you."
-			#endif
-			#undef GFX_USE_GFILE
-			#define GFX_USE_GFILE	TRUE
-		#endif
-	#endif
-#endif
-
-#endif /* _GDISP_RULES_H */
-/** @} */
diff --git a/src/gdriver/gdriver.c b/src/gdriver/gdriver.c
new file mode 100644
index 00000000..d0324639
--- /dev/null
+++ b/src/gdriver/gdriver.c
@@ -0,0 +1,148 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GDRIVER
+
+#include "gdriver.h"
+
+#include <string.h>         // For memset
+
+// Define the tables to hold the driver instances.
+static GDriver *dhead;
+static GDriver *dtail;
+
+// The system initialization.
+void _gdriverInit(void) {
+}
+
+// The system de-initialization.
+void _gdriverDeinit(void) {
+	while(dhead)
+		gdriverUnRegister(dhead);
+}
+
+
+GDriver *gdriverRegister(const GDriverVMT *vmt, void *param) {
+	GDriver *	pd;
+	unsigned	dinstance, sinstance;
+
+	// Loop to find the driver instance and the system instance numbers
+	dinstance = sinstance = 0;
+	for(pd = dhead; pd; pd = pd->driverchain) {
+		if (pd->vmt == vmt)
+			dinstance++;
+		if (pd->vmt->type == vmt->type)
+			sinstance++;
+	}
+
+	// Get a new driver instance of the correct size and initialize it
+	pd = gfxAlloc(vmt->objsize);
+	if (!pd)
+		return 0;
+    memset(pd, 0, vmt->objsize);
+	pd->vmt = vmt;
+	if (vmt->init && !vmt->init(pd, param, dinstance, sinstance)) {
+		gfxFree(pd);
+		return 0;
+	}
+
+	// Add it to the driver chain
+	if (dhead)
+		dtail->driverchain = pd;
+	else
+		dhead = dtail = pd;
+
+	// Do the post init
+	if (vmt->postinit)
+		vmt->postinit(pd);
+
+	return pd;
+}
+
+void gdriverUnRegister(GDriver *driver) {
+	GDriver		*pd;
+
+	// Safety
+	if (!driver)
+		return;
+
+	// Remove it from the list of drivers
+	if (dhead == driver)
+		dhead = driver->driverchain;
+	else {
+		for(pd = dhead; pd->driverchain; pd = pd->driverchain) {
+			if (pd->driverchain == driver) {
+				pd->driverchain = driver->driverchain;
+				break;
+			}
+		}
+	}
+
+	// Call the deinit()
+	if (driver->vmt->deinit)
+		driver->vmt->deinit(driver);
+
+	// Cleanup
+	gfxFree(driver);
+}
+
+GDriver *gdriverGetInstance(uint16_t type, unsigned instance) {
+	GDriver		*pd;
+	unsigned	sinstance;
+
+	// Loop to find the system instance
+	sinstance = 0;
+	for(pd = dhead; pd; pd = pd->driverchain) {
+		if (pd->vmt->type == type) {
+			if (sinstance == instance)
+				return pd;
+			sinstance++;
+		}
+	}
+	return 0;
+}
+
+unsigned gdriverInstanceCount(uint16_t type) {
+	GDriver		*pd;
+	unsigned	sinstance;
+
+	// Loop to count the system instances
+	sinstance = 0;
+	for(pd = dhead; pd; pd = pd->driverchain) {
+		if (pd->vmt->type == type)
+			sinstance++;
+	}
+	return sinstance;
+}
+
+GDriver *gdriverGetNext(uint16_t type, GDriver *driver) {
+	driver = driver ? driver->driverchain : dhead;
+
+	while(driver && driver->vmt->type != type)
+		driver = driver->driverchain;
+
+	return driver;
+}
+
+unsigned gdriverGetDriverInstanceNumber(GDriver *driver) {
+	GDriver		*pd;
+	unsigned	instance;
+
+	// Loop to find the system instance
+	instance = 0;
+	for(pd = dhead; pd; pd = pd->driverchain) {
+		if (pd == driver)
+			return instance;
+		if (pd->vmt->type == driver->vmt->type)
+			instance++;
+	}
+	return (unsigned)-1;
+}
+
+#endif /* GFX_USE_GDRIVER */
diff --git a/src/gdriver/gdriver.h b/src/gdriver/gdriver.h
new file mode 100644
index 00000000..6f245ef1
--- /dev/null
+++ b/src/gdriver/gdriver.h
@@ -0,0 +1,159 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gdriver/gdriver.h
+ *
+ * @addtogroup GDRIVER
+ *
+ * @brief		Module to support registering and unregistering of drivers
+ *
+ * @details		GDRIVER provides a generalized way of defining and registering drivers.
+ *
+ * @note		There are many different types of drivers and GDRIVER can handle any
+ * 				type of driver defined by the uGFX system.
+ *
+ * @note		GDRIVER supports multiple drivers for one type of device. eg a SSD1289 LCD
+ * 				driver simultaneously with a framebuffer driver.
+ * @note		GDRIVER supports multiple instances of a single driver. eg 2 SSD1289 LCD's.
+ * @note		If there is only a single device of a particular type it will automatically
+ *				register that device (it only needs to be included in the build, no special
+ *				configuration is required)
+ * @note		This module gdriver.h file is NOT included in the general gfx.h file.
+ * 				Instead it is included in each driver type's driver API.
+ *
+ * @pre			GFX_USE_GDRIVER must be set to TRUE in your gfxconf.h
+ *
+ * @{
+ */
+
+#ifndef _GDRIVER_H
+#define _GDRIVER_H
+
+#if GFX_USE_GDRIVER || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+#define GDRIVER_TYPE_DISPLAY		'g'		// @< A graphics display
+#define GDRIVER_TYPE_MOUSE			'm'		// @< A mouse
+#define GDRIVER_TYPE_TOUCH			'm'		// @< A touch display (equivalent to a mouse)
+#define GDRIVER_TYPE_TOGGLE			't'		// @< A toggle device eg GPIO pins, switches etc
+#define GDRIVER_TYPE_DIAL			'd'		// @< A analog or digit dial (ranges in value from a minimum to a maximum)
+#define GDRIVER_TYPE_KEYBOARD		'k'		// @< A keyboard
+#define GDRIVER_TYPE_BLOCK			'b'		// @< A block device
+#define GDRIVER_TYPE_STRING			's'		// @< A device that returns strings of data
+
+/**
+ * @brief	All runtime driver structures start with this structure
+ *
+ * @note	This structure (and any additional structure memory) is allocated
+ * 			dynamically by the system for each driver instance.
+ */
+typedef struct GDriver {
+	struct GDriver *			driverchain;
+	const struct GDriverVMT *	vmt;
+} GDriver;
+
+/**
+ * @brief	All driver VMT's start with this structure.
+ */
+typedef struct GDriverVMT {
+	uint16_t	type;																// @< What type of driver this is
+	uint16_t	flags;																// @< Flags for the driver. Meaning is specific to each driver type.
+	uint32_t	objsize;															// @< How big the runtime driver structure is
+	bool_t		(*init)(GDriver *driver, void *param, unsigned driverinstance, unsigned systeminstance);	// @< Initialise the driver. Returns TRUE if OK.
+																					//		driverinstance is the instance 0..n of this driver.
+																					//		systeminstance is the instance 0..n of this type of device.
+																					//      The memory allocated is cleared before this call.
+	void		(*postinit)(GDriver *driver);										// @< Called once the driver is registered.
+	void		(*deinit)(GDriver *driver);											// @< De-initialise the driver
+} GDriverVMT;
+
+/**
+ * @brief	A definition that allows getting addresses of GDriverVMT structures to put into a list.
+ * @note	eg. <code>
+ * 				const MyDriverVMTtype a[1] = {{...}};
+ * 				const MyDriverVMTtype b[1] = {{...}};
+ * 				...
+ * 				\#define DRIVER_LIST		a, b
+ * 				extern GDriverVMTList	DRIVER_LIST;	// Now treated as single element arrays of GDriverVMT
+ * 				const GDriverVMT const * mylist = { DRIVER_LIST };
+ * 				</code>
+ *
+ */
+typedef const struct GDriverVMT const	GDriverVMTList[1];
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	/**
+	 * @brief	Register a new driver instance.
+	 * @return	The runtime driver structure or NULL if it fails.
+	 *
+	 * @param[in]	vmt		The driver's vmt
+	 * @param[in]	param	An arbitrary paramater passed to the driver init routine.
+	 */
+	GDriver *gdriverRegister(const GDriverVMT *vmt, void *param);
+
+	/**
+	 * @brief	UnRegister a driver instance.
+	 *
+	 * @param[in]	driver	The driver instance's runtime structure
+	 */
+	void gdriverUnRegister(GDriver *driver);
+
+	/**
+	 * @brief	Get the driver for a particular instance of a type of device
+	 * @return	The runtime driver structure or NULL if it fails.
+	 *
+	 * @param[in]	type		The type of driver to find
+	 * @param[in]	instance	The instance (0..n) to find
+	 */
+	GDriver *gdriverGetInstance(uint16_t type, unsigned instance);
+
+	/**
+	 * @brief	Get the count of instances of a type of device
+	 * @return	The instance count.
+	 *
+	 * @note	Valid instance numbers are then 0 .. count-1
+	 *
+	 * @param[in]	type		The type of driver to find
+	 */
+	unsigned gdriverInstanceCount(uint16_t type);
+
+	/**
+	 * @brief	Get the instance number for a device
+	 * @return	The instance number or (unsigned)-1 if it fails.
+	 *
+	 * @param[in]	driver	The driver to find the instance number for
+	 */
+	unsigned gdriverGetDriverInstanceNumber(GDriver *driver);
+
+	/**
+	 * @brief	Get the next driver for a type of device
+	 * @return	The runtime driver structure or NULL if there are no more.
+	 *
+	 * @param[in]	type		The type of driver to find
+	 * @param[in]	driver		The last driver returned or NULL to start again
+	 */
+	GDriver *gdriverGetNext(uint16_t type, GDriver *driver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GDRIVER */
+
+#endif /* _GDRIVER_H */
+/** @} */
diff --git a/src/gdriver/gdriver.mk b/src/gdriver/gdriver.mk
new file mode 100644
index 00000000..663042af
--- /dev/null
+++ b/src/gdriver/gdriver.mk
@@ -0,0 +1 @@
+GFXSRC +=   $(GFXLIB)/src/gdriver/gdriver.c
diff --git a/src/gdriver/gdriver_gdriver.c b/src/gdriver/gdriver_gdriver.c
deleted file mode 100644
index 210840b1..00000000
--- a/src/gdriver/gdriver_gdriver.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-#include "gfx.h"
-
-#if GFX_USE_GDRIVER
-
-#include "sys_defs.h"
-
-#include <string.h>         // For memset
-
-// Define the tables to hold the driver instances.
-static GDriver *dhead;
-static GDriver *dtail;
-
-// The system initialization.
-void _gdriverInit(void) {
-}
-
-// The system de-initialization.
-void _gdriverDeinit(void) {
-	while(dhead)
-		gdriverUnRegister(dhead);
-}
-
-
-GDriver *gdriverRegister(const GDriverVMT *vmt, void *param) {
-	GDriver *	pd;
-	unsigned	dinstance, sinstance;
-
-	// Loop to find the driver instance and the system instance numbers
-	dinstance = sinstance = 0;
-	for(pd = dhead; pd; pd = pd->driverchain) {
-		if (pd->vmt == vmt)
-			dinstance++;
-		if (pd->vmt->type == vmt->type)
-			sinstance++;
-	}
-
-	// Get a new driver instance of the correct size and initialize it
-	pd = gfxAlloc(vmt->objsize);
-	if (!pd)
-		return 0;
-    memset(pd, 0, vmt->objsize);
-	pd->vmt = vmt;
-	if (vmt->init && !vmt->init(pd, param, dinstance, sinstance)) {
-		gfxFree(pd);
-		return 0;
-	}
-
-	// Add it to the driver chain
-	if (dhead)
-		dtail->driverchain = pd;
-	else
-		dhead = dtail = pd;
-
-	// Do the post init
-	if (vmt->postinit)
-		vmt->postinit(pd);
-
-	return pd;
-}
-
-void gdriverUnRegister(GDriver *driver) {
-	GDriver		*pd;
-
-	// Safety
-	if (!driver)
-		return;
-
-	// Remove it from the list of drivers
-	if (dhead == driver)
-		dhead = driver->driverchain;
-	else {
-		for(pd = dhead; pd->driverchain; pd = pd->driverchain) {
-			if (pd->driverchain == driver) {
-				pd->driverchain = driver->driverchain;
-				break;
-			}
-		}
-	}
-
-	// Call the deinit()
-	if (driver->vmt->deinit)
-		driver->vmt->deinit(driver);
-
-	// Cleanup
-	gfxFree(driver);
-}
-
-GDriver *gdriverGetInstance(uint16_t type, unsigned instance) {
-	GDriver		*pd;
-	unsigned	sinstance;
-
-	// Loop to find the system instance
-	sinstance = 0;
-	for(pd = dhead; pd; pd = pd->driverchain) {
-		if (pd->vmt->type == type) {
-			if (sinstance == instance)
-				return pd;
-			sinstance++;
-		}
-	}
-	return 0;
-}
-
-unsigned gdriverInstanceCount(uint16_t type) {
-	GDriver		*pd;
-	unsigned	sinstance;
-
-	// Loop to count the system instances
-	sinstance = 0;
-	for(pd = dhead; pd; pd = pd->driverchain) {
-		if (pd->vmt->type == type)
-			sinstance++;
-	}
-	return sinstance;
-}
-
-GDriver *gdriverGetNext(uint16_t type, GDriver *driver) {
-	driver = driver ? driver->driverchain : dhead;
-
-	while(driver && driver->vmt->type != type)
-		driver = driver->driverchain;
-
-	return driver;
-}
-
-unsigned gdriverGetDriverInstanceNumber(GDriver *driver) {
-	GDriver		*pd;
-	unsigned	instance;
-
-	// Loop to find the system instance
-	instance = 0;
-	for(pd = dhead; pd; pd = pd->driverchain) {
-		if (pd == driver)
-			return instance;
-		if (pd->vmt->type == driver->vmt->type)
-			instance++;
-	}
-	return (unsigned)-1;
-}
-
-#endif /* GFX_USE_GDRIVER */
diff --git a/src/gdriver/gdriver_options.h b/src/gdriver/gdriver_options.h
new file mode 100644
index 00000000..ca3fe1f1
--- /dev/null
+++ b/src/gdriver/gdriver_options.h
@@ -0,0 +1,32 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gdriver/gdriver_options.h
+ * @brief   GDRIVER - Driver options header file.
+ *
+ * @addtogroup GDRIVER
+ * @{
+ */
+
+#ifndef _GDRIVER_OPTIONS_H
+#define _GDRIVER_OPTIONS_H
+
+/**
+ * @name    GDRIVER Functionality to be included
+ * @{
+ */
+/**
+ * @}
+ *
+ * @name    GDRIVER Optional Parameters
+ * @{
+ */
+/** @} */
+
+#endif /* _GDRIVER_OPTIONS_H */
+/** @} */
diff --git a/src/gdriver/gdriver_rules.h b/src/gdriver/gdriver_rules.h
new file mode 100644
index 00000000..2aaffa1b
--- /dev/null
+++ b/src/gdriver/gdriver_rules.h
@@ -0,0 +1,23 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gdriver/gdriver_rules.h
+ * @brief   GDRIVER safety rules header file.
+ *
+ * @addtogroup GFILE
+ * @{
+ */
+
+#ifndef _GDRIVER_RULES_H
+#define _GDRIVER_RULES_H
+
+#if GFX_USE_GDRIVER
+#endif
+
+#endif /* _GDRIVER_RULES_H */
+/** @} */
diff --git a/src/gdriver/sys_defs.h b/src/gdriver/sys_defs.h
deleted file mode 100644
index 4ac20b19..00000000
--- a/src/gdriver/sys_defs.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gdriver/sys_defs.h
- *
- * @addtogroup GDRIVER
- *
- * @brief		Module to support registering and unregistering of drivers
- *
- * @details		GDRIVER provides a generalized way of defining and registering drivers.
- *
- * @note		There are many different types of drivers and GDRIVER can handle any
- * 				type of driver defined by the uGFX system.
- *
- * @note		GDRIVER supports multiple drivers for one type of device. eg a SSD1289 LCD
- * 				driver simultaneously with a framebuffer driver.
- * @note		GDRIVER supports multiple instances of a single driver. eg 2 SSD1289 LCD's.
- * @note		If there is only a single device of a particular type it will automatically
- *				register that device (it only needs to be included in the build, no special
- *				configuration is required)
- * @note		This module sys_defs.h file is NOT included in the general gfx.h file.
- * 				Instead it is included in each driver type's driver API.
- *
- * @pre			GFX_USE_GDRIVER must be set to TRUE in your gfxconf.h
- *
- * @{
- */
-
-#ifndef _GDRIVER_H
-#define _GDRIVER_H
-
-#if GFX_USE_GDRIVER || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-#define GDRIVER_TYPE_DISPLAY		'g'		// @< A graphics display
-#define GDRIVER_TYPE_MOUSE			'm'		// @< A mouse
-#define GDRIVER_TYPE_TOUCH			'm'		// @< A touch display (equivalent to a mouse)
-#define GDRIVER_TYPE_TOGGLE			't'		// @< A toggle device eg GPIO pins, switches etc
-#define GDRIVER_TYPE_DIAL			'd'		// @< A analog or digit dial (ranges in value from a minimum to a maximum)
-#define GDRIVER_TYPE_KEYBOARD		'k'		// @< A keyboard
-#define GDRIVER_TYPE_BLOCK			'b'		// @< A block device
-#define GDRIVER_TYPE_STRING			's'		// @< A device that returns strings of data
-
-/**
- * @brief	All runtime driver structures start with this structure
- *
- * @note	This structure (and any additional structure memory) is allocated
- * 			dynamically by the system for each driver instance.
- */
-typedef struct GDriver {
-	struct GDriver *			driverchain;
-	const struct GDriverVMT *	vmt;
-} GDriver;
-
-/**
- * @brief	All driver VMT's start with this structure.
- */
-typedef struct GDriverVMT {
-	uint16_t	type;																// @< What type of driver this is
-	uint16_t	flags;																// @< Flags for the driver. Meaning is specific to each driver type.
-	uint32_t	objsize;															// @< How big the runtime driver structure is
-	bool_t		(*init)(GDriver *driver, void *param, unsigned driverinstance, unsigned systeminstance);	// @< Initialise the driver. Returns TRUE if OK.
-																					//		driverinstance is the instance 0..n of this driver.
-																					//		systeminstance is the instance 0..n of this type of device.
-																					//      The memory allocated is cleared before this call.
-	void		(*postinit)(GDriver *driver);										// @< Called once the driver is registered.
-	void		(*deinit)(GDriver *driver);											// @< De-initialise the driver
-} GDriverVMT;
-
-/**
- * @brief	A definition that allows getting addresses of GDriverVMT structures to put into a list.
- * @note	eg. <code>
- * 				const MyDriverVMTtype a[1] = {{...}};
- * 				const MyDriverVMTtype b[1] = {{...}};
- * 				...
- * 				\#define DRIVER_LIST		a, b
- * 				extern GDriverVMTList	DRIVER_LIST;	// Now treated as single element arrays of GDriverVMT
- * 				const GDriverVMT const * mylist = { DRIVER_LIST };
- * 				</code>
- *
- */
-typedef const struct GDriverVMT const	GDriverVMTList[1];
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-	/**
-	 * @brief	Register a new driver instance.
-	 * @return	The runtime driver structure or NULL if it fails.
-	 *
-	 * @param[in]	vmt		The driver's vmt
-	 * @param[in]	param	An arbitrary paramater passed to the driver init routine.
-	 */
-	GDriver *gdriverRegister(const GDriverVMT *vmt, void *param);
-
-	/**
-	 * @brief	UnRegister a driver instance.
-	 *
-	 * @param[in]	driver	The driver instance's runtime structure
-	 */
-	void gdriverUnRegister(GDriver *driver);
-
-	/**
-	 * @brief	Get the driver for a particular instance of a type of device
-	 * @return	The runtime driver structure or NULL if it fails.
-	 *
-	 * @param[in]	type		The type of driver to find
-	 * @param[in]	instance	The instance (0..n) to find
-	 */
-	GDriver *gdriverGetInstance(uint16_t type, unsigned instance);
-
-	/**
-	 * @brief	Get the count of instances of a type of device
-	 * @return	The instance count.
-	 *
-	 * @note	Valid instance numbers are then 0 .. count-1
-	 *
-	 * @param[in]	type		The type of driver to find
-	 */
-	unsigned gdriverInstanceCount(uint16_t type);
-
-	/**
-	 * @brief	Get the instance number for a device
-	 * @return	The instance number or (unsigned)-1 if it fails.
-	 *
-	 * @param[in]	driver	The driver to find the instance number for
-	 */
-	unsigned gdriverGetDriverInstanceNumber(GDriver *driver);
-
-	/**
-	 * @brief	Get the next driver for a type of device
-	 * @return	The runtime driver structure or NULL if there are no more.
-	 *
-	 * @param[in]	type		The type of driver to find
-	 * @param[in]	driver		The last driver returned or NULL to start again
-	 */
-	GDriver *gdriverGetNext(uint16_t type, GDriver *driver);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GDRIVER */
-
-#endif /* _GDRIVER_H */
-/** @} */
diff --git a/src/gdriver/sys_make.mk b/src/gdriver/sys_make.mk
deleted file mode 100644
index 93810aa9..00000000
--- a/src/gdriver/sys_make.mk
+++ /dev/null
@@ -1 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gdriver/gdriver_gdriver.c
diff --git a/src/gdriver/sys_options.h b/src/gdriver/sys_options.h
deleted file mode 100644
index bef0a95a..00000000
--- a/src/gdriver/sys_options.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gdriver/sys_options.h
- * @brief   GDRIVER - Driver options header file.
- *
- * @addtogroup GDRIVER
- * @{
- */
-
-#ifndef _GDRIVER_OPTIONS_H
-#define _GDRIVER_OPTIONS_H
-
-/**
- * @name    GDRIVER Functionality to be included
- * @{
- */
-/**
- * @}
- *
- * @name    GDRIVER Optional Parameters
- * @{
- */
-/** @} */
-
-#endif /* _GDRIVER_OPTIONS_H */
-/** @} */
diff --git a/src/gdriver/sys_rules.h b/src/gdriver/sys_rules.h
deleted file mode 100644
index 596babba..00000000
--- a/src/gdriver/sys_rules.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gdriver/sys_rules.h
- * @brief   GDRIVER safety rules header file.
- *
- * @addtogroup GFILE
- * @{
- */
-
-#ifndef _GDRIVER_RULES_H
-#define _GDRIVER_RULES_H
-
-#if GFX_USE_GDRIVER
-#endif
-
-#endif /* _GDRIVER_RULES_H */
-/** @} */
diff --git a/src/gevent/gevent.c b/src/gevent/gevent.c
new file mode 100644
index 00000000..bb57b3ad
--- /dev/null
+++ b/src/gevent/gevent.c
@@ -0,0 +1,238 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GEVENT || defined(__DOXYGEN__)
+
+#if GEVENT_ASSERT_NO_RESOURCE
+	#define GEVENT_ASSERT(x)		assert(x)
+#else
+	#define GEVENT_ASSERT(x)
+#endif
+
+/* Flags in the listener structure */
+#define GLISTENER_EVENTBUSY			0x0001			// The event buffer is busy
+#define GLISTENER_WAITING			0x0002			// The listener is waiting for a signal
+#define GLISTENER_WITHSOURCE		0x0004			// The listener is being looked at by a source for a possible event
+#define GLISTENER_PENDING			0x0008			// There is an event waiting ready to go without a current listener
+
+/* This mutex protects access to our tables */
+static gfxMutex	geventMutex;
+
+/* Our table of listener/source pairs */
+static GSourceListener		Assignments[GEVENT_MAX_SOURCE_LISTENERS];
+
+/* Send an exit event if possible. */
+/* We already have the geventMutex */
+static void doExitEvent(GListener *pl) {
+	// Don't do the exit if someone else currently has the event lock
+	if ((pl->flags & (GLISTENER_WAITING|GLISTENER_EVENTBUSY)) == GLISTENER_WAITING) {
+		pl->flags |= GLISTENER_EVENTBUSY;							// Event buffer is in use
+		pl->event.type = GEVENT_EXIT;								// Set up the EXIT event
+		pl->flags &= ~GLISTENER_WAITING;							// Wake up the listener (with data)
+		gfxSemSignal(&pl->waitqueue);
+	}
+}
+
+/* Loop through the assignment table deleting this listener/source pair. */
+/*	Null is treated as a wildcard. */
+/* We already have the geventMutex */
+static void deleteAssignments(GListener *pl, GSourceHandle gsh) {
+	GSourceListener *psl;
+
+	for(psl = Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
+		if ((!pl || psl->pListener == pl) && (!gsh || psl->pSource == gsh)) {
+			doExitEvent(psl->pListener);
+			psl->pListener = 0;
+			psl->pSource = 0;
+		}
+	}
+}
+
+void _geventInit(void)
+{
+	gfxMutexInit(&geventMutex);
+}
+
+void _geventDeinit(void)
+{
+	gfxMutexDestroy(&geventMutex);	
+}
+
+void geventListenerInit(GListener *pl) {
+	gfxSemInit(&pl->waitqueue, 0, MAX_SEMAPHORE_COUNT);		// Next wait'er will block
+	pl->callback = 0;										// No callback active
+	pl->event.type = GEVENT_NULL;							// Always safety
+	pl->flags = 0;
+}
+
+bool_t geventAttachSource(GListener *pl, GSourceHandle gsh, unsigned flags) {
+	GSourceListener *psl, *pslfree;
+
+	// Safety first
+	if (!pl || !gsh) {
+		GEVENT_ASSERT(FALSE);
+		return FALSE;
+	}
+
+	gfxMutexEnter(&geventMutex);
+
+	// Check if this pair is already in the table (scan for a free slot at the same time)
+	pslfree = 0;
+	for(psl = Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
+		
+		if (pl == psl->pListener && gsh == psl->pSource) {
+			// Just update the flags
+			psl->listenflags = flags;
+			gfxMutexExit(&geventMutex);
+			return TRUE;
+		}
+		if (!pslfree && !psl->pListener)
+			pslfree = psl;
+	}
+	
+	// A free slot was found - allocate it
+	if (pslfree) {
+		pslfree->pListener = pl;
+		pslfree->pSource = gsh;
+		pslfree->listenflags = flags;
+		pslfree->srcflags = 0;
+	}
+	gfxMutexExit(&geventMutex);
+	GEVENT_ASSERT(pslfree != 0);
+	return pslfree != 0;
+}
+
+void geventDetachSource(GListener *pl, GSourceHandle gsh) {
+	if (pl) {
+		gfxMutexEnter(&geventMutex);
+		deleteAssignments(pl, gsh);
+		if (!gsh)
+			doExitEvent(pl);
+		gfxMutexExit(&geventMutex);
+	}
+}
+
+GEvent *geventEventWait(GListener *pl, delaytime_t timeout) {
+	gfxMutexEnter(&geventMutex);
+	// Don't allow waiting if we are on callbacks or if there is already a thread waiting
+	if (pl->callback || (pl->flags & GLISTENER_WAITING)) {
+		gfxMutexExit(&geventMutex);
+		return 0;
+	}
+
+	// Check to see if there is a pending event ready for us
+	if ((pl->flags & GLISTENER_PENDING)) {
+		pl->flags &= ~GLISTENER_PENDING;				// We have now got this
+		pl->flags |= GLISTENER_EVENTBUSY;				// Event buffer is definitely busy
+		gfxMutexExit(&geventMutex);
+		return &pl->event;
+	}
+
+	// No - wait for one.
+	pl->flags &= ~GLISTENER_EVENTBUSY;				// Event buffer is definitely not busy
+	pl->flags |= GLISTENER_WAITING;					// We will now be waiting on the thread
+	gfxMutexExit(&geventMutex);
+	if (gfxSemWait(&pl->waitqueue, timeout))
+		return &pl->event;
+
+	// Timeout - clear the waiting flag.
+	// We know this is safe as any other thread will still think there is someone waiting.
+	gfxMutexEnter(&geventMutex);
+	pl->flags &= ~GLISTENER_WAITING;
+	gfxMutexExit(&geventMutex);
+	return 0;
+}
+
+void geventEventComplete(GListener *pl) {
+	pl->flags &= ~GLISTENER_EVENTBUSY;
+}
+
+void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param) {
+	if (pl) {
+		gfxMutexEnter(&geventMutex);
+		doExitEvent(pl);
+		pl->param = param;						// Set the param
+		pl->callback = fn;						// Set the callback function
+		if (fn)
+			pl->flags &= ~GLISTENER_EVENTBUSY;	// The event buffer is immediately available
+		gfxMutexExit(&geventMutex);
+	}
+}
+
+GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *lastlr) {
+	GSourceListener *psl;
+
+	// Safety first
+	if (!gsh)
+		return 0;
+
+	gfxMutexEnter(&geventMutex);
+
+	// Unlock the last listener event buffer if it wasn't used.
+	if (lastlr && lastlr->pListener && (lastlr->pListener->flags & GLISTENER_WITHSOURCE))
+		lastlr->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
+		
+	// Loop through the table looking for attachments to this source
+	for(psl = lastlr ? (lastlr+1) : Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
+		if (gsh == psl->pSource) {
+			gfxMutexExit(&geventMutex);
+			return psl;
+		}
+	}
+	gfxMutexExit(&geventMutex);
+	return 0;
+}
+
+GEvent *geventGetEventBuffer(GSourceListener *psl) {
+	gfxMutexEnter(&geventMutex);
+	if ((psl->pListener->flags & GLISTENER_EVENTBUSY)) {
+		// Oops - event buffer is still in use
+		gfxMutexExit(&geventMutex);
+		return 0;
+	}
+
+	// Allocate the event buffer
+	psl->pListener->flags |= (GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
+	gfxMutexExit(&geventMutex);
+	return &psl->pListener->event;
+}
+
+void geventSendEvent(GSourceListener *psl) {
+	gfxMutexEnter(&geventMutex);
+	if (psl->pListener->callback) {
+
+		// Mark it back as free and as sent. This is early to be marking as free but it protects
+		//	if the callback alters the listener in any way
+		psl->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY|GLISTENER_PENDING);
+		gfxMutexExit(&geventMutex);
+
+		// Do the callback
+		psl->pListener->callback(psl->pListener->param, &psl->pListener->event);
+
+	} else {
+		// Wake up the listener
+		psl->pListener->flags &= ~GLISTENER_WITHSOURCE;
+		if ((psl->pListener->flags & GLISTENER_WAITING)) {
+			psl->pListener->flags &= ~(GLISTENER_WAITING|GLISTENER_PENDING);
+			gfxSemSignal(&psl->pListener->waitqueue);
+		} else
+			psl->pListener->flags |= GLISTENER_PENDING;
+
+		// The listener thread will free the event buffer when ready
+		gfxMutexExit(&geventMutex);
+	}
+}
+
+void geventDetachSourceListeners(GSourceHandle gsh) {
+	gfxMutexEnter(&geventMutex);
+	deleteAssignments(0, gsh);
+	gfxMutexExit(&geventMutex);
+}
+
+#endif /* GFX_USE_GEVENT */
diff --git a/src/gevent/gevent.h b/src/gevent/gevent.h
new file mode 100644
index 00000000..a33fd84a
--- /dev/null
+++ b/src/gevent/gevent.h
@@ -0,0 +1,246 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gevent/gevent.h
+ *
+ * @addtogroup GEVENT
+ *
+ * @brief		Module to build a complete many-to-many event system
+ * 
+ * @details		GEVENT provides a simple to use but yet powerful event
+ *				system.
+ *
+ * @pre			GFX_USE_GEVENT must be set to TRUE in your gfxconf.h
+ *
+ * @{
+ */
+#ifndef _GEVENT_H
+#define _GEVENT_H
+
+#include "gfx.h"
+
+#if GFX_USE_GEVENT || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+typedef uint16_t						GEventType;
+		#define GEVENT_NULL				0x0000				// Null Event - Do nothing
+		#define GEVENT_EXIT				0x0001				// The listener is being forced to exit (someone is destroying the listener)
+		
+		/* Other event types are allocated in ranges in their respective include files */
+		#define GEVENT_GINPUT_FIRST		0x0100				// GINPUT events range from 0x0100 to 0x01FF
+		#define GEVENT_GWIN_FIRST		0x0200				// GWIN events range from 0x0200 to 0x02FF
+		#define GEVENT_GADC_FIRST		0x0300				// GADC events range from 0x0300 to 0x033F
+		#define GEVENT_GAUDIO_FIRST		0x0340				// GAUDIO events range from 0x0340 to 0x037F
+		#define GEVENT_USER_FIRST		0x8000				// Any application defined events start at 0x8000
+
+// This object can be typecast to any GEventXxxxx type to allow any sub-system (or the application) to create events.
+//	The prerequisite is that the new status structure type starts with a field named 'type' of type 'GEventType'.
+//	The total status structure also must not exceed GEVENT_MAXIMUM_SIZE bytes.
+//	For example, this is used by GWIN button events, GINPUT data streams etc.
+typedef union GEvent_u {
+	GEventType			type;								// The type of this event
+	char				pad[GEVENT_MAXIMUM_SIZE];			// This is here to allow static initialisation of GEventObject's in the application.
+} GEvent;
+
+// A special callback function
+typedef void (*GEventCallbackFn)(void *param, GEvent *pe);
+
+// The Listener Object
+typedef struct GListener {
+	gfxSem				waitqueue;			// Private: Semaphore for the listener to wait on.
+	uint16_t			flags;				// Private: Flags for operation
+	GEventCallbackFn	callback;			// Private: Call back Function
+	void				*param;				// Private: Parameter for the callback function.
+	GEvent				event;				// Public:  The event object into which the event information is stored.
+	} GListener;
+
+// The Source Object
+typedef struct GSource_t			GSource, *GSourceHandle;	
+
+// This structure is passed to a source to describe a contender listener for sending the current event.
+typedef struct GSourceListener_t {
+	GListener		*pListener;			// The listener
+	GSource			*pSource;			// The source
+	unsigned		listenflags;		// The flags the listener passed when the source was assigned to it.
+	unsigned		srcflags;			// For the source's exclusive use. Initialised as 0 for a new listener source assignment.
+	} GSourceListener;
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* How to listen for events (act as a Listener)...
+	1. Get handles for all the event sources you are interested in.
+	2. Initialise a listener
+	3. Attach sources to your listener.
+		- Sources can be attached or detached from a listener at any time.
+		- A source can be attached to more than one listener.
+	4. Loop on getting listener events
+	5. When finished detach all sources from the listener
+	
+	How to create events (act as a Source)...
+	1. Provide a funtion to the application that returns a GSourceHandle (which can be a pointer to whatever the source wants)
+	2. Whenever a possible event occurs call geventGetSourceListener to get a pointer to a GSourceListener.
+			This will return NULL when there are no more listeners.
+			For each listener	- check the flags to see if an event should be sent.
+								- use geventGetEvent() to get the event buffer supplied by the listener
+									and then call geventSendEvent to send the event.
+								- Note: geventGetEvent() may return FALSE to indicate the listener is currently not listening and
+									therefore no event should be sent. This situation enables the source to (optionally) flag
+									to the listener on its next wait that there have been missed events.
+								- Note: The GSourceListener pointer (and the GEvent buffer) are only valid between
+									the geventGetSourceListener call and either the geventSendEvent call or the next
+									geventGetSourceListener call.
+								- Note: All listeners must be processed for this event before anything else is processed.
+*/
+
+/*---------- Listener Functions --------------------------------------------*/
+
+/**
+ * @brief	Create a Listener
+ * @details	If insufficient resources are available it will either assert or return NULL
+ *			depending on the value of GEVENT_ASSERT_NO_RESOURCE.
+ *
+ * @param[in] pl	A listener
+ */
+void geventListenerInit(GListener *pl);
+
+/**
+ * @brief 	Attach a source to a listener
+ * @details	Flags are interpreted by the source when generating events for each listener.
+ *			If this source is already assigned to the listener it will update the flags.
+ *			If insufficient resources are available it will either assert or return FALSE
+ *			depending on the value of GEVENT_ASSERT_NO_RESOURCE.
+ *
+ * @param[in] pl	The listener
+ * @param[in] gsh	The source which has to be attached to the listener
+ * @param[in] flags	The flags
+ *
+ * @return TRUE if succeeded, FALSE otherwise
+ */
+bool_t geventAttachSource(GListener *pl, GSourceHandle gsh, unsigned flags);
+
+/**
+ * @brief	Detach a source from a listener
+ * @details	If gsh is NULL detach all sources from this listener and if there is still
+ *			a thread waiting for events on this listener, it is sent the exit event.
+ *
+ * @param[in] pl	The listener
+ * @param[in] gsh	The source
+ */
+void geventDetachSource(GListener *pl, GSourceHandle gsh);
+
+/**
+ * @brief	Wait for an event on a listener from an assigned source.
+ * @details	The type of the event should be checked (pevent->type) and then pevent should
+ *			be typecast to the actual event type if it needs to be processed.
+ * 			timeout specifies the time to wait in system ticks.
+ *			TIME_INFINITE means no timeout - wait forever for an event.
+ *			TIME_IMMEDIATE means return immediately
+ * @note	The returned GEvent is released when this routine is called again
+ * 			or when optionally @p geventEventComplete() is called. Calling @p geventEventComplete()
+ * 			allows the GEvent object to be reused earlier which can reduce missed events. The GEvent
+ * 			object MUST NOT be used after this function is called (and is blocked waiting for the next
+ * 			event) or after geventEventComplete() is called.
+ *
+ * @param[in] pl		The listener
+ * @param[in] timeout	The timeout
+ *
+ * @return	NULL on timeout
+ */
+GEvent *geventEventWait(GListener *pl, delaytime_t timeout);
+
+/**
+ * @brief	Release the GEvent buffer associated with a listener.
+ * @details	The GEvent returned by @p geventEventWait() is released.
+ * @note	The GEvent pointer returned by @p geventEventWait() is released when @p geventEventWait()
+ * 			is called again or when this function is called. The GEvent
+ * 			object MUST NOT be used after this function is called.
+ *
+ * @param[in] pl		The listener
+ */
+void geventEventComplete(GListener *pl);
+
+/* @brief	Register a callback for an event on a listener from an assigned source.
+ * @details	The type of the event should be checked (pevent->type) and then pevent should be typecast to the
+ *			actual event type if it needs to be processed.
+ *
+ * @params[in] pl		The Listener
+ * @params[in] fn		The function to call back
+ * @params[in] param	A parameter to pass the callback function
+ *
+ * @note	The GEvent buffer is valid only during the time of the callback. The callback MUST NOT save
+ * 			a pointer to the buffer for use outside the callback.
+ * @note	An existing callback function is de-registered by passing a NULL for 'fn'. Any existing
+ * 			callback function is replaced. Any thread currently waiting using geventEventWait will be sent the exit event.
+ * @note	Callbacks occur in a thread context but stack space must be kept to a minumum and
+ * 			the callback must process quickly as all other events are performed on a single thread.
+ * @note	In the callback function you should never call ANY event functions using your own GListener handle
+ * 			as it WILL create a deadlock and lock the system up.
+ * @note	Applications should not use this call - geventEventWait() is the preferred mechanism for an
+ * 			application. This call is provided for GUI objects that may not have their own thread.
+ */
+void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param);
+
+/*---------- Source Functions --------------------------------------------*/
+
+/**
+ * @brief	Called by a source with a possible event to get a listener record.
+ * @details	@p lastlr should be NULL on the first call and thereafter the result of the previous call.
+ *
+ * @param[in] gsh		The source handler
+ * @param[in] lastlr	The source listener
+ *
+ * @return	NULL when there are no more listeners for this source
+ */
+GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *lastlr);
+
+/**
+ * @brief	Get the event buffer from the GSourceListener.
+ * @details	A NULL return allows the source to record (perhaps in glr->scrflags) that the listener
+ *			has missed events. This can then be notified as part of the next event for the listener.
+ *			The buffer can only be accessed untill the next call to geventGetSourceListener
+ *			or geventSendEvent
+ *
+ * @param[in] psl	The source listener
+ *
+ * @return	NULL if the listener is not currently listening.
+ */
+GEvent *geventGetEventBuffer(GSourceListener *psl);
+
+/** 
+ * @brief	Called by a source to indicate the listener's event buffer has been filled.
+ * @details	After calling this function the source must not reference in fields in the GSourceListener or the event buffer.
+ *
+ * @param[in] psl	The source listener
+ */
+void geventSendEvent(GSourceListener *psl);
+
+/**
+ * @brief	Detach any listener that has this source attached
+ *
+ * @param[in] gsh	The source handle
+ */
+void geventDetachSourceListeners(GSourceHandle gsh);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GEVENT */
+
+#endif /* _GEVENT_H */
+/** @} */
+
diff --git a/src/gevent/gevent.mk b/src/gevent/gevent.mk
new file mode 100644
index 00000000..5744ae46
--- /dev/null
+++ b/src/gevent/gevent.mk
@@ -0,0 +1 @@
+GFXSRC +=   $(GFXLIB)/src/gevent/gevent.c
diff --git a/src/gevent/gevent_gevent.c b/src/gevent/gevent_gevent.c
deleted file mode 100644
index fc45102e..00000000
--- a/src/gevent/gevent_gevent.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gevent/gevent_gevent.c
- * @brief   GEVENT Driver code.
- *
- * @addtogroup GEVENT
- * @{
- */
-#include "gfx.h"
-
-#if GFX_USE_GEVENT || defined(__DOXYGEN__)
-
-#if GEVENT_ASSERT_NO_RESOURCE
-	#define GEVENT_ASSERT(x)		assert(x)
-#else
-	#define GEVENT_ASSERT(x)
-#endif
-
-/* Flags in the listener structure */
-#define GLISTENER_EVENTBUSY			0x0001			// The event buffer is busy
-#define GLISTENER_WAITING			0x0002			// The listener is waiting for a signal
-#define GLISTENER_WITHSOURCE		0x0004			// The listener is being looked at by a source for a possible event
-#define GLISTENER_PENDING			0x0008			// There is an event waiting ready to go without a current listener
-
-/* This mutex protects access to our tables */
-static gfxMutex	geventMutex;
-
-/* Our table of listener/source pairs */
-static GSourceListener		Assignments[GEVENT_MAX_SOURCE_LISTENERS];
-
-/* Send an exit event if possible. */
-/* We already have the geventMutex */
-static void doExitEvent(GListener *pl) {
-	// Don't do the exit if someone else currently has the event lock
-	if ((pl->flags & (GLISTENER_WAITING|GLISTENER_EVENTBUSY)) == GLISTENER_WAITING) {
-		pl->flags |= GLISTENER_EVENTBUSY;							// Event buffer is in use
-		pl->event.type = GEVENT_EXIT;								// Set up the EXIT event
-		pl->flags &= ~GLISTENER_WAITING;							// Wake up the listener (with data)
-		gfxSemSignal(&pl->waitqueue);
-	}
-}
-
-/* Loop through the assignment table deleting this listener/source pair. */
-/*	Null is treated as a wildcard. */
-/* We already have the geventMutex */
-static void deleteAssignments(GListener *pl, GSourceHandle gsh) {
-	GSourceListener *psl;
-
-	for(psl = Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
-		if ((!pl || psl->pListener == pl) && (!gsh || psl->pSource == gsh)) {
-			doExitEvent(psl->pListener);
-			psl->pListener = 0;
-			psl->pSource = 0;
-		}
-	}
-}
-
-void _geventInit(void)
-{
-	gfxMutexInit(&geventMutex);
-}
-
-void _geventDeinit(void)
-{
-	gfxMutexDestroy(&geventMutex);	
-}
-
-void geventListenerInit(GListener *pl) {
-	gfxSemInit(&pl->waitqueue, 0, MAX_SEMAPHORE_COUNT);		// Next wait'er will block
-	pl->callback = 0;										// No callback active
-	pl->event.type = GEVENT_NULL;							// Always safety
-	pl->flags = 0;
-}
-
-bool_t geventAttachSource(GListener *pl, GSourceHandle gsh, unsigned flags) {
-	GSourceListener *psl, *pslfree;
-
-	// Safety first
-	if (!pl || !gsh) {
-		GEVENT_ASSERT(FALSE);
-		return FALSE;
-	}
-
-	gfxMutexEnter(&geventMutex);
-
-	// Check if this pair is already in the table (scan for a free slot at the same time)
-	pslfree = 0;
-	for(psl = Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
-		
-		if (pl == psl->pListener && gsh == psl->pSource) {
-			// Just update the flags
-			psl->listenflags = flags;
-			gfxMutexExit(&geventMutex);
-			return TRUE;
-		}
-		if (!pslfree && !psl->pListener)
-			pslfree = psl;
-	}
-	
-	// A free slot was found - allocate it
-	if (pslfree) {
-		pslfree->pListener = pl;
-		pslfree->pSource = gsh;
-		pslfree->listenflags = flags;
-		pslfree->srcflags = 0;
-	}
-	gfxMutexExit(&geventMutex);
-	GEVENT_ASSERT(pslfree != 0);
-	return pslfree != 0;
-}
-
-void geventDetachSource(GListener *pl, GSourceHandle gsh) {
-	if (pl) {
-		gfxMutexEnter(&geventMutex);
-		deleteAssignments(pl, gsh);
-		if (!gsh)
-			doExitEvent(pl);
-		gfxMutexExit(&geventMutex);
-	}
-}
-
-GEvent *geventEventWait(GListener *pl, delaytime_t timeout) {
-	gfxMutexEnter(&geventMutex);
-	// Don't allow waiting if we are on callbacks or if there is already a thread waiting
-	if (pl->callback || (pl->flags & GLISTENER_WAITING)) {
-		gfxMutexExit(&geventMutex);
-		return 0;
-	}
-
-	// Check to see if there is a pending event ready for us
-	if ((pl->flags & GLISTENER_PENDING)) {
-		pl->flags &= ~GLISTENER_PENDING;				// We have now got this
-		pl->flags |= GLISTENER_EVENTBUSY;				// Event buffer is definitely busy
-		gfxMutexExit(&geventMutex);
-		return &pl->event;
-	}
-
-	// No - wait for one.
-	pl->flags &= ~GLISTENER_EVENTBUSY;				// Event buffer is definitely not busy
-	pl->flags |= GLISTENER_WAITING;					// We will now be waiting on the thread
-	gfxMutexExit(&geventMutex);
-	if (gfxSemWait(&pl->waitqueue, timeout))
-		return &pl->event;
-
-	// Timeout - clear the waiting flag.
-	// We know this is safe as any other thread will still think there is someone waiting.
-	gfxMutexEnter(&geventMutex);
-	pl->flags &= ~GLISTENER_WAITING;
-	gfxMutexExit(&geventMutex);
-	return 0;
-}
-
-void geventEventComplete(GListener *pl) {
-	pl->flags &= ~GLISTENER_EVENTBUSY;
-}
-
-void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param) {
-	if (pl) {
-		gfxMutexEnter(&geventMutex);
-		doExitEvent(pl);
-		pl->param = param;						// Set the param
-		pl->callback = fn;						// Set the callback function
-		if (fn)
-			pl->flags &= ~GLISTENER_EVENTBUSY;	// The event buffer is immediately available
-		gfxMutexExit(&geventMutex);
-	}
-}
-
-GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *lastlr) {
-	GSourceListener *psl;
-
-	// Safety first
-	if (!gsh)
-		return 0;
-
-	gfxMutexEnter(&geventMutex);
-
-	// Unlock the last listener event buffer if it wasn't used.
-	if (lastlr && lastlr->pListener && (lastlr->pListener->flags & GLISTENER_WITHSOURCE))
-		lastlr->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
-		
-	// Loop through the table looking for attachments to this source
-	for(psl = lastlr ? (lastlr+1) : Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
-		if (gsh == psl->pSource) {
-			gfxMutexExit(&geventMutex);
-			return psl;
-		}
-	}
-	gfxMutexExit(&geventMutex);
-	return 0;
-}
-
-GEvent *geventGetEventBuffer(GSourceListener *psl) {
-	gfxMutexEnter(&geventMutex);
-	if ((psl->pListener->flags & GLISTENER_EVENTBUSY)) {
-		// Oops - event buffer is still in use
-		gfxMutexExit(&geventMutex);
-		return 0;
-	}
-
-	// Allocate the event buffer
-	psl->pListener->flags |= (GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
-	gfxMutexExit(&geventMutex);
-	return &psl->pListener->event;
-}
-
-void geventSendEvent(GSourceListener *psl) {
-	gfxMutexEnter(&geventMutex);
-	if (psl->pListener->callback) {
-
-		// Mark it back as free and as sent. This is early to be marking as free but it protects
-		//	if the callback alters the listener in any way
-		psl->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY|GLISTENER_PENDING);
-		gfxMutexExit(&geventMutex);
-
-		// Do the callback
-		psl->pListener->callback(psl->pListener->param, &psl->pListener->event);
-
-	} else {
-		// Wake up the listener
-		psl->pListener->flags &= ~GLISTENER_WITHSOURCE;
-		if ((psl->pListener->flags & GLISTENER_WAITING)) {
-			psl->pListener->flags &= ~(GLISTENER_WAITING|GLISTENER_PENDING);
-			gfxSemSignal(&psl->pListener->waitqueue);
-		} else
-			psl->pListener->flags |= GLISTENER_PENDING;
-
-		// The listener thread will free the event buffer when ready
-		gfxMutexExit(&geventMutex);
-	}
-}
-
-void geventDetachSourceListeners(GSourceHandle gsh) {
-	gfxMutexEnter(&geventMutex);
-	deleteAssignments(0, gsh);
-	gfxMutexExit(&geventMutex);
-}
-
-#endif /* GFX_USE_GEVENT */
-/** @} */
diff --git a/src/gevent/gevent_options.h b/src/gevent/gevent_options.h
new file mode 100644
index 00000000..7f68fd32
--- /dev/null
+++ b/src/gevent/gevent_options.h
@@ -0,0 +1,55 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gevent/gevent_options.h
+ * @brief   GEVENT sub-system options header file.
+ *
+ * @addtogroup GEVENT
+ * @{
+ */
+
+#ifndef _GEVENT_OPTIONS_H
+#define _GEVENT_OPTIONS_H
+
+/**
+ * @name    GEVENT Functionality to be included
+ * @{
+ */
+	/**
+	 * @brief   Should routines assert() if they run out of resources.
+	 * @details	Defaults to FALSE.
+	 * @details	If FALSE the application must be prepared to handle these
+	 *			failures.
+	 */
+	#ifndef GEVENT_ASSERT_NO_RESOURCE
+		#define GEVENT_ASSERT_NO_RESOURCE		FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GEVENT Optional Sizing Parameters
+ * @{
+ */
+	/**
+	 * @brief   Defines the maximum size of an event status variable.
+	 * @details	Defaults to 32 bytes
+	 */
+	#ifndef GEVENT_MAXIMUM_SIZE
+		#define GEVENT_MAXIMUM_SIZE				32
+	#endif
+	/**
+	 * @brief   Defines the maximum Source/Listener pairs in the system.
+	 * @details	Defaults to 32
+	 */
+	#ifndef GEVENT_MAX_SOURCE_LISTENERS
+		#define GEVENT_MAX_SOURCE_LISTENERS		32
+	#endif
+/** @} */
+
+#endif /* _GEVENT_OPTIONS_H */
+/** @} */
diff --git a/src/gevent/gevent_rules.h b/src/gevent/gevent_rules.h
new file mode 100644
index 00000000..8dc12c8d
--- /dev/null
+++ b/src/gevent/gevent_rules.h
@@ -0,0 +1,23 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gevent/gevent_rules.h
+ * @brief   GEVENT safety rules header file.
+ *
+ * @addtogroup GEVENT
+ * @{
+ */
+
+#ifndef _GEVENT_RULES_H
+#define _GEVENT_RULES_H
+
+#if GFX_USE_GEVENT
+#endif
+
+#endif /* _GEVENT_RULES_H */
+/** @} */
diff --git a/src/gevent/sys_defs.h b/src/gevent/sys_defs.h
deleted file mode 100644
index 9f1f4dde..00000000
--- a/src/gevent/sys_defs.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gevent/sys_defs.h
- *
- * @addtogroup GEVENT
- *
- * @brief		Module to build a complete many-to-many event system
- * 
- * @details		GEVENT provides a simple to use but yet powerful event
- *				system.
- *
- * @pre			GFX_USE_GEVENT must be set to TRUE in your gfxconf.h
- *
- * @{
- */
-#ifndef _GEVENT_H
-#define _GEVENT_H
-
-#include "gfx.h"
-
-#if GFX_USE_GEVENT || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-typedef uint16_t						GEventType;
-		#define GEVENT_NULL				0x0000				// Null Event - Do nothing
-		#define GEVENT_EXIT				0x0001				// The listener is being forced to exit (someone is destroying the listener)
-		
-		/* Other event types are allocated in ranges in their respective include files */
-		#define GEVENT_GINPUT_FIRST		0x0100				// GINPUT events range from 0x0100 to 0x01FF
-		#define GEVENT_GWIN_FIRST		0x0200				// GWIN events range from 0x0200 to 0x02FF
-		#define GEVENT_GADC_FIRST		0x0300				// GADC events range from 0x0300 to 0x033F
-		#define GEVENT_GAUDIO_FIRST		0x0340				// GAUDIO events range from 0x0340 to 0x037F
-		#define GEVENT_USER_FIRST		0x8000				// Any application defined events start at 0x8000
-
-// This object can be typecast to any GEventXxxxx type to allow any sub-system (or the application) to create events.
-//	The prerequisite is that the new status structure type starts with a field named 'type' of type 'GEventType'.
-//	The total status structure also must not exceed GEVENT_MAXIMUM_SIZE bytes.
-//	For example, this is used by GWIN button events, GINPUT data streams etc.
-typedef union GEvent_u {
-	GEventType			type;								// The type of this event
-	char				pad[GEVENT_MAXIMUM_SIZE];			// This is here to allow static initialisation of GEventObject's in the application.
-} GEvent;
-
-// A special callback function
-typedef void (*GEventCallbackFn)(void *param, GEvent *pe);
-
-// The Listener Object
-typedef struct GListener {
-	gfxSem				waitqueue;			// Private: Semaphore for the listener to wait on.
-	uint16_t			flags;				// Private: Flags for operation
-	GEventCallbackFn	callback;			// Private: Call back Function
-	void				*param;				// Private: Parameter for the callback function.
-	GEvent				event;				// Public:  The event object into which the event information is stored.
-	} GListener;
-
-// The Source Object
-typedef struct GSource_t			GSource, *GSourceHandle;	
-
-// This structure is passed to a source to describe a contender listener for sending the current event.
-typedef struct GSourceListener_t {
-	GListener		*pListener;			// The listener
-	GSource			*pSource;			// The source
-	unsigned		listenflags;		// The flags the listener passed when the source was assigned to it.
-	unsigned		srcflags;			// For the source's exclusive use. Initialised as 0 for a new listener source assignment.
-	} GSourceListener;
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* How to listen for events (act as a Listener)...
-	1. Get handles for all the event sources you are interested in.
-	2. Initialise a listener
-	3. Attach sources to your listener.
-		- Sources can be attached or detached from a listener at any time.
-		- A source can be attached to more than one listener.
-	4. Loop on getting listener events
-	5. When finished detach all sources from the listener
-	
-	How to create events (act as a Source)...
-	1. Provide a funtion to the application that returns a GSourceHandle (which can be a pointer to whatever the source wants)
-	2. Whenever a possible event occurs call geventGetSourceListener to get a pointer to a GSourceListener.
-			This will return NULL when there are no more listeners.
-			For each listener	- check the flags to see if an event should be sent.
-								- use geventGetEvent() to get the event buffer supplied by the listener
-									and then call geventSendEvent to send the event.
-								- Note: geventGetEvent() may return FALSE to indicate the listener is currently not listening and
-									therefore no event should be sent. This situation enables the source to (optionally) flag
-									to the listener on its next wait that there have been missed events.
-								- Note: The GSourceListener pointer (and the GEvent buffer) are only valid between
-									the geventGetSourceListener call and either the geventSendEvent call or the next
-									geventGetSourceListener call.
-								- Note: All listeners must be processed for this event before anything else is processed.
-*/
-
-/*---------- Listener Functions --------------------------------------------*/
-
-/**
- * @brief	Create a Listener
- * @details	If insufficient resources are available it will either assert or return NULL
- *			depending on the value of GEVENT_ASSERT_NO_RESOURCE.
- *
- * @param[in] pl	A listener
- */
-void geventListenerInit(GListener *pl);
-
-/**
- * @brief 	Attach a source to a listener
- * @details	Flags are interpreted by the source when generating events for each listener.
- *			If this source is already assigned to the listener it will update the flags.
- *			If insufficient resources are available it will either assert or return FALSE
- *			depending on the value of GEVENT_ASSERT_NO_RESOURCE.
- *
- * @param[in] pl	The listener
- * @param[in] gsh	The source which has to be attached to the listener
- * @param[in] flags	The flags
- *
- * @return TRUE if succeeded, FALSE otherwise
- */
-bool_t geventAttachSource(GListener *pl, GSourceHandle gsh, unsigned flags);
-
-/**
- * @brief	Detach a source from a listener
- * @details	If gsh is NULL detach all sources from this listener and if there is still
- *			a thread waiting for events on this listener, it is sent the exit event.
- *
- * @param[in] pl	The listener
- * @param[in] gsh	The source
- */
-void geventDetachSource(GListener *pl, GSourceHandle gsh);
-
-/**
- * @brief	Wait for an event on a listener from an assigned source.
- * @details	The type of the event should be checked (pevent->type) and then pevent should
- *			be typecast to the actual event type if it needs to be processed.
- * 			timeout specifies the time to wait in system ticks.
- *			TIME_INFINITE means no timeout - wait forever for an event.
- *			TIME_IMMEDIATE means return immediately
- * @note	The returned GEvent is released when this routine is called again
- * 			or when optionally @p geventEventComplete() is called. Calling @p geventEventComplete()
- * 			allows the GEvent object to be reused earlier which can reduce missed events. The GEvent
- * 			object MUST NOT be used after this function is called (and is blocked waiting for the next
- * 			event) or after geventEventComplete() is called.
- *
- * @param[in] pl		The listener
- * @param[in] timeout	The timeout
- *
- * @return	NULL on timeout
- */
-GEvent *geventEventWait(GListener *pl, delaytime_t timeout);
-
-/**
- * @brief	Release the GEvent buffer associated with a listener.
- * @details	The GEvent returned by @p geventEventWait() is released.
- * @note	The GEvent pointer returned by @p geventEventWait() is released when @p geventEventWait()
- * 			is called again or when this function is called. The GEvent
- * 			object MUST NOT be used after this function is called.
- *
- * @param[in] pl		The listener
- */
-void geventEventComplete(GListener *pl);
-
-/* @brief	Register a callback for an event on a listener from an assigned source.
- * @details	The type of the event should be checked (pevent->type) and then pevent should be typecast to the
- *			actual event type if it needs to be processed.
- *
- * @params[in] pl		The Listener
- * @params[in] fn		The function to call back
- * @params[in] param	A parameter to pass the callback function
- *
- * @note	The GEvent buffer is valid only during the time of the callback. The callback MUST NOT save
- * 			a pointer to the buffer for use outside the callback.
- * @note	An existing callback function is de-registered by passing a NULL for 'fn'. Any existing
- * 			callback function is replaced. Any thread currently waiting using geventEventWait will be sent the exit event.
- * @note	Callbacks occur in a thread context but stack space must be kept to a minumum and
- * 			the callback must process quickly as all other events are performed on a single thread.
- * @note	In the callback function you should never call ANY event functions using your own GListener handle
- * 			as it WILL create a deadlock and lock the system up.
- * @note	Applications should not use this call - geventEventWait() is the preferred mechanism for an
- * 			application. This call is provided for GUI objects that may not have their own thread.
- */
-void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param);
-
-/*---------- Source Functions --------------------------------------------*/
-
-/**
- * @brief	Called by a source with a possible event to get a listener record.
- * @details	@p lastlr should be NULL on the first call and thereafter the result of the previous call.
- *
- * @param[in] gsh		The source handler
- * @param[in] lastlr	The source listener
- *
- * @return	NULL when there are no more listeners for this source
- */
-GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *lastlr);
-
-/**
- * @brief	Get the event buffer from the GSourceListener.
- * @details	A NULL return allows the source to record (perhaps in glr->scrflags) that the listener
- *			has missed events. This can then be notified as part of the next event for the listener.
- *			The buffer can only be accessed untill the next call to geventGetSourceListener
- *			or geventSendEvent
- *
- * @param[in] psl	The source listener
- *
- * @return	NULL if the listener is not currently listening.
- */
-GEvent *geventGetEventBuffer(GSourceListener *psl);
-
-/** 
- * @brief	Called by a source to indicate the listener's event buffer has been filled.
- * @details	After calling this function the source must not reference in fields in the GSourceListener or the event buffer.
- *
- * @param[in] psl	The source listener
- */
-void geventSendEvent(GSourceListener *psl);
-
-/**
- * @brief	Detach any listener that has this source attached
- *
- * @param[in] gsh	The source handle
- */
-void geventDetachSourceListeners(GSourceHandle gsh);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GEVENT */
-
-#endif /* _GEVENT_H */
-/** @} */
-
diff --git a/src/gevent/sys_make.mk b/src/gevent/sys_make.mk
deleted file mode 100644
index f8b88e56..00000000
--- a/src/gevent/sys_make.mk
+++ /dev/null
@@ -1 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gevent/gevent_gevent.c
diff --git a/src/gevent/sys_options.h b/src/gevent/sys_options.h
deleted file mode 100644
index 6a58103f..00000000
--- a/src/gevent/sys_options.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gevent/sys_options.h
- * @brief   GEVENT sub-system options header file.
- *
- * @addtogroup GEVENT
- * @{
- */
-
-#ifndef _GEVENT_OPTIONS_H
-#define _GEVENT_OPTIONS_H
-
-/**
- * @name    GEVENT Functionality to be included
- * @{
- */
-	/**
-	 * @brief   Should routines assert() if they run out of resources.
-	 * @details	Defaults to FALSE.
-	 * @details	If FALSE the application must be prepared to handle these
-	 *			failures.
-	 */
-	#ifndef GEVENT_ASSERT_NO_RESOURCE
-		#define GEVENT_ASSERT_NO_RESOURCE		FALSE
-	#endif
-/**
- * @}
- *
- * @name    GEVENT Optional Sizing Parameters
- * @{
- */
-	/**
-	 * @brief   Defines the maximum size of an event status variable.
-	 * @details	Defaults to 32 bytes
-	 */
-	#ifndef GEVENT_MAXIMUM_SIZE
-		#define GEVENT_MAXIMUM_SIZE				32
-	#endif
-	/**
-	 * @brief   Defines the maximum Source/Listener pairs in the system.
-	 * @details	Defaults to 32
-	 */
-	#ifndef GEVENT_MAX_SOURCE_LISTENERS
-		#define GEVENT_MAX_SOURCE_LISTENERS		32
-	#endif
-/** @} */
-
-#endif /* _GEVENT_OPTIONS_H */
-/** @} */
diff --git a/src/gevent/sys_rules.h b/src/gevent/sys_rules.h
deleted file mode 100644
index 8cf7e9b4..00000000
--- a/src/gevent/sys_rules.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gevent/sys_rules.h
- * @brief   GEVENT safety rules header file.
- *
- * @addtogroup GEVENT
- * @{
- */
-
-#ifndef _GEVENT_RULES_H
-#define _GEVENT_RULES_H
-
-#if GFX_USE_GEVENT
-#endif
-
-#endif /* _GEVENT_RULES_H */
-/** @} */
diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c
new file mode 100644
index 00000000..4c22e6cc
--- /dev/null
+++ b/src/gfile/gfile.c
@@ -0,0 +1,401 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GFILE
+
+#include "gfile_fs.h"
+
+/**
+ * Define the VMT's for the file-systems we want to search for files.
+ * Virtual file-systems that have special open() calls do not need to
+ * be in this list.
+ */
+#if GFILE_NEED_ROMFS
+	extern const GFILEVMT FsROMVMT;
+#endif
+#if GFILE_NEED_NATIVEFS
+	extern const GFILEVMT FsNativeVMT;
+#endif
+#if GFILE_NEED_FATFS
+	extern const GFILEVMT FsFatFSVMT;
+#endif
+#if GFILE_NEED_RAMFS
+	extern const GFILEVMT FsRAMVMT;
+#endif
+
+
+/**
+ * The order of the file-systems below determines the order
+ * that they are searched to find a file.
+ */
+static const GFILEVMT const * FsArray[] = {
+	#if GFILE_NEED_ROMFS
+		&FsROMVMT,
+	#endif
+	#if GFILE_NEED_NATIVEFS
+		&FsNativeVMT,
+	#endif
+	#if GFILE_NEED_FATFS
+		&FsFatFSVMT,
+	#endif
+	#if GFILE_NEED_RAMFS
+		&FsRAMVMT,
+	#endif
+};
+
+/*
+ * The table of GFILE's
+ */
+static GFILE gfileArr[GFILE_MAX_GFILES];
+GFILE *gfileStdIn;
+GFILE *gfileStdOut;
+GFILE *gfileStdErr;
+
+/**
+ * The init routine
+ */
+void _gfileInit(void) {
+	#if GFILE_NEED_NATIVEFS
+		extern void _gfileNativeAssignStdio(void);
+		_gfileNativeAssignStdio();
+	#endif
+}
+
+void _gfileDeinit(void)
+{
+	/* ToDo */
+}
+
+/**
+ * Internal routine to find an empty GFILE slot and interpret flags.
+ */
+GFILE *_gfileFindSlot(const char *mode) {
+	GFILE *			f;
+
+	// First find an available GFILE slot.
+	for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
+		if (!(f->flags & GFILEFLG_OPEN)) {
+			// Get the flags
+			switch(mode[0]) {
+			case 'r':
+				f->flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST;
+				while (*++mode) {
+					switch(mode[0]) {
+					case '+':	f->flags |= GFILEFLG_WRITE;			break;
+					case 'b':	f->flags |= GFILEFLG_BINARY;		break;
+					}
+				}
+				break;
+			case 'w':
+				f->flags = GFILEFLG_WRITE|GFILEFLG_TRUNC;
+				while (*++mode) {
+					switch(mode[0]) {
+					case '+':	f->flags |= GFILEFLG_READ;			break;
+					case 'b':	f->flags |= GFILEFLG_BINARY;		break;
+					case 'x':	f->flags |= GFILEFLG_MUSTNOTEXIST;	break;
+					}
+				}
+				break;
+			case 'a':
+				f->flags = GFILEFLG_WRITE|GFILEFLG_APPEND;
+				while (*++mode) {
+					switch(mode[0]) {
+					case '+':	f->flags |= GFILEFLG_READ;			break;
+					case 'b':	f->flags |= GFILEFLG_BINARY;		break;
+					case 'x':	f->flags |= GFILEFLG_MUSTNOTEXIST;	break;
+					}
+				}
+				break;
+			default:
+				return 0;
+			}
+			return f;
+		}
+	}
+	return 0;
+}
+
+/********************************************************
+ * IO routines
+ ********************************************************/
+
+bool_t gfileExists(const char *fname) {
+	const GFILEVMT * const *p;
+
+	#if GFILE_ALLOW_DEVICESPECIFIC
+		if (fname[0] && fname[1] == '|') {
+			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+				if (p[0]->prefix == fname[0])
+					return p[0]->exists && p[0]->exists(fname+2);
+			}
+			return FALSE;
+		}
+	#endif
+
+	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+		if (p[0]->exists && p[0]->exists(fname))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+bool_t gfileDelete(const char *fname) {
+	const GFILEVMT **p;
+
+	#if GFILE_ALLOW_DEVICESPECIFIC
+		if (fname[0] && fname[1] == '|') {
+			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+				if (p[0]->prefix == fname[0])
+					return p[0]->del && p[0]->del(fname+2);
+			}
+			return FALSE;
+		}
+	#endif
+
+	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+		if (p[0]->del && p[0]->del(fname))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+long int gfileGetFilesize(const char *fname) {
+	const GFILEVMT * const *p;
+	long int res;
+
+	#if GFILE_ALLOW_DEVICESPECIFIC
+		if (fname[0] && fname[1] == '|') {
+			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+				if (p[0]->prefix == fname[0])
+					return p[0]->filesize ? p[0]->filesize(fname+2) : -1;
+			}
+			return -1;
+		}
+	#endif
+
+	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+		if (p[0]->filesize && (res = p[0]->filesize(fname)) != -1)
+			return res;
+	}
+	return -1;
+}
+
+bool_t gfileRename(const char *oldname, const char *newname) {
+	const GFILEVMT * const *p;
+
+	#if GFILE_ALLOW_DEVICESPECIFIC
+		if ((oldname[0] && oldname[1] == '|') || (newname[0] && newname[1] == '|')) {
+			char ch;
+
+			if (oldname[0] && oldname[1] == '|') {
+				ch = oldname[0];
+				oldname += 2;
+				if (newname[0] && newname[1] == '|') {
+					if (newname[0] != ch)
+						// Both oldname and newname are fs specific but different ones.
+						return FALSE;
+					newname += 2;
+				}
+			} else {
+				ch = newname[0];
+				newname += 2;
+			}
+			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+				if (p[0]->prefix == ch)
+					return p[0]->ren && p[0]->ren(oldname, newname);
+			}
+			return FALSE;
+		}
+	#endif
+
+	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+		if (p[0]->ren && p[0]->ren(oldname,newname))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+static bool_t testopen(const GFILEVMT *p, GFILE *f, const char *fname) {
+	// If we want write but the fs doesn't allow it then return
+	if ((f->flags & GFILEFLG_WRITE) && !(p->flags & GFSFLG_WRITEABLE))
+		return FALSE;
+
+	// Try to open
+	if (!p->open || !p->open(f, fname))
+		return FALSE;
+
+	// File is open - fill in all the details
+	f->vmt = p;
+	f->pos = 0;
+	f->flags |= GFILEFLG_OPEN;
+	if (p->flags & GFSFLG_SEEKABLE)
+		f->flags |= GFILEFLG_CANSEEK;
+	return TRUE;
+}
+
+GFILE *gfileOpen(const char *fname, const char *mode) {
+	GFILE *			f;
+	const GFILEVMT * const *p;
+
+	// Get an empty file and set the flags
+	if (!(f = _gfileFindSlot(mode)))
+		return 0;
+
+	#if GFILE_ALLOW_DEVICESPECIFIC
+		if (fname[0] && fname[1] == '|') {
+			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+				if (p[0]->prefix == fname[0])
+					return testopen(p[0], f, fname+2) ? f : 0;
+			}
+
+			// File not found
+			return 0;
+		}
+	#endif
+
+	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+		if (testopen(p[0], f, fname))
+			return f;
+	}
+
+	// File not found
+	return 0;
+}
+
+void gfileClose(GFILE *f) {
+	if (!f || !(f->flags & GFILEFLG_OPEN))
+		return;
+	if (f->vmt->close)
+		f->vmt->close(f);
+	f->flags = 0;
+}
+
+size_t gfileRead(GFILE *f, void *buf, size_t len) {
+	size_t	res;
+
+	if (!f || (f->flags & (GFILEFLG_OPEN|GFILEFLG_READ)) != (GFILEFLG_OPEN|GFILEFLG_READ))
+		return 0;
+	if (!f->vmt->read)
+		return 0;
+	if ((res = f->vmt->read(f, buf, len)) <= 0)
+		return 0;
+	f->pos += res;
+	return res;
+}
+
+size_t gfileWrite(GFILE *f, const void *buf, size_t len) {
+	size_t	res;
+
+	if (!f || (f->flags & (GFILEFLG_OPEN|GFILEFLG_WRITE)) != (GFILEFLG_OPEN|GFILEFLG_WRITE))
+		return 0;
+	if (!f->vmt->write)
+		return 0;
+	if ((res = f->vmt->write(f, buf, len)) <= 0)
+		return 0;
+	f->pos += res;
+	return res;
+}
+
+long int gfileGetPos(GFILE *f) {
+	if (!f || !(f->flags & GFILEFLG_OPEN))
+		return 0;
+	return f->pos;
+}
+
+bool_t gfileSetPos(GFILE *f, long int pos) {
+	if (!f || !(f->flags & GFILEFLG_OPEN))
+		return FALSE;
+	if (!f->vmt->setpos || !f->vmt->setpos(f, pos))
+		return FALSE;
+	f->pos = pos;
+	return TRUE;
+}
+
+long int gfileGetSize(GFILE *f) {
+	if (!f || !(f->flags & GFILEFLG_OPEN))
+		return 0;
+	if (!f->vmt->getsize)
+		return 0;
+	return f->vmt->getsize(f);
+}
+
+bool_t gfileEOF(GFILE *f) {
+	if (!f || !(f->flags & GFILEFLG_OPEN))
+		return TRUE;
+	if (!f->vmt->eof)
+		return FALSE;
+	return f->vmt->eof(f);
+}
+
+bool_t gfileMount(char fs, const char* drive) {
+	const GFILEVMT * const *p;
+
+	// Find the correct VMT
+	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+		if (p[0]->prefix == fs) {
+			if (!p[0]->mount)
+				return FALSE;
+			return p[0]->mount(drive);
+		}
+	}
+	return FALSE;
+}
+
+bool_t gfileUnmount(char fs, const char* drive) {
+	const GFILEVMT * const *p;
+
+	// Find the correct VMT
+	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+		if (p[0]->prefix == fs) {
+			if (!p[0]->mount)
+				return FALSE;
+			return p[0]->unmount(drive);
+		}
+	}
+	return FALSE;
+}
+
+bool_t gfileSync(GFILE *f) {
+	if (!f->vmt->sync)
+		return FALSE;
+	return f->vmt->sync(f);
+}
+
+#if GFILE_NEED_FILELISTS
+	gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs) {
+		const GFILEVMT * const *p;
+		gfileList *		pfl;
+
+		// Find the correct VMT
+		for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
+			if (p[0]->prefix == fs) {
+				if (!p[0]->flopen)
+					return 0;
+				pfl = p[0]->flopen(path, dirs);
+				if (pfl) {
+					pfl->vmt = p[0];
+					pfl->dirs = dirs;
+				}
+				return pfl;
+			}
+		}
+		return 0;
+	}
+
+	const char *gfileReadFileList(gfileList *pfl) {
+		return pfl->vmt->flread ? pfl->vmt->flread(pfl) : 0;
+	}
+
+	void gfileCloseFileList(gfileList *pfl) {
+		if (pfl->vmt->flclose)
+			pfl->vmt->flclose(pfl);
+	}
+#endif
+
+#endif /* GFX_USE_GFILE */
diff --git a/src/gfile/gfile.h b/src/gfile/gfile.h
new file mode 100644
index 00000000..f332db4c
--- /dev/null
+++ b/src/gfile/gfile.h
@@ -0,0 +1,470 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gfile/gfile.h
+ * @brief   GFILE - File IO Routines header file.
+ *
+ * @addtogroup GFILE
+ *
+ * @brief	Module which contains Operating system independent FILEIO
+ *
+ * @{
+ */
+
+#ifndef _GFILE_H
+#define _GFILE_H
+
+#include "gfx.h"
+
+#if GFX_USE_GFILE || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+/**
+ * @brief	A file pointer
+ */
+
+typedef struct GFILE GFILE;
+typedef struct gfileList gfileList;
+
+extern GFILE *gfileStdIn;
+extern GFILE *gfileStdErr;
+extern GFILE *gfileStdOut;
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	/**
+	 * @brief					Check if file exists
+	 * 
+	 * @param[in] fname			The file name
+	 * 
+	 * @return					TRUE if file exists, FALSE otherwise
+	 * 
+	 * @api
+	 */
+	bool_t		gfileExists(const char *fname);
+
+	/**
+	 * @brief					Delete file
+	 * 
+	 * @param[in] fname			The file name
+	 * 
+	 * @return					TRUE on success, FALSE otherwise
+	 * 
+	 * @api
+	 */
+	bool_t		gfileDelete(const char *fname);
+
+	/**
+	 * @brief					Get the size of a file
+	 * @note					Please use @p gfileGetSize() if the file is opened
+	 * 
+	 * @param[in] fname			The file name
+	 * 
+	 * @return					File size on success, -1 on error
+	 * 
+	 * @api
+	 */
+	long int	gfileGetFilesize(const char *fname);
+
+	/**
+	 * @brief					Rename file
+	 *
+	 * @param[in] oldname		The current file name
+	 * @param[in] newname		The new name of the file
+	 *
+	 * @return					TRUE on success, FALSE otherwise
+	 *
+	 * @api
+	 */
+	bool_t		gfileRename(const char *oldname, const char *newname);
+
+	/**
+	 * @brief					Open file
+	 * @details					A file must be opened before it can be accessed
+	 * @details					The resulting GFILE will be used for all functions that access the file.
+	 *
+	 * @param[in] fname			The file name
+	 * @param[in] mode			The mode.
+	 *
+	 * @return					Valid GFILE on success, 0 otherwise
+	 *
+	 * @note					The modes follow the c library fopen() standard.
+	 * 							The valid modes are:
+	 * 							<ul><li>r   - Open for read, the file must exist</li>
+	 * 								<li>w   - Open for write, the file is truncated if it exists</li>
+	 * 								<li>wx  - Open for write, the file must not exist</li>
+	 * 								<li>a   - Open for append, the file is truncated if it exists</li>
+	 * 								<li>ax  - Open for append, the file must not exists</li>
+	 * 							</ul>
+	 * 							The following flags can also be added to the above modes:<br/>
+	 * 							<ul><li>+   - Open for both read and write</li>
+	 * 								<li>b   - Open as a binary file rather than a text file</li>
+	 * 							</ul>
+	 * @note					Not all file-systems support all modes. For example, write
+	 * 							is not available with the ROM file-system. Similarly few platforms
+	 * 							distinguish between binary and text files.
+	 * @note					Even though binary vs. text is relevant only for a small number of platforms
+	 * 							the "b" flag should always be specified for binary files such as images.
+	 * 							This ensures portability to other platforms. The extra flag will be ignored
+	 * 							on platforms where it is not relevant.
+	 *
+	 * @api
+	 */	
+	GFILE *		gfileOpen(const char *fname, const char *mode);
+
+	/**
+	 * @brief					Close file
+	 * @details					Closes a file after is has been opened using @p gfileOpen()
+	 *
+	 * @param[in] f				The file
+	 *
+	 * @api
+	 */
+	void		gfileClose(GFILE *f);
+
+	/**
+	 * @brief					Read from file
+	 * @details					Reads a given amount of bytes from the file
+	 * @details					The read/write cursor will not be reset when calling this function
+	 *
+	 * @param[in] f				The file
+	 * @param[out] buf			The buffer in which to save the content that has been read from the file
+	 * @param[in] len			Amount of bytes to read
+	 *
+	 * @return					Amount of bytes read
+	 *
+	 * @api
+	 */
+	size_t		gfileRead(GFILE *f, void *buf, size_t len);
+
+	/**
+	 * @brief					Write to file
+	 * @details					Write a given amount of bytes to the file
+	 * @details					The read/write cursor will not be reset when calling this function
+	 *
+	 * @param[in] f				The file
+	 * @param[in] buf			The buffer which contains the content that will be written to the file
+	 * @param[in] len			Amount of bytes to write
+	 *
+	 * @return					Amount of bytes written
+	 *
+	 * @api
+	 */
+	size_t		gfileWrite(GFILE *f, const void *buf, size_t len);
+
+	/**
+	 * @brief					Get the current position of the read/write cursor
+	 *
+	 * @param[in] f				The file
+	 *
+	 * @return					The current position in the file
+	 *
+	 * @api
+	 */
+	long int	gfileGetPos(GFILE *f);
+
+	/**
+	 * @brief					Set the position of the read/write cursor
+	 *
+	 * @param[in] f				The file
+	 * @param[in] pos			The position to which the cursor will be set
+	 *
+	 * @return					TRUE on success, FALSE otherwise
+	 *
+	 * @api
+	 */
+	bool_t		gfileSetPos(GFILE *f, long int pos);
+
+	/**
+	 * @brief					Get the size of file
+	 * @note					Please use @p gfileGetFilesize() if the file is not opened
+	 *
+	 * @param[in] f				The file
+	 *
+	 * @return					The size of the file
+	 *
+	 * @api
+	 */
+	long int	gfileGetSize(GFILE *f);
+
+	/**
+	 * @brief					Check for EOF
+	 * @details					Checks if the cursor is at the end of the file
+	 *
+	 * @param[in] f				The file
+	 *
+	 * @return					TRUE if EOF, FALSE otherwise
+	 *
+	 * @api
+	 */
+	bool_t		gfileEOF(GFILE *f);
+
+	/**
+	 * @brief					Mount a logical drive (aka partition)
+	 *
+	 * @details					Not supported by every file system
+	 * @details					Currently just one drive at one is supported.
+	 *
+	 * @param[in] fs			The file system (F for FatFS)
+	 * @param[in] drive			The logical drive prefix
+	 *
+	 * @return					TRUE on success, FALSE otherwise
+	 *
+	 * @api
+	 */
+	bool_t gfileMount(char fs, const char *drive);
+
+	/**
+	 * @brief					Unmount a logical drive (aka partition)
+	 *
+	 * @details					Does have no effect if @p gfileMount() as been called before hand
+	 *
+	 * @param[in] fs			The file system (F for FatFS)
+	 * @param[in] drive			The logical drive prefix
+	 *
+	 * @return					TRUE on success, FALSE otherwise
+	 *
+	 * @api
+	 */
+	bool_t gfileUnmount(char fs, const char *drive);
+
+	/**
+	 * @brief					Syncs the file object (flushes the buffer)
+	 *
+	 * @details					Not supported by every file system
+	 *
+	 * @param[in] f				The file
+	 *
+	 * @return					TRUE on success, FALSE otherwise
+	 *
+	 * @api
+	 */
+	bool_t gfileSync(GFILE *f);
+
+	#if GFILE_NEED_FILELISTS || defined(__DOXYGEN__)
+		/**
+		 * @brief				Open a file list
+		 *
+		 * @param[in] fs		The file system (F for FatFS)
+		 * @param[in] path		Path information to pass to the file system
+		 * @param[in] dirs		Pass TRUE to get directories only, FALSE to get files only
+		 *
+		 * @return				A pointer to a file list on success, NULL otherwise
+		 *
+		 * @note				The path parameter is handled in a file-system specific way. It could be
+		 * 						treated as a directory name, it may be treated as a file pattern, or it
+		 * 						may be ignored. Passing NULL will always return the full list of files
+		 * 						in at least the top level directory.
+		 * @note				For file systems that do not support directories, passing TRUE for dirs
+		 * 						will return an error.
+		 * @note				You must call @p gfileCloseFileList() when you have finished with the
+		 * 						file list in order to free resources.
+		 *
+		 * @api
+		 */
+		gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs);
+
+		/**
+		 * @brief				Get the next file in a file list.
+		 *
+		 * @param[in] pfl		Pointer to a file list returned by @p gfileOpenFileList()
+		 *
+		 * @return				A pointer to a file (or directory) name. Returns NULL if there are no more.
+		 *
+		 * @note				The file name may contain the full directory path or may not depending
+		 * 						on how the file system treats directories.
+		 * @note				The returned buffer may be destroyed by the next call to any of
+		 * 						@p gfileOpenFileList(), @p gfileReadFileList() or @p gfileCloseFileList().
+		 * 						Do not use this pointer after one of those calls.
+		 *
+		 * @api
+		 */
+		const char *gfileReadFileList(gfileList *pfl);
+
+		/**
+		 * @brief				Close a file list.
+		 *
+		 * @param[in] pfl		Pointer to a file list returned by @p gfileOpenFileList()
+		 *
+		 * @api
+		 */
+		void gfileCloseFileList(gfileList *pfl);
+	#endif
+
+	#if (GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS) || defined(__DOXYGEN__)
+		/**
+		 * @brief					Open file from a ChibiOS BaseFileStream
+		 *
+		 * @param[in] BaseFileStreamPtr	The BaseFileStream to open as a GFILE
+		 * @param[in] mode			The mode.
+		 *
+		 * @return					Valid GFILE on success, 0 otherwise
+		 *
+		 * @note					The modes are the same modes as in @p gfileOpen(). The
+		 * 							open mode is NOT compared against the BaseFileStream capabilities.
+		 * @note					Supported operations are: read, write, getpos, setpos, eof and getsize
+		 *
+		 * @api
+		 */
+		GFILE *		gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode);
+	#endif
+
+	#if GFILE_NEED_MEMFS || defined(__DOXYGEN__)
+		/**
+		 * @brief					Open file from a memory pointer
+		 *
+		 * @param[in] memptr		The pointer to the memory
+		 * @param[in] mode			The mode.
+		 *
+		 * @return					Valid GFILE on success, 0 otherwise
+		 *
+		 * @note					The modes are the same modes as in @p gfileOpen(). Note there is
+		 * 							no concept of file-size. Be careful not to overwrite other memory or
+		 * 							to read from inaccessible sections of memory.
+		 * @note					Supported operations are: read, write, getpos, setpos
+		 *
+		 * @api
+		 */
+		GFILE *		gfileOpenMemory(void *memptr, const char *mode);
+	#endif
+
+	#if GFILE_NEED_STRINGS || defined(__DOXYGEN__)
+		/**
+		 * @brief					Open file from a null terminated C string
+		 *
+		 * @param[in] str			The pointer to the string or string buffer
+		 * @param[in] mode			The mode
+		 *
+		 * @return					Valid GFILE on success, 0 otherwise
+		 *
+		 * @note					The modes are the same modes as in @p gfileOpen(). Note there is
+		 * 							no concept of file-size. Be careful not to overwrite other memory or
+		 * 							to read from inaccessible sections of memory.
+		 * @note					Reading will return EOF when the NULL character is reached.
+		 * @note					Writing will always place a NULL in the next character effectively terminating the
+		 * 							string at the character just written.
+		 * @note					Supported operations are: read, write, append, getpos, setpos
+		 * @note					Be careful with setpos and getpos. They do not check for the end of the string.
+		 * @note					Reading and Writing will read/write a maximum of one character at a time.
+		 *
+		 * @api
+		 */
+		GFILE *		gfileOpenString(char *str, const char *mode);
+	#endif
+
+	#if GFILE_NEED_PRINTG || defined(__DOXYGEN__)
+		#include <stdarg.h>
+
+		int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg);
+		int fnprintg(GFILE *f, int maxlen, const char *fmt, ...);
+		#define vfprintg(f,m,a)			vfnprintg(f,0,m,a)
+		#define fprintg(f,m,...)		fnprintg(f,0,m,...)
+		#define vprintg(m,a)			vfnprintg(gfileStdOut,0,m,a)
+		#define printg(m,...)			fnprintg(gfileStdOut,0,m,...)
+
+		#if GFILE_NEED_STRINGS
+			int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg);
+			int snprintg(char *buf, int maxlen, const char *fmt, ...);
+			#define vsprintg(s,m,a)		vsnprintg(s,0,m,a)
+			#define sprintg(s,m,...)	snprintg(s,0,m,...)
+		#endif
+	#endif
+
+	#if GFILE_NEED_SCANG || defined(__DOXYGEN__)
+		#include <stdarg.h>
+
+		int vfscang(GFILE *f, const char *fmt, va_list arg);
+		int fscang(GFILE *f, const char *fmt, ...);
+		#define vscang(f,a)			vfscang(gfileStdIn,f,a)
+		#define scang(f,...)		fscang(gfileStdIn,f,...)
+
+		#if GFILE_NEED_STRINGS
+			int vsscang(const char *buf, const char *fmt, va_list arg);
+			int sscang(const char *buf, const char *fmt, ...);
+		#endif
+	#endif
+
+	#if GFILE_NEED_STDIO && !defined(GFILE_IMPLEMENTATION)
+		#define stdin					gfileStdIn
+		#define stdout					gfileStdOut
+		#define stderr					gfileStdErr
+		#define FILENAME_MAX			256						// Use a relatively small number for an embedded platform
+		#define L_tmpnam				FILENAME_MAX
+		#define FOPEN_MAX				GFILE_MAX_GFILES
+		#define TMP_MAX					GFILE_MAX_GFILES
+		#define P_tmpdir				"/tmp/"
+		#define FILE					GFILE
+		#define fopen(n,m)				gfileOpen(n,m)
+		#define fclose(f)				gfileClose(f)
+		size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f);
+		size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f);
+		#define fread(p,sz,cnt,f)		gstdioRead(p,sz,cnt,f)
+		#define fwrite(p,sz,cnt,f)		gstdioWrite(p,sz,cnt,f)
+		int gstdioSeek(FILE *f, size_t offset, int origin);
+		#define fseek(f,ofs,org)		gstdioSeek(f,ofs,org)
+			#define SEEK_SET	0
+			#define SEEK_CUR	1
+			#define SEEK_END	2
+		#define remove(n)				(!gfileDelete(n))
+		#define rename(o,n)				(!gfileRename(o,n))
+		#define fflush(f)				(0)
+		#define ftell(f)				gfileGetPos(f)
+		#define fpos_t					long int
+		int gstdioGetpos(FILE *f, long int *pos);
+		#define fgetpos(f,pos)			gstdioGetpos(f,pos)
+		#define fsetpos(f, pos)			(!gfileSetPos(f, *pos))
+		#define rewind(f)				gfileSetPos(f, 0);
+		#define feof(f)					gfileEOF(f)
+
+		#define vfprintf(f,m,a)			vfnprintg(f,0,m,a)
+		#define fprintf(f,m,...)		fnprintg(f,0,m,...)
+		#define vprintf(m,a)			vfnprintg(gfileStdOut,0,m,a)
+		#define printf(m,...)			fnprintg(gfileStdOut,0,m,...)
+		#define vsnprintf(s,n,m,a)		vsnprintg(s,n,m,a)
+		#define snprintf(s,n,m,...)		snprintg(s,n,m,...)
+		#define vsprintf(s,m,a)			vsnprintg(s,0,m,a)
+		#define sprintf(s,m,...)		snprintg(s,0,m,...)
+		//TODO
+		//void clearerr ( FILE * stream );
+		//int ferror ( FILE * stream );
+		//FILE * tmpfile ( void );		// Auto-deleting
+		//char * tmpnam ( char * str );
+		//char * mktemp (char *template);
+		//FILE * freopen ( const char * filename, const char * mode, FILE * stream );
+		//setbuf
+		//setvbuf
+		//fflush
+		//fgetc
+		//fgets
+		//fputc
+		//fputs
+		//getc
+		//getchar
+		//puts
+		//ungetc
+		//void perror (const char * str);
+	#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GFILE */
+
+#endif /* _GFILE_H */
+/** @} */
+
diff --git a/src/gfile/gfile.mk b/src/gfile/gfile.mk
new file mode 100644
index 00000000..8f20b5ce
--- /dev/null
+++ b/src/gfile/gfile.mk
@@ -0,0 +1,18 @@
+GFXSRC +=   $(GFXLIB)/src/gfile/gfile.c \
+            $(GFXLIB)/src/gfile/gfile_fs_native.c \
+            $(GFXLIB)/src/gfile/gfile_fs_ram.c \
+            $(GFXLIB)/src/gfile/gfile_fs_rom.c \
+            $(GFXLIB)/src/gfile/gfile_fs_fatfs.c \
+            $(GFXLIB)/src/gfile/gfile_fs_petitfs.c \
+            $(GFXLIB)/src/gfile/gfile_fs_mem.c \
+            $(GFXLIB)/src/gfile/gfile_fs_chibios.c \
+            $(GFXLIB)/src/gfile/gfile_fs_strings.c \
+            $(GFXLIB)/src/gfile/gfile_printg.c \
+            $(GFXLIB)/src/gfile/gfile_scang.c \
+            $(GFXLIB)/src/gfile/gfile_stdio.c \
+            $(GFXLIB)/src/gfile/gfile_fatfs_wrapper.c \
+            $(GFXLIB)/src/gfile/gfile_fatfs_diskio_chibios.c \
+            $(GFXLIB)/src/gfile/gfile_petitfs_wrapper.c \
+            $(GFXLIB)/src/gfile/gfile_petitfs_diskio_chibios.c \
+
+            
\ No newline at end of file
diff --git a/src/gfile/gfile_fatfs_diskio_chibios.c b/src/gfile/gfile_fatfs_diskio_chibios.c
index 46ddbb7e..319d1a86 100644
--- a/src/gfile/gfile_fatfs_diskio_chibios.c
+++ b/src/gfile/gfile_fatfs_diskio_chibios.c
@@ -5,12 +5,6 @@
 /* disk I/O modules and attach it to FatFs module with common interface. */
 /*-----------------------------------------------------------------------*/
 
-/**
- * @file    src/gfile/gfile_fatfs_diskio_chibios.c
- * @brief   GFILE FATFS wrapper.
- *
- */
-
 #include "gfx.h"
 
 #if GFX_USE_GFILE && GFILE_NEED_FATFS && GFX_USE_OS_CHIBIOS
diff --git a/src/gfile/gfile_fatfs_wrapper.c b/src/gfile/gfile_fatfs_wrapper.c
index edcab056..fb5e6ec2 100644
--- a/src/gfile/gfile_fatfs_wrapper.c
+++ b/src/gfile/gfile_fatfs_wrapper.c
@@ -5,12 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gfile/gfile_fatfs_wrapper.c
- * @brief   GFILE FATFS wrapper.
- *
- */
-
 #include "gfx.h"
 
 #if GFX_USE_GFILE && GFILE_NEED_FATFS
diff --git a/src/gfile/gfile_gfile.c b/src/gfile/gfile_gfile.c
deleted file mode 100644
index 3547f861..00000000
--- a/src/gfile/gfile_gfile.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gfile/gfile_gfile.c
- * @brief   GFILE code.
- *
- */
-
-#include "gfx.h"
-
-#if GFX_USE_GFILE
-
-#include "gfile_fs.h"
-
-/**
- * Define the VMT's for the file-systems we want to search for files.
- * Virtual file-systems that have special open() calls do not need to
- * be in this list.
- */
-#if GFILE_NEED_ROMFS
-	extern const GFILEVMT FsROMVMT;
-#endif
-#if GFILE_NEED_NATIVEFS
-	extern const GFILEVMT FsNativeVMT;
-#endif
-#if GFILE_NEED_FATFS
-	extern const GFILEVMT FsFatFSVMT;
-#endif
-#if GFILE_NEED_RAMFS
-	extern const GFILEVMT FsRAMVMT;
-#endif
-
-
-/**
- * The order of the file-systems below determines the order
- * that they are searched to find a file.
- */
-static const GFILEVMT const * FsArray[] = {
-	#if GFILE_NEED_ROMFS
-		&FsROMVMT,
-	#endif
-	#if GFILE_NEED_NATIVEFS
-		&FsNativeVMT,
-	#endif
-	#if GFILE_NEED_FATFS
-		&FsFatFSVMT,
-	#endif
-	#if GFILE_NEED_RAMFS
-		&FsRAMVMT,
-	#endif
-};
-
-/*
- * The table of GFILE's
- */
-static GFILE gfileArr[GFILE_MAX_GFILES];
-GFILE *gfileStdIn;
-GFILE *gfileStdOut;
-GFILE *gfileStdErr;
-
-/**
- * The init routine
- */
-void _gfileInit(void) {
-	#if GFILE_NEED_NATIVEFS
-		extern void _gfileNativeAssignStdio(void);
-		_gfileNativeAssignStdio();
-	#endif
-}
-
-void _gfileDeinit(void)
-{
-	/* ToDo */
-}
-
-/**
- * Internal routine to find an empty GFILE slot and interpret flags.
- */
-GFILE *_gfileFindSlot(const char *mode) {
-	GFILE *			f;
-
-	// First find an available GFILE slot.
-	for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
-		if (!(f->flags & GFILEFLG_OPEN)) {
-			// Get the flags
-			switch(mode[0]) {
-			case 'r':
-				f->flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST;
-				while (*++mode) {
-					switch(mode[0]) {
-					case '+':	f->flags |= GFILEFLG_WRITE;			break;
-					case 'b':	f->flags |= GFILEFLG_BINARY;		break;
-					}
-				}
-				break;
-			case 'w':
-				f->flags = GFILEFLG_WRITE|GFILEFLG_TRUNC;
-				while (*++mode) {
-					switch(mode[0]) {
-					case '+':	f->flags |= GFILEFLG_READ;			break;
-					case 'b':	f->flags |= GFILEFLG_BINARY;		break;
-					case 'x':	f->flags |= GFILEFLG_MUSTNOTEXIST;	break;
-					}
-				}
-				break;
-			case 'a':
-				f->flags = GFILEFLG_WRITE|GFILEFLG_APPEND;
-				while (*++mode) {
-					switch(mode[0]) {
-					case '+':	f->flags |= GFILEFLG_READ;			break;
-					case 'b':	f->flags |= GFILEFLG_BINARY;		break;
-					case 'x':	f->flags |= GFILEFLG_MUSTNOTEXIST;	break;
-					}
-				}
-				break;
-			default:
-				return 0;
-			}
-			return f;
-		}
-	}
-	return 0;
-}
-
-/********************************************************
- * IO routines
- ********************************************************/
-
-bool_t gfileExists(const char *fname) {
-	const GFILEVMT * const *p;
-
-	#if GFILE_ALLOW_DEVICESPECIFIC
-		if (fname[0] && fname[1] == '|') {
-			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-				if (p[0]->prefix == fname[0])
-					return p[0]->exists && p[0]->exists(fname+2);
-			}
-			return FALSE;
-		}
-	#endif
-
-	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-		if (p[0]->exists && p[0]->exists(fname))
-			return TRUE;
-	}
-	return FALSE;
-}
-
-bool_t gfileDelete(const char *fname) {
-	const GFILEVMT **p;
-
-	#if GFILE_ALLOW_DEVICESPECIFIC
-		if (fname[0] && fname[1] == '|') {
-			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-				if (p[0]->prefix == fname[0])
-					return p[0]->del && p[0]->del(fname+2);
-			}
-			return FALSE;
-		}
-	#endif
-
-	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-		if (p[0]->del && p[0]->del(fname))
-			return TRUE;
-	}
-	return FALSE;
-}
-
-long int gfileGetFilesize(const char *fname) {
-	const GFILEVMT * const *p;
-	long int res;
-
-	#if GFILE_ALLOW_DEVICESPECIFIC
-		if (fname[0] && fname[1] == '|') {
-			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-				if (p[0]->prefix == fname[0])
-					return p[0]->filesize ? p[0]->filesize(fname+2) : -1;
-			}
-			return -1;
-		}
-	#endif
-
-	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-		if (p[0]->filesize && (res = p[0]->filesize(fname)) != -1)
-			return res;
-	}
-	return -1;
-}
-
-bool_t gfileRename(const char *oldname, const char *newname) {
-	const GFILEVMT * const *p;
-
-	#if GFILE_ALLOW_DEVICESPECIFIC
-		if ((oldname[0] && oldname[1] == '|') || (newname[0] && newname[1] == '|')) {
-			char ch;
-
-			if (oldname[0] && oldname[1] == '|') {
-				ch = oldname[0];
-				oldname += 2;
-				if (newname[0] && newname[1] == '|') {
-					if (newname[0] != ch)
-						// Both oldname and newname are fs specific but different ones.
-						return FALSE;
-					newname += 2;
-				}
-			} else {
-				ch = newname[0];
-				newname += 2;
-			}
-			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-				if (p[0]->prefix == ch)
-					return p[0]->ren && p[0]->ren(oldname, newname);
-			}
-			return FALSE;
-		}
-	#endif
-
-	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-		if (p[0]->ren && p[0]->ren(oldname,newname))
-			return TRUE;
-	}
-	return FALSE;
-}
-
-static bool_t testopen(const GFILEVMT *p, GFILE *f, const char *fname) {
-	// If we want write but the fs doesn't allow it then return
-	if ((f->flags & GFILEFLG_WRITE) && !(p->flags & GFSFLG_WRITEABLE))
-		return FALSE;
-
-	// Try to open
-	if (!p->open || !p->open(f, fname))
-		return FALSE;
-
-	// File is open - fill in all the details
-	f->vmt = p;
-	f->pos = 0;
-	f->flags |= GFILEFLG_OPEN;
-	if (p->flags & GFSFLG_SEEKABLE)
-		f->flags |= GFILEFLG_CANSEEK;
-	return TRUE;
-}
-
-GFILE *gfileOpen(const char *fname, const char *mode) {
-	GFILE *			f;
-	const GFILEVMT * const *p;
-
-	// Get an empty file and set the flags
-	if (!(f = _gfileFindSlot(mode)))
-		return 0;
-
-	#if GFILE_ALLOW_DEVICESPECIFIC
-		if (fname[0] && fname[1] == '|') {
-			for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-				if (p[0]->prefix == fname[0])
-					return testopen(p[0], f, fname+2) ? f : 0;
-			}
-
-			// File not found
-			return 0;
-		}
-	#endif
-
-	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-		if (testopen(p[0], f, fname))
-			return f;
-	}
-
-	// File not found
-	return 0;
-}
-
-void gfileClose(GFILE *f) {
-	if (!f || !(f->flags & GFILEFLG_OPEN))
-		return;
-	if (f->vmt->close)
-		f->vmt->close(f);
-	f->flags = 0;
-}
-
-size_t gfileRead(GFILE *f, void *buf, size_t len) {
-	size_t	res;
-
-	if (!f || (f->flags & (GFILEFLG_OPEN|GFILEFLG_READ)) != (GFILEFLG_OPEN|GFILEFLG_READ))
-		return 0;
-	if (!f->vmt->read)
-		return 0;
-	if ((res = f->vmt->read(f, buf, len)) <= 0)
-		return 0;
-	f->pos += res;
-	return res;
-}
-
-size_t gfileWrite(GFILE *f, const void *buf, size_t len) {
-	size_t	res;
-
-	if (!f || (f->flags & (GFILEFLG_OPEN|GFILEFLG_WRITE)) != (GFILEFLG_OPEN|GFILEFLG_WRITE))
-		return 0;
-	if (!f->vmt->write)
-		return 0;
-	if ((res = f->vmt->write(f, buf, len)) <= 0)
-		return 0;
-	f->pos += res;
-	return res;
-}
-
-long int gfileGetPos(GFILE *f) {
-	if (!f || !(f->flags & GFILEFLG_OPEN))
-		return 0;
-	return f->pos;
-}
-
-bool_t gfileSetPos(GFILE *f, long int pos) {
-	if (!f || !(f->flags & GFILEFLG_OPEN))
-		return FALSE;
-	if (!f->vmt->setpos || !f->vmt->setpos(f, pos))
-		return FALSE;
-	f->pos = pos;
-	return TRUE;
-}
-
-long int gfileGetSize(GFILE *f) {
-	if (!f || !(f->flags & GFILEFLG_OPEN))
-		return 0;
-	if (!f->vmt->getsize)
-		return 0;
-	return f->vmt->getsize(f);
-}
-
-bool_t gfileEOF(GFILE *f) {
-	if (!f || !(f->flags & GFILEFLG_OPEN))
-		return TRUE;
-	if (!f->vmt->eof)
-		return FALSE;
-	return f->vmt->eof(f);
-}
-
-bool_t gfileMount(char fs, const char* drive) {
-	const GFILEVMT * const *p;
-
-	// Find the correct VMT
-	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-		if (p[0]->prefix == fs) {
-			if (!p[0]->mount)
-				return FALSE;
-			return p[0]->mount(drive);
-		}
-	}
-	return FALSE;
-}
-
-bool_t gfileUnmount(char fs, const char* drive) {
-	const GFILEVMT * const *p;
-
-	// Find the correct VMT
-	for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-		if (p[0]->prefix == fs) {
-			if (!p[0]->mount)
-				return FALSE;
-			return p[0]->unmount(drive);
-		}
-	}
-	return FALSE;
-}
-
-bool_t gfileSync(GFILE *f) {
-	if (!f->vmt->sync)
-		return FALSE;
-	return f->vmt->sync(f);
-}
-
-#if GFILE_NEED_FILELISTS
-	gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs) {
-		const GFILEVMT * const *p;
-		gfileList *		pfl;
-
-		// Find the correct VMT
-		for(p = FsArray; p < &FsArray[sizeof(FsArray)/sizeof(FsArray[0])]; p++) {
-			if (p[0]->prefix == fs) {
-				if (!p[0]->flopen)
-					return 0;
-				pfl = p[0]->flopen(path, dirs);
-				if (pfl) {
-					pfl->vmt = p[0];
-					pfl->dirs = dirs;
-				}
-				return pfl;
-			}
-		}
-		return 0;
-	}
-
-	const char *gfileReadFileList(gfileList *pfl) {
-		return pfl->vmt->flread ? pfl->vmt->flread(pfl) : 0;
-	}
-
-	void gfileCloseFileList(gfileList *pfl) {
-		if (pfl->vmt->flclose)
-			pfl->vmt->flclose(pfl);
-	}
-#endif
-
-#endif /* GFX_USE_GFILE */
diff --git a/src/gfile/gfile_options.h b/src/gfile/gfile_options.h
new file mode 100644
index 00000000..06781f38
--- /dev/null
+++ b/src/gfile/gfile_options.h
@@ -0,0 +1,207 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gfile/gfile_options.h
+ * @brief   GFILE - File IO options header file.
+ *
+ * @addtogroup GFILE
+ * @{
+ */
+
+#ifndef _GFILE_OPTIONS_H
+#define _GFILE_OPTIONS_H
+
+/**
+ * @name    GFILE Functionality to be included
+ * @{
+ */
+	/**
+	 * @brief	Should the filesystem not be mounted automatically
+	 * @details	The filesystem is normally mounted automatically if the
+	 *			user does not do it manually. This option turns that off
+	 *			so the user must manually mount the file-system first.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFILE_NEED_NOAUTOMOUNT
+		#define GFILE_NEED_NOAUTOMOUNT	FALSE
+	#endif
+	/**
+	 * @brief	Should the filesystem be synced automatically
+	 * @details	The filesystem will automatically be synced after an open() or
+	 *			write() call unless this feature is disabled.
+	 * @details	If this feature is disabled, the user should sync the filesystem
+	 *			himself using @p gfileSync()
+	 * @details	Not all filesystems implement the syncing feature. This feature will
+	 *			have no effect in such a case.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFILE_NEED_NOAUTOSYNC
+		#define GFILE_NEED_NOAUTOSYNC	FALSE
+	#endif
+	/**
+	 * @brief   Include printg, fprintg etc functions
+	 * @details	Defaults to FALSE
+	 * @pre		To get the string sprintg functions you also need to define @p GFILE_NEED_STRINGS
+	 */
+	#ifndef GFILE_NEED_PRINTG
+		#define GFILE_NEED_PRINTG		FALSE
+	#endif
+	/**
+	 * @brief   Include scang, fscang etc functions
+	 * @details	Defaults to FALSE
+	 * @pre		To get the string sscang functions you also need to define @p GFILE_NEED_STRINGS
+	 */
+	#ifndef GFILE_NEED_SCANG
+		#define GFILE_NEED_SCANG		FALSE
+	#endif
+	/**
+	 * @brief   Include the string based file functions
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFILE_NEED_STRINGS
+		#define GFILE_NEED_STRINGS		FALSE
+	#endif
+	/**
+	 * @brief   Map many stdio functions to their GFILE equivalent
+	 * @details	Defaults to FALSE
+	 * @note	This replaces the functions in stdio.h with equivalents
+	 * 			- Do not include stdio.h as it has different conflicting definitions.
+	 */
+	#ifndef GFILE_NEED_STDIO
+		#define GFILE_NEED_STDIO		FALSE
+	#endif
+	/**
+	 * @brief   Include the ROM file system
+	 * @details	Defaults to FALSE
+	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+	 * 			opening a file on the ROM file system by prefixing
+	 * 			its name with "S|" (the letter 'S', followed by a vertical bar).
+	 * @note	This requires a file called romfs_files.h to be in the
+	 * 			users project include path. This file should include all the files
+	 * 			converted to .h files using the file2c utility (using flags "-dbcs").
+	 */
+	#ifndef GFILE_NEED_ROMFS
+		#define GFILE_NEED_ROMFS		FALSE
+	#endif
+	/**
+	 * @brief   Include the RAM file system
+	 * @details	Defaults to FALSE
+	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+	 * 			opening a file on the RAM file system by prefixing
+	 * 			its name with "R|" (the letter 'R', followed by a vertical bar).
+	 * @note	You must also define GFILE_RAMFS_SIZE with the size of the file system
+	 * 			to be allocated in RAM.
+	 */
+	#ifndef GFILE_NEED_RAMFS
+		#define GFILE_NEED_RAMFS		FALSE
+	#endif
+	/**
+	 * @brief   Include the FAT file system driver based on the FATFS library
+	 * @details	Defaults to FALSE
+	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+	 * 			opening a file on the FAT file system by prefixing
+	 * 			its name with "F|" (the letter 'F', followed by a vertical bar).
+	 * @note	FATFS and PETITFS offer the same FAT file system support. They just use
+	 * 			different constraints. PETITFS is smaller but has less features. Only
+	 * 			one can be used at a time. The block interfaces are also different.
+	 */
+	#ifndef GFILE_NEED_FATFS
+		#define GFILE_NEED_FATFS		FALSE
+	#endif
+	/**
+	 * @brief   Include the FAT file system driver based on the PETITFS library
+	 * @details	Defaults to FALSE
+	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+	 * 			opening a file on the FAT file system by prefixing
+	 * 			its name with "F|" (the letter 'F', followed by a vertical bar).
+	 * @note	FATFS and PETITFS offer the same FAT file system support. They just use
+	 * 			different constraints. PETITFS is smaller but has less features. Only
+	 * 			one can be used at a time. The block interfaces are also different.
+	 * @note	Due to the restrictions on the PETITFS library on writing, we do not implement
+	 * 			writing.
+	 * @note	PETITFS can only have one file open at a time.
+	 */
+	#ifndef GFILE_NEED_PETITFS
+		#define GFILE_NEED_PETITFS		FALSE
+	#endif
+	/**
+	 * @brief   Include the operating system's native file system
+	 * @details	Defaults to FALSE
+	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
+	 * 			opening a file on the native file system by prefixing
+	 * 			its name with "N|" (the letter 'N', followed by a vertical bar).
+	 * @note	If defined then the gfileStdOut and gfileStdErr handles
+	 * 			use the operating system equivalent stdio and stderr.
+	 * 			If it is not defined the gfileStdOut and gfileStdErr io is discarded.
+	 */
+	#ifndef GFILE_NEED_NATIVEFS
+		#define GFILE_NEED_NATIVEFS		FALSE
+	#endif
+	/**
+	 * @brief   Include ChibiOS BaseFileStream support
+	 * @details	Defaults to FALSE
+	 * @pre		This is only relevant on the ChibiOS operating system.
+	 * @note	Use the @p gfileOpenBaseFileStream() call to open a GFILE based on a
+	 * 			BaseFileStream. The BaseFileStream must already be open.
+	 * @note	A GFile of this type cannot be opened by filename. The BaseFileStream
+	 * 			must be pre-opened using the operating system.
+	 */
+	#ifndef GFILE_NEED_CHIBIOSFS
+		#define GFILE_NEED_CHIBIOSFS	FALSE
+	#endif
+	/**
+	 * @brief   Include raw memory pointer support
+	 * @details	Defaults to FALSE
+	 * @note	Use the @p gfileOpenMemory() call to open a GFILE based on a
+	 * 			memory pointer. The GFILE opened appears to be of unlimited size.
+	 * @note	A GFile of this type cannot be opened by filename.
+	 */
+	#ifndef GFILE_NEED_MEMFS
+		#define GFILE_NEED_MEMFS		FALSE
+	#endif
+	/**
+	 * @brief   Include support for file list functions
+	 * @details	Defaults to FALSE
+	 * @note	Adds support for @p gfileOpenFileList(), @p gfileReadFileList() and @p gfileCloseFileList().
+	 */
+	#ifndef GFILE_NEED_FILELISTS
+		#define GFILE_NEED_FILELISTS	FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GFILE Optional Parameters
+ * @{
+ */
+	/**
+	 * @brief  Add floating point support to printg/scang etc.
+	 */
+	#ifndef GFILE_ALLOW_FLOATS
+		#define GFILE_ALLOW_FLOATS	FALSE
+	#endif
+	/**
+	 * @brief   Can the device be specified as part of the file name.
+	 * @note	If this is on then a device letter and a vertical bar can be
+	 * 			prefixed on a file name to specify that it must be on a
+	 * 			specific device.
+	 */
+	#ifndef GFILE_ALLOW_DEVICESPECIFIC
+		#define GFILE_ALLOW_DEVICESPECIFIC		FALSE
+	#endif
+	/**
+	 * @brief   The maximum number of open files
+	 * @note	This count excludes gfileStdIn, gfileStdOut and gfileStdErr
+	 * 			(if open by default).
+	 */
+	#ifndef GFILE_MAX_GFILES
+		#define GFILE_MAX_GFILES		3
+	#endif
+/** @} */
+
+#endif /* _GFILE_OPTIONS_H */
+/** @} */
diff --git a/src/gfile/gfile_petitfs_diskio_chibios.c b/src/gfile/gfile_petitfs_diskio_chibios.c
index 90e709e4..7aa236ba 100644
--- a/src/gfile/gfile_petitfs_diskio_chibios.c
+++ b/src/gfile/gfile_petitfs_diskio_chibios.c
@@ -5,12 +5,6 @@
 /* disk I/O modules and attach it to FatFs module with common interface. */
 /*-----------------------------------------------------------------------*/
 
-/**
- * @file    src/gfile/gfile_petitfs_diskio_chibios.c
- * @brief   GFILE FATFS wrapper.
- *
- */
-
 #include "gfx.h"
 
 #if GFX_USE_GFILE && GFILE_NEED_PETITFS && GFX_USE_OS_CHIBIOS
diff --git a/src/gfile/gfile_petitfs_wrapper.c b/src/gfile/gfile_petitfs_wrapper.c
index 8efc7eb9..b7bc0ee1 100644
--- a/src/gfile/gfile_petitfs_wrapper.c
+++ b/src/gfile/gfile_petitfs_wrapper.c
@@ -5,12 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gfile/gfile_petitfs_wrapper.c
- * @brief   GFILE PETITFS wrapper.
- *
- */
-
 #include "gfx.h"
 
 #if GFX_USE_GFILE && GFILE_NEED_PETITFS
diff --git a/src/gfile/gfile_rules.h b/src/gfile/gfile_rules.h
new file mode 100644
index 00000000..949a500c
--- /dev/null
+++ b/src/gfile/gfile_rules.h
@@ -0,0 +1,26 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gfile/gfile_rules.h
+ * @brief   GFILE safety rules header file.
+ *
+ * @addtogroup GFILE
+ * @{
+ */
+
+#ifndef _GFILE_RULES_H
+#define _GFILE_RULES_H
+
+#if GFX_USE_GFILE
+	#if GFILE_NEED_PETITFS && GFILE_NEED_FATFS
+		#error "GFILE: Both GFILE_NEED_PETITFS and GFILE_NEED_FATFS cannot both be turned on at the same time."
+	#endif
+#endif
+
+#endif /* _GFILE_RULES_H */
+/** @} */
diff --git a/src/gfile/sys_defs.h b/src/gfile/sys_defs.h
deleted file mode 100644
index 2c475b40..00000000
--- a/src/gfile/sys_defs.h
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gfile/sys_defs.h
- * @brief   GFILE - File IO Routines header file.
- *
- * @addtogroup GFILE
- *
- * @brief	Module which contains Operating system independent FILEIO
- *
- * @{
- */
-
-#ifndef _GFILE_H
-#define _GFILE_H
-
-#include "gfx.h"
-
-#if GFX_USE_GFILE || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-/**
- * @brief	A file pointer
- */
-
-typedef struct GFILE GFILE;
-typedef struct gfileList gfileList;
-
-extern GFILE *gfileStdIn;
-extern GFILE *gfileStdErr;
-extern GFILE *gfileStdOut;
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-	/**
-	 * @brief					Check if file exists
-	 * 
-	 * @param[in] fname			The file name
-	 * 
-	 * @return					TRUE if file exists, FALSE otherwise
-	 * 
-	 * @api
-	 */
-	bool_t		gfileExists(const char *fname);
-
-	/**
-	 * @brief					Delete file
-	 * 
-	 * @param[in] fname			The file name
-	 * 
-	 * @return					TRUE on success, FALSE otherwise
-	 * 
-	 * @api
-	 */
-	bool_t		gfileDelete(const char *fname);
-
-	/**
-	 * @brief					Get the size of a file
-	 * @note					Please use @p gfileGetSize() if the file is opened
-	 * 
-	 * @param[in] fname			The file name
-	 * 
-	 * @return					File size on success, -1 on error
-	 * 
-	 * @api
-	 */
-	long int	gfileGetFilesize(const char *fname);
-
-	/**
-	 * @brief					Rename file
-	 *
-	 * @param[in] oldname		The current file name
-	 * @param[in] newname		The new name of the file
-	 *
-	 * @return					TRUE on success, FALSE otherwise
-	 *
-	 * @api
-	 */
-	bool_t		gfileRename(const char *oldname, const char *newname);
-
-	/**
-	 * @brief					Open file
-	 * @details					A file must be opened before it can be accessed
-	 * @details					The resulting GFILE will be used for all functions that access the file.
-	 *
-	 * @param[in] fname			The file name
-	 * @param[in] mode			The mode.
-	 *
-	 * @return					Valid GFILE on success, 0 otherwise
-	 *
-	 * @note					The modes follow the c library fopen() standard.
-	 * 							The valid modes are:
-	 * 							<ul><li>r   - Open for read, the file must exist</li>
-	 * 								<li>w   - Open for write, the file is truncated if it exists</li>
-	 * 								<li>wx  - Open for write, the file must not exist</li>
-	 * 								<li>a   - Open for append, the file is truncated if it exists</li>
-	 * 								<li>ax  - Open for append, the file must not exists</li>
-	 * 							</ul>
-	 * 							The following flags can also be added to the above modes:<br/>
-	 * 							<ul><li>+   - Open for both read and write</li>
-	 * 								<li>b   - Open as a binary file rather than a text file</li>
-	 * 							</ul>
-	 * @note					Not all file-systems support all modes. For example, write
-	 * 							is not available with the ROM file-system. Similarly few platforms
-	 * 							distinguish between binary and text files.
-	 * @note					Even though binary vs. text is relevant only for a small number of platforms
-	 * 							the "b" flag should always be specified for binary files such as images.
-	 * 							This ensures portability to other platforms. The extra flag will be ignored
-	 * 							on platforms where it is not relevant.
-	 *
-	 * @api
-	 */	
-	GFILE *		gfileOpen(const char *fname, const char *mode);
-
-	/**
-	 * @brief					Close file
-	 * @details					Closes a file after is has been opened using @p gfileOpen()
-	 *
-	 * @param[in] f				The file
-	 *
-	 * @api
-	 */
-	void		gfileClose(GFILE *f);
-
-	/**
-	 * @brief					Read from file
-	 * @details					Reads a given amount of bytes from the file
-	 * @details					The read/write cursor will not be reset when calling this function
-	 *
-	 * @param[in] f				The file
-	 * @param[out] buf			The buffer in which to save the content that has been read from the file
-	 * @param[in] len			Amount of bytes to read
-	 *
-	 * @return					Amount of bytes read
-	 *
-	 * @api
-	 */
-	size_t		gfileRead(GFILE *f, void *buf, size_t len);
-
-	/**
-	 * @brief					Write to file
-	 * @details					Write a given amount of bytes to the file
-	 * @details					The read/write cursor will not be reset when calling this function
-	 *
-	 * @param[in] f				The file
-	 * @param[in] buf			The buffer which contains the content that will be written to the file
-	 * @param[in] len			Amount of bytes to write
-	 *
-	 * @return					Amount of bytes written
-	 *
-	 * @api
-	 */
-	size_t		gfileWrite(GFILE *f, const void *buf, size_t len);
-
-	/**
-	 * @brief					Get the current position of the read/write cursor
-	 *
-	 * @param[in] f				The file
-	 *
-	 * @return					The current position in the file
-	 *
-	 * @api
-	 */
-	long int	gfileGetPos(GFILE *f);
-
-	/**
-	 * @brief					Set the position of the read/write cursor
-	 *
-	 * @param[in] f				The file
-	 * @param[in] pos			The position to which the cursor will be set
-	 *
-	 * @return					TRUE on success, FALSE otherwise
-	 *
-	 * @api
-	 */
-	bool_t		gfileSetPos(GFILE *f, long int pos);
-
-	/**
-	 * @brief					Get the size of file
-	 * @note					Please use @p gfileGetFilesize() if the file is not opened
-	 *
-	 * @param[in] f				The file
-	 *
-	 * @return					The size of the file
-	 *
-	 * @api
-	 */
-	long int	gfileGetSize(GFILE *f);
-
-	/**
-	 * @brief					Check for EOF
-	 * @details					Checks if the cursor is at the end of the file
-	 *
-	 * @param[in] f				The file
-	 *
-	 * @return					TRUE if EOF, FALSE otherwise
-	 *
-	 * @api
-	 */
-	bool_t		gfileEOF(GFILE *f);
-
-	/**
-	 * @brief					Mount a logical drive (aka partition)
-	 *
-	 * @details					Not supported by every file system
-	 * @details					Currently just one drive at one is supported.
-	 *
-	 * @param[in] fs			The file system (F for FatFS)
-	 * @param[in] drive			The logical drive prefix
-	 *
-	 * @return					TRUE on success, FALSE otherwise
-	 *
-	 * @api
-	 */
-	bool_t gfileMount(char fs, const char *drive);
-
-	/**
-	 * @brief					Unmount a logical drive (aka partition)
-	 *
-	 * @details					Does have no effect if @p gfileMount() as been called before hand
-	 *
-	 * @param[in] fs			The file system (F for FatFS)
-	 * @param[in] drive			The logical drive prefix
-	 *
-	 * @return					TRUE on success, FALSE otherwise
-	 *
-	 * @api
-	 */
-	bool_t gfileUnmount(char fs, const char *drive);
-
-	/**
-	 * @brief					Syncs the file object (flushes the buffer)
-	 *
-	 * @details					Not supported by every file system
-	 *
-	 * @param[in] f				The file
-	 *
-	 * @return					TRUE on success, FALSE otherwise
-	 *
-	 * @api
-	 */
-	bool_t gfileSync(GFILE *f);
-
-	#if GFILE_NEED_FILELISTS || defined(__DOXYGEN__)
-		/**
-		 * @brief				Open a file list
-		 *
-		 * @param[in] fs		The file system (F for FatFS)
-		 * @param[in] path		Path information to pass to the file system
-		 * @param[in] dirs		Pass TRUE to get directories only, FALSE to get files only
-		 *
-		 * @return				A pointer to a file list on success, NULL otherwise
-		 *
-		 * @note				The path parameter is handled in a file-system specific way. It could be
-		 * 						treated as a directory name, it may be treated as a file pattern, or it
-		 * 						may be ignored. Passing NULL will always return the full list of files
-		 * 						in at least the top level directory.
-		 * @note				For file systems that do not support directories, passing TRUE for dirs
-		 * 						will return an error.
-		 * @note				You must call @p gfileCloseFileList() when you have finished with the
-		 * 						file list in order to free resources.
-		 *
-		 * @api
-		 */
-		gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs);
-
-		/**
-		 * @brief				Get the next file in a file list.
-		 *
-		 * @param[in] pfl		Pointer to a file list returned by @p gfileOpenFileList()
-		 *
-		 * @return				A pointer to a file (or directory) name. Returns NULL if there are no more.
-		 *
-		 * @note				The file name may contain the full directory path or may not depending
-		 * 						on how the file system treats directories.
-		 * @note				The returned buffer may be destroyed by the next call to any of
-		 * 						@p gfileOpenFileList(), @p gfileReadFileList() or @p gfileCloseFileList().
-		 * 						Do not use this pointer after one of those calls.
-		 *
-		 * @api
-		 */
-		const char *gfileReadFileList(gfileList *pfl);
-
-		/**
-		 * @brief				Close a file list.
-		 *
-		 * @param[in] pfl		Pointer to a file list returned by @p gfileOpenFileList()
-		 *
-		 * @api
-		 */
-		void gfileCloseFileList(gfileList *pfl);
-	#endif
-
-	#if (GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS) || defined(__DOXYGEN__)
-		/**
-		 * @brief					Open file from a ChibiOS BaseFileStream
-		 *
-		 * @param[in] BaseFileStreamPtr	The BaseFileStream to open as a GFILE
-		 * @param[in] mode			The mode.
-		 *
-		 * @return					Valid GFILE on success, 0 otherwise
-		 *
-		 * @note					The modes are the same modes as in @p gfileOpen(). The
-		 * 							open mode is NOT compared against the BaseFileStream capabilities.
-		 * @note					Supported operations are: read, write, getpos, setpos, eof and getsize
-		 *
-		 * @api
-		 */
-		GFILE *		gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode);
-	#endif
-
-	#if GFILE_NEED_MEMFS || defined(__DOXYGEN__)
-		/**
-		 * @brief					Open file from a memory pointer
-		 *
-		 * @param[in] memptr		The pointer to the memory
-		 * @param[in] mode			The mode.
-		 *
-		 * @return					Valid GFILE on success, 0 otherwise
-		 *
-		 * @note					The modes are the same modes as in @p gfileOpen(). Note there is
-		 * 							no concept of file-size. Be careful not to overwrite other memory or
-		 * 							to read from inaccessible sections of memory.
-		 * @note					Supported operations are: read, write, getpos, setpos
-		 *
-		 * @api
-		 */
-		GFILE *		gfileOpenMemory(void *memptr, const char *mode);
-	#endif
-
-	#if GFILE_NEED_STRINGS || defined(__DOXYGEN__)
-		/**
-		 * @brief					Open file from a null terminated C string
-		 *
-		 * @param[in] str			The pointer to the string or string buffer
-		 * @param[in] mode			The mode
-		 *
-		 * @return					Valid GFILE on success, 0 otherwise
-		 *
-		 * @note					The modes are the same modes as in @p gfileOpen(). Note there is
-		 * 							no concept of file-size. Be careful not to overwrite other memory or
-		 * 							to read from inaccessible sections of memory.
-		 * @note					Reading will return EOF when the NULL character is reached.
-		 * @note					Writing will always place a NULL in the next character effectively terminating the
-		 * 							string at the character just written.
-		 * @note					Supported operations are: read, write, append, getpos, setpos
-		 * @note					Be careful with setpos and getpos. They do not check for the end of the string.
-		 * @note					Reading and Writing will read/write a maximum of one character at a time.
-		 *
-		 * @api
-		 */
-		GFILE *		gfileOpenString(char *str, const char *mode);
-	#endif
-
-	#if GFILE_NEED_PRINTG || defined(__DOXYGEN__)
-		#include <stdarg.h>
-
-		int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg);
-		int fnprintg(GFILE *f, int maxlen, const char *fmt, ...);
-		#define vfprintg(f,m,a)			vfnprintg(f,0,m,a)
-		#define fprintg(f,m,...)		fnprintg(f,0,m,...)
-		#define vprintg(m,a)			vfnprintg(gfileStdOut,0,m,a)
-		#define printg(m,...)			fnprintg(gfileStdOut,0,m,...)
-
-		#if GFILE_NEED_STRINGS
-			int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg);
-			int snprintg(char *buf, int maxlen, const char *fmt, ...);
-			#define vsprintg(s,m,a)		vsnprintg(s,0,m,a)
-			#define sprintg(s,m,...)	snprintg(s,0,m,...)
-		#endif
-	#endif
-
-	#if GFILE_NEED_SCANG || defined(__DOXYGEN__)
-		#include <stdarg.h>
-
-		int vfscang(GFILE *f, const char *fmt, va_list arg);
-		int fscang(GFILE *f, const char *fmt, ...);
-		#define vscang(f,a)			vfscang(gfileStdIn,f,a)
-		#define scang(f,...)		fscang(gfileStdIn,f,...)
-
-		#if GFILE_NEED_STRINGS
-			int vsscang(const char *buf, const char *fmt, va_list arg);
-			int sscang(const char *buf, const char *fmt, ...);
-		#endif
-	#endif
-
-	#if GFILE_NEED_STDIO && !defined(GFILE_IMPLEMENTATION)
-		#define stdin					gfileStdIn
-		#define stdout					gfileStdOut
-		#define stderr					gfileStdErr
-		#define FILENAME_MAX			256						// Use a relatively small number for an embedded platform
-		#define L_tmpnam				FILENAME_MAX
-		#define FOPEN_MAX				GFILE_MAX_GFILES
-		#define TMP_MAX					GFILE_MAX_GFILES
-		#define P_tmpdir				"/tmp/"
-		#define FILE					GFILE
-		#define fopen(n,m)				gfileOpen(n,m)
-		#define fclose(f)				gfileClose(f)
-		size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f);
-		size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f);
-		#define fread(p,sz,cnt,f)		gstdioRead(p,sz,cnt,f)
-		#define fwrite(p,sz,cnt,f)		gstdioWrite(p,sz,cnt,f)
-		int gstdioSeek(FILE *f, size_t offset, int origin);
-		#define fseek(f,ofs,org)		gstdioSeek(f,ofs,org)
-			#define SEEK_SET	0
-			#define SEEK_CUR	1
-			#define SEEK_END	2
-		#define remove(n)				(!gfileDelete(n))
-		#define rename(o,n)				(!gfileRename(o,n))
-		#define fflush(f)				(0)
-		#define ftell(f)				gfileGetPos(f)
-		#define fpos_t					long int
-		int gstdioGetpos(FILE *f, long int *pos);
-		#define fgetpos(f,pos)			gstdioGetpos(f,pos)
-		#define fsetpos(f, pos)			(!gfileSetPos(f, *pos))
-		#define rewind(f)				gfileSetPos(f, 0);
-		#define feof(f)					gfileEOF(f)
-
-		#define vfprintf(f,m,a)			vfnprintg(f,0,m,a)
-		#define fprintf(f,m,...)		fnprintg(f,0,m,...)
-		#define vprintf(m,a)			vfnprintg(gfileStdOut,0,m,a)
-		#define printf(m,...)			fnprintg(gfileStdOut,0,m,...)
-		#define vsnprintf(s,n,m,a)		vsnprintg(s,n,m,a)
-		#define snprintf(s,n,m,...)		snprintg(s,n,m,...)
-		#define vsprintf(s,m,a)			vsnprintg(s,0,m,a)
-		#define sprintf(s,m,...)		snprintg(s,0,m,...)
-		//TODO
-		//void clearerr ( FILE * stream );
-		//int ferror ( FILE * stream );
-		//FILE * tmpfile ( void );		// Auto-deleting
-		//char * tmpnam ( char * str );
-		//char * mktemp (char *template);
-		//FILE * freopen ( const char * filename, const char * mode, FILE * stream );
-		//setbuf
-		//setvbuf
-		//fflush
-		//fgetc
-		//fgets
-		//fputc
-		//fputs
-		//getc
-		//getchar
-		//puts
-		//ungetc
-		//void perror (const char * str);
-	#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GFILE */
-
-#endif /* _GFILE_H */
-/** @} */
-
diff --git a/src/gfile/sys_make.mk b/src/gfile/sys_make.mk
deleted file mode 100644
index 0a85d1ae..00000000
--- a/src/gfile/sys_make.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gfile/gfile_gfile.c \
-            $(GFXLIB)/src/gfile/gfile_fs_native.c \
-            $(GFXLIB)/src/gfile/gfile_fs_ram.c \
-            $(GFXLIB)/src/gfile/gfile_fs_rom.c \
-            $(GFXLIB)/src/gfile/gfile_fs_fatfs.c \
-            $(GFXLIB)/src/gfile/gfile_fs_petitfs.c \
-            $(GFXLIB)/src/gfile/gfile_fs_mem.c \
-            $(GFXLIB)/src/gfile/gfile_fs_chibios.c \
-            $(GFXLIB)/src/gfile/gfile_fs_strings.c \
-            $(GFXLIB)/src/gfile/gfile_printg.c \
-            $(GFXLIB)/src/gfile/gfile_scang.c \
-            $(GFXLIB)/src/gfile/gfile_stdio.c \
-            $(GFXLIB)/src/gfile/gfile_fatfs_wrapper.c \
-            $(GFXLIB)/src/gfile/gfile_fatfs_diskio_chibios.c \
-            $(GFXLIB)/src/gfile/gfile_petitfs_wrapper.c \
-            $(GFXLIB)/src/gfile/gfile_petitfs_diskio_chibios.c \
-
-            
\ No newline at end of file
diff --git a/src/gfile/sys_options.h b/src/gfile/sys_options.h
deleted file mode 100644
index 5581b13b..00000000
--- a/src/gfile/sys_options.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gfile/sys_options.h
- * @brief   GFILE - File IO options header file.
- *
- * @addtogroup GFILE
- * @{
- */
-
-#ifndef _GFILE_OPTIONS_H
-#define _GFILE_OPTIONS_H
-
-/**
- * @name    GFILE Functionality to be included
- * @{
- */
-	/**
-	 * @brief	Should the filesystem not be mounted automatically
-	 * @details	The filesystem is normally mounted automatically if the
-	 *			user does not do it manually. This option turns that off
-	 *			so the user must manually mount the file-system first.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFILE_NEED_NOAUTOMOUNT
-		#define GFILE_NEED_NOAUTOMOUNT	FALSE
-	#endif
-	/**
-	 * @brief	Should the filesystem be synced automatically
-	 * @details	The filesystem will automatically be synced after an open() or
-	 *			write() call unless this feature is disabled.
-	 * @details	If this feature is disabled, the user should sync the filesystem
-	 *			himself using @p gfileSync()
-	 * @details	Not all filesystems implement the syncing feature. This feature will
-	 *			have no effect in such a case.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFILE_NEED_NOAUTOSYNC
-		#define GFILE_NEED_NOAUTOSYNC	FALSE
-	#endif
-	/**
-	 * @brief   Include printg, fprintg etc functions
-	 * @details	Defaults to FALSE
-	 * @pre		To get the string sprintg functions you also need to define @p GFILE_NEED_STRINGS
-	 */
-	#ifndef GFILE_NEED_PRINTG
-		#define GFILE_NEED_PRINTG		FALSE
-	#endif
-	/**
-	 * @brief   Include scang, fscang etc functions
-	 * @details	Defaults to FALSE
-	 * @pre		To get the string sscang functions you also need to define @p GFILE_NEED_STRINGS
-	 */
-	#ifndef GFILE_NEED_SCANG
-		#define GFILE_NEED_SCANG		FALSE
-	#endif
-	/**
-	 * @brief   Include the string based file functions
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFILE_NEED_STRINGS
-		#define GFILE_NEED_STRINGS		FALSE
-	#endif
-	/**
-	 * @brief   Map many stdio functions to their GFILE equivalent
-	 * @details	Defaults to FALSE
-	 * @note	This replaces the functions in stdio.h with equivalents
-	 * 			- Do not include stdio.h as it has different conflicting definitions.
-	 */
-	#ifndef GFILE_NEED_STDIO
-		#define GFILE_NEED_STDIO		FALSE
-	#endif
-	/**
-	 * @brief   Include the ROM file system
-	 * @details	Defaults to FALSE
-	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
-	 * 			opening a file on the ROM file system by prefixing
-	 * 			its name with "S|" (the letter 'S', followed by a vertical bar).
-	 * @note	This requires a file called romfs_files.h to be in the
-	 * 			users project include path. This file should include all the files
-	 * 			converted to .h files using the file2c utility (using flags "-dbcs").
-	 */
-	#ifndef GFILE_NEED_ROMFS
-		#define GFILE_NEED_ROMFS		FALSE
-	#endif
-	/**
-	 * @brief   Include the RAM file system
-	 * @details	Defaults to FALSE
-	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
-	 * 			opening a file on the RAM file system by prefixing
-	 * 			its name with "R|" (the letter 'R', followed by a vertical bar).
-	 * @note	You must also define GFILE_RAMFS_SIZE with the size of the file system
-	 * 			to be allocated in RAM.
-	 */
-	#ifndef GFILE_NEED_RAMFS
-		#define GFILE_NEED_RAMFS		FALSE
-	#endif
-	/**
-	 * @brief   Include the FAT file system driver based on the FATFS library
-	 * @details	Defaults to FALSE
-	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
-	 * 			opening a file on the FAT file system by prefixing
-	 * 			its name with "F|" (the letter 'F', followed by a vertical bar).
-	 * @note	FATFS and PETITFS offer the same FAT file system support. They just use
-	 * 			different constraints. PETITFS is smaller but has less features. Only
-	 * 			one can be used at a time. The block interfaces are also different.
-	 */
-	#ifndef GFILE_NEED_FATFS
-		#define GFILE_NEED_FATFS		FALSE
-	#endif
-	/**
-	 * @brief   Include the FAT file system driver based on the PETITFS library
-	 * @details	Defaults to FALSE
-	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
-	 * 			opening a file on the FAT file system by prefixing
-	 * 			its name with "F|" (the letter 'F', followed by a vertical bar).
-	 * @note	FATFS and PETITFS offer the same FAT file system support. They just use
-	 * 			different constraints. PETITFS is smaller but has less features. Only
-	 * 			one can be used at a time. The block interfaces are also different.
-	 * @note	Due to the restrictions on the PETITFS library on writing, we do not implement
-	 * 			writing.
-	 * @note	PETITFS can only have one file open at a time.
-	 */
-	#ifndef GFILE_NEED_PETITFS
-		#define GFILE_NEED_PETITFS		FALSE
-	#endif
-	/**
-	 * @brief   Include the operating system's native file system
-	 * @details	Defaults to FALSE
-	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are
-	 * 			opening a file on the native file system by prefixing
-	 * 			its name with "N|" (the letter 'N', followed by a vertical bar).
-	 * @note	If defined then the gfileStdOut and gfileStdErr handles
-	 * 			use the operating system equivalent stdio and stderr.
-	 * 			If it is not defined the gfileStdOut and gfileStdErr io is discarded.
-	 */
-	#ifndef GFILE_NEED_NATIVEFS
-		#define GFILE_NEED_NATIVEFS		FALSE
-	#endif
-	/**
-	 * @brief   Include ChibiOS BaseFileStream support
-	 * @details	Defaults to FALSE
-	 * @pre		This is only relevant on the ChibiOS operating system.
-	 * @note	Use the @p gfileOpenBaseFileStream() call to open a GFILE based on a
-	 * 			BaseFileStream. The BaseFileStream must already be open.
-	 * @note	A GFile of this type cannot be opened by filename. The BaseFileStream
-	 * 			must be pre-opened using the operating system.
-	 */
-	#ifndef GFILE_NEED_CHIBIOSFS
-		#define GFILE_NEED_CHIBIOSFS	FALSE
-	#endif
-	/**
-	 * @brief   Include raw memory pointer support
-	 * @details	Defaults to FALSE
-	 * @note	Use the @p gfileOpenMemory() call to open a GFILE based on a
-	 * 			memory pointer. The GFILE opened appears to be of unlimited size.
-	 * @note	A GFile of this type cannot be opened by filename.
-	 */
-	#ifndef GFILE_NEED_MEMFS
-		#define GFILE_NEED_MEMFS		FALSE
-	#endif
-	/**
-	 * @brief   Include support for file list functions
-	 * @details	Defaults to FALSE
-	 * @note	Adds support for @p gfileOpenFileList(), @p gfileReadFileList() and @p gfileCloseFileList().
-	 */
-	#ifndef GFILE_NEED_FILELISTS
-		#define GFILE_NEED_FILELISTS	FALSE
-	#endif
-/**
- * @}
- *
- * @name    GFILE Optional Parameters
- * @{
- */
-	/**
-	 * @brief  Add floating point support to printg/scang etc.
-	 */
-	#ifndef GFILE_ALLOW_FLOATS
-		#define GFILE_ALLOW_FLOATS	FALSE
-	#endif
-	/**
-	 * @brief   Can the device be specified as part of the file name.
-	 * @note	If this is on then a device letter and a vertical bar can be
-	 * 			prefixed on a file name to specify that it must be on a
-	 * 			specific device.
-	 */
-	#ifndef GFILE_ALLOW_DEVICESPECIFIC
-		#define GFILE_ALLOW_DEVICESPECIFIC		FALSE
-	#endif
-	/**
-	 * @brief   The maximum number of open files
-	 * @note	This count excludes gfileStdIn, gfileStdOut and gfileStdErr
-	 * 			(if open by default).
-	 */
-	#ifndef GFILE_MAX_GFILES
-		#define GFILE_MAX_GFILES		3
-	#endif
-/** @} */
-
-#endif /* _GFILE_OPTIONS_H */
-/** @} */
diff --git a/src/gfile/sys_rules.h b/src/gfile/sys_rules.h
deleted file mode 100644
index d13041f2..00000000
--- a/src/gfile/sys_rules.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gfile/sys_rules.h
- * @brief   GFILE safety rules header file.
- *
- * @addtogroup GFILE
- * @{
- */
-
-#ifndef _GFILE_RULES_H
-#define _GFILE_RULES_H
-
-#if GFX_USE_GFILE
-	#if GFILE_NEED_PETITFS && GFILE_NEED_FATFS
-		#error "GFILE: Both GFILE_NEED_PETITFS and GFILE_NEED_FATFS cannot both be turned on at the same time."
-	#endif
-#endif
-
-#endif /* _GFILE_RULES_H */
-/** @} */
diff --git a/src/ginput/driver_dial.h b/src/ginput/driver_dial.h
deleted file mode 100644
index bf01da20..00000000
--- a/src/ginput/driver_dial.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/driver_dial.h
- * @brief   GINPUT header file for dial drivers.
- *
- * @defgroup Dial Dial
- * @ingroup GINPUT
- * @{
- */
-
-#ifndef _LLD_GINPUT_DIAL_H
-#define _LLD_GINPUT_DIAL_H
-
-#if GINPUT_NEED_DIAL || defined(__DOXYGEN__)
-
-#include "ginput_lld_dial_config.h"
-
-typedef void (*DialCallbackFn)(uint16_t instance, uint16_t rawvalue);
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-	void ginput_lld_dial_init(void);
-	void ginput_lld_dial_poll(DialCallbackFn fn);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GINPUT && GINPUT_NEED_TOGGLE */
-
-#endif /* _LLD_GINPUT_TOGGLE_H */
-/** @} */
-
diff --git a/src/ginput/driver_keyboard.h b/src/ginput/driver_keyboard.h
deleted file mode 100644
index 329df97a..00000000
--- a/src/ginput/driver_keyboard.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/driver_keyboard.h
- * @brief   GINPUT LLD header file for keyboard drivers.
- *
- * @defgroup Keyboard Keyboard
- * @ingroup GINPUT
- * @{
- */
-
-#ifndef _LLD_GINPUT_KEYBOARD_H
-#define _LLD_GINPUT_KEYBOARD_H
-
-#if GINPUT_NEED_KEYBOARD //|| defined(__DOXYGEN__)
-
-// Include the GDRIVER infrastructure
-#include "src/gdriver/sys_defs.h"
-
-typedef struct GKeyboard {
-	GDriver			d;					// The driver overheads and vmt
-	uint16_t		cntc;				// The byte count in c
-	uint16_t		cntsc;				// The byte count in sc
-	char			c[8];				// The utf8 code for the current key
-	char			sc[8];				// The scancode for the current key
-	uint32_t		keystate;			// The keyboard state.
-	uint16_t		flags;
-		#define GKEYBOARD_FLG_NEEDREAD	0x0001
-	uint16_t		laystate;			// The layout state.
-	const uint8_t *	pLayout;			// The current keyboard layout
-	// Other driver specific fields may follow.
-} GKeyboard;
-
-typedef struct GKeyboardVMT {
-	GDriverVMT	d;											// Device flags are part of the general vmt
-		#define GKEYBOARD_VFLG_NOPOLL			0x0001		// Do not poll this device - it is purely interrupt driven
-		#define GKEYBOARD_VFLG_DYNAMICONLY		0x8000		// This keyboard driver should not be statically initialized eg Win32
-	const uint8_t *	defLayout;								// The default keyboard layout
-	bool_t	(*init)(GKeyboard *m, unsigned driverinstance);	// Required
-	void	(*deinit)(GKeyboard *m);						// Optional
-	int		(*getdata)(GKeyboard *k, uint8_t *pch, int sz);	// Required. Get zero or more scancode bytes. Returns the number of scancode bytes returns
-	void	(*putdata)(GKeyboard *k, char ch);				// Optional. Send a single byte to the keyboard.
-} GKeyboardVMT;
-
-#define gkvmt(m)		((const GKeyboardVMT const *)((m)->d.vmt))
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-// If we are not using multiple keyboards then hard-code the VMT name
-#if !defined(GINPUT_KEYBOARD_DRIVER_LIST)
-	#undef GKEYBOARD_DRIVER_VMT
-	#define GKEYBOARD_DRIVER_VMT		GKEYBOARDVMT_OnlyOne
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-	/**
-	 * @brief	Initialize a keyboard driver
-	 *
-	 * @param[in] g					The keyboard driver
-	 * @param[in] param				Unused by keyboard
-	 * @param[in] driverinstance	The driver instance		ToDo: Add some more details
-	 * @param[in] systeminstance	The mouse instance		ToDo: Add some more details
-	 *
-	 * @return	TRUE on success, FALSE otherwise
-	 * @note	This routine is provided by the high level code for
-	 * 			use in the driver VMT's GMouseVMT.d structure.
-	 *
-	 * @notapi
-	 */
-	bool_t _gkeyboardInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance);
-
-	/**
-	 * @brief	Routine that is called after initialization
-	 *
-	 * @param[in] g		The keyboard driver
-	 * @note	This routine is provided by the high level code for
-	 * 			use in the driver VMT's GKeyboardVMT.d structure.
-	 *
-	 * @notapi
-	 */
-	void _gkeyboardPostInitDriver(GDriver *g);
-
-	/**
-	 * @brief	Deinitialize a keyboard driver
-	 *
-	 * @param[in] g		The kerboard driver
-	 * @note	This routine is provided by the high level code for
-	 * 			use in the driver VMT's GKeyboardVMT.d structure.
-	 *
-	 * @notapi
-	 */
-	void _gkeyboardDeInitDriver(GDriver *g);
-
-	/**
-	 * @brief	Wakeup the high level code so that it attempts another read
-	 *
-	 * @note	This routine is provided to low level drivers by the high level code
-	 *
-	 * @notapi
-	 */
-	void _gkeyboardWakeup(GKeyboard *k);
-
-	/**
-	 * @brief	Wakeup the high level code so that it attempts another read
-	 *
-	 * @note	This routine is provided to low level drivers by the high level code
-	 *
-	 * @iclass
-	 * @notapi
-	 */
-	void _gkeyboardWakeupI(GKeyboard *k);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GINPUT_NEED_KEYBOARD */
-
-#endif /* _LLD_GINPUT_KEYBOARD_H */
-/** @} */
diff --git a/src/ginput/driver_mouse.h b/src/ginput/driver_mouse.h
deleted file mode 100644
index 5f948458..00000000
--- a/src/ginput/driver_mouse.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/driver_mouse.h
- * @brief   GINPUT LLD header file for mouse/touch drivers.
- *
- * @defgroup Mouse Mouse
- * @ingroup GINPUT
- * @{
- */
-
-#ifndef _LLD_GINPUT_MOUSE_H
-#define _LLD_GINPUT_MOUSE_H
-
-#if GINPUT_NEED_MOUSE //|| defined(__DOXYGEN__)
-
-// Include the GDRIVER infrastructure
-#include "src/gdriver/sys_defs.h"
-
-typedef struct GMouseReading {
-	coord_t		x, y, z;
-	uint16_t	buttons;
-	} GMouseReading;
-
-#if !GINPUT_TOUCH_NOCALIBRATE
-	typedef struct GMouseCalibration {
-		float	ax;
-		float	bx;
-		float	cx;
-		float	ay;
-		float	by;
-		float	cy;
-	} GMouseCalibration;
-#endif
-
-typedef struct GMouse {
-	GDriver								d;					// The driver overheads and vmt
-	GMouseReading						r;					// The current position and state
-	uint16_t							flags;				// Flags
-			#define GMOUSE_FLG_CLICK_TIMER		0x0001				// Currently timing a click
-			#define GMOUSE_FLG_INDELTA			0x0002				// Currently in a up/down transition test
-			#define GMOUSE_FLG_CLIP				0x0004				// Clip reading to the display
-			#define GMOUSE_FLG_CALIBRATE		0x0008				// Calibrate readings
-			#define GMOUSE_FLG_IN_CAL			0x0010				// Currently in calibration routine
-			#define GMOUSE_FLG_FINGERMODE		0x0020				// Mouse is currently in finger mode
-			#define GMOUSE_FLG_NEEDREAD			0x0040				// The mouse needs reading
-			#define GMOUSE_FLG_DRIVER_FIRST		0x0100				// The first flag available for the driver
-	point								clickpos;			// The position of the last click event
-	systemticks_t						clicktime;			// The time of the last click event
-	GDisplay *							display;			// The display the mouse is associated with
-	#if !GINPUT_TOUCH_NOCALIBRATE
-		GMouseCalibration				caldata;			// The calibration data
-	#endif
-	// Other driver specific fields may follow.
-} GMouse;
-
-typedef struct GMouseJitter {
-	coord_t		calibrate;									// Maximum error for a calibration to succeed
-	coord_t		click;										// Movement allowed without discarding the CLICK or CLICKCXT event
-	coord_t		move;										// Movement allowed without discarding the MOVE event
-} GMouseJitter;
-
-typedef struct GMouseVMT {
-	GDriverVMT	d;											// Device flags are part of the general vmt
-		#define GMOUSE_VFLG_TOUCH			0x0001			// This is a touch device (rather than a mouse). Button 1 is calculated from z value.
-		#define GMOUSE_VFLG_NOPOLL			0x0002			// Do not poll this device - it is purely interrupt driven
-		#define GMOUSE_VFLG_SELFROTATION	0x0004			// This device returns readings that are aligned with the display orientation
-		#define GMOUSE_VFLG_DEFAULTFINGER	0x0008			// Default to finger mode
-		#define GMOUSE_VFLG_CALIBRATE		0x0010			// This device requires calibration
-		#define GMOUSE_VFLG_CAL_EXTREMES	0x0020			// Use edge to edge calibration
-		#define GMOUSE_VFLG_CAL_TEST		0x0040			// Test the results of the calibration
-		#define GMOUSE_VFLG_ONLY_DOWN		0x0100			// This device returns a valid position only when the mouse is down
-		#define GMOUSE_VFLG_POORUPDOWN		0x0200			// Position readings during up/down are unreliable
-		#define GMOUSE_VFLG_DYNAMICONLY		0x8000			// This mouse driver should not be statically initialized eg Win32
-	coord_t		z_max;										// TOUCH: Maximum possible z value (fully touched)
-	coord_t		z_min;										// TOUCH: Minimum possible z value (touch off screen). Note may also be > z_max
-	coord_t		z_touchon;									// TOUCH: z values between z_max and this are a solid touch on
-	coord_t		z_touchoff;									// TOUCH: z values between z_min and this are a solid touch off
-
-	GMouseJitter	pen_jitter;								// PEN MODE: Jitter settings
-	GMouseJitter	finger_jitter;							// FINGER MODE: Jitter settings
-
-	bool_t	(*init)(GMouse *m, unsigned driverinstance);	// Required
-	void	(*deinit)(GMouse *m);							// Optional
-	bool_t	(*get)(GMouse *m, GMouseReading *prd);			// Required
-	void	(*calsave)(GMouse *m, const void *buf, size_t sz);	// Optional
-	bool_t	(*calload)(GMouse *m, void *buf, size_t sz);	// Optional
-} GMouseVMT;
-
-#define gmvmt(m)		((const GMouseVMT const *)((m)->d.vmt))
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-// If we are not using multiple mice then hard-code the VMT name
-#if !defined(GINPUT_MOUSE_DRIVER_LIST)
-	#undef GMOUSE_DRIVER_VMT
-	#define GMOUSE_DRIVER_VMT		GMOUSEVMT_OnlyOne
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-	/**
-	 * @brief	Initialize a mouse driver
-	 *
-	 * @param[in] g					The mouse driver
-	 * @param[in] display			The display to which the mouse shall be assigned
-	 * @param[in] driverinstance	The driver instance		ToDo: Add some more details
-	 * @param[in] systeminstance	The mouse instance		ToDo: Add some more details
-	 *
-	 * @return	TRUE on success, FALSE otherwise
-	 * @note	This routine is provided by the high level code for
-	 * 			use in the driver VMT's GMouseVMT.d structure.
-	 *
-	 * @notapi
-	 */
-	bool_t _gmouseInitDriver(GDriver *g, void *display, unsigned driverinstance, unsigned systeminstance);
-
-	/**
-	 * @brief	Routine that is called after initialization
-	 *
-	 * @param[in] g		The mouse driver
-	 * @note	This routine is provided by the high level code for
-	 * 			use in the driver VMT's GMouseVMT.d structure.
-	 *
-	 * @notapi
-	 */
-	void _gmousePostInitDriver(GDriver *g);
-
-	/**
-	 * @brief	Deinitialize a mouse driver
-	 *
-	 * @param[in] g		The mouse driver
-	 * @note	This routine is provided by the high level code for
-	 * 			use in the driver VMT's GMouseVMT.d structure.
-	 *
-	 * @notapi
-	 */
-	void _gmouseDeInitDriver(GDriver *g);
-
-	/**
-	 * @brief	Wakeup the high level code so that it attempts another read
-	 *
-	 * @note	This routine is provided to low level drivers by the high level code
-	 *
-	 * @notapi
-	 */
-	void _gmouseWakeup(GMouse *m);
-
-	/**
-	 * @brief	Wakeup the high level code so that it attempts another read
-	 *
-	 * @note	This routine is provided to low level drivers by the high level code
-	 *
-	 * @iclass
-	 * @notapi
-	 */
-	void _gmouseWakeupI(GMouse *m);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GINPUT_NEED_MOUSE */
-
-#endif /* _LLD_GINPUT_MOUSE_H */
-/** @} */
diff --git a/src/ginput/driver_toggle.h b/src/ginput/driver_toggle.h
deleted file mode 100644
index 6d672c91..00000000
--- a/src/ginput/driver_toggle.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/driver_toggle.h
- * @brief   GINPUT header file for toggle drivers.
- *
- * @defgroup Toggle Toggle
- * @ingroup GINPUT
- * @{
- */
-
-#ifndef _LLD_GINPUT_TOGGLE_H
-#define _LLD_GINPUT_TOGGLE_H
-
-#if GINPUT_NEED_TOGGLE || defined(__DOXYGEN__)
-
-// Describes how the toggle bits are obtained
-typedef struct GToggleConfig_t {
-	void		*id;
-	unsigned	mask;
-	unsigned	invert;
-	unsigned	mode;
-} GToggleConfig;
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-	extern const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES];
-	
-	void ginput_lld_toggle_init(const GToggleConfig *ptc);
-	unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc);
-
-	/* This routine is provided to low level drivers to wakeup a value read from a thread context.
-	 *	Particularly useful if GINPUT_TOGGLE_POLL_PERIOD = TIME_INFINITE
-	 */
-	void ginputToggleWakeup(void);
-
-	/* This routine is provided to low level drivers to wakeup a value read from an ISR
-	 *	Particularly useful if GINPUT_TOGGLE_POLL_PERIOD = TIME_INFINITE
-	 */
-	void ginputToggleWakeupI(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GINPUT && GINPUT_NEED_TOGGLE */
-
-#endif /* _LLD_GINPUT_TOGGLE_H */
-/** @} */
-
diff --git a/src/ginput/ginput.c b/src/ginput/ginput.c
new file mode 100644
index 00000000..becefc19
--- /dev/null
+++ b/src/ginput/ginput.c
@@ -0,0 +1,54 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/ginput_ginput.c
+ * @brief   GINPUT subsystem common code.
+ *
+ * @addtogroup GINPUT
+ * @{
+ */
+#include "gfx.h"
+
+#if GFX_USE_GINPUT
+
+#if GINPUT_NEED_MOUSE
+    extern void _gmouseInit(void);
+    extern void _gmouseDeinit(void);
+#endif
+#if GINPUT_NEED_KEYBOARD
+    extern void _gkeyboardInit(void);
+    extern void _gkeyboardDeinit(void);
+#endif
+
+void _ginputInit(void)
+{
+    #if GINPUT_NEED_MOUSE
+        _gmouseInit();
+    #endif
+	#if GINPUT_NEED_KEYBOARD
+		_gkeyboardInit();
+	#endif
+	/**
+	 * This should really call an init routine for each ginput sub-system.
+	 * Maybe we'll do this later.
+	 */
+}
+
+void _ginputDeinit(void)
+{
+	#if GINPUT_NEED_KEYBOARD
+		_gkeyboardDeinit();
+	#endif
+    #if GINPUT_NEED_MOUSE
+        _gmouseDeinit();
+    #endif
+}
+
+#endif /* GFX_USE_GINPUT */
+/** @} */
+
diff --git a/src/ginput/ginput.h b/src/ginput/ginput.h
new file mode 100644
index 00000000..469a10d1
--- /dev/null
+++ b/src/ginput/ginput.h
@@ -0,0 +1,50 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/ginput.h
+ *
+ * @addtogroup GINPUT
+ *
+ * @brief		Module to interface different hardware input sources such as touchscreens
+ *
+ * @details		GINPUT provides an easy and common interface to use different input devices
+ *				such as touchscreens and mices.
+ *
+ * @pre			GFX_USE_GINPUT must be set to TRUE in your gfxconf.h
+ *
+ * @{
+ */
+#ifndef _GINPUT_H
+#define _GINPUT_H
+
+#include "gfx.h"
+
+#if GFX_USE_GINPUT || defined(__DOXYGEN__)
+
+/* How to use...
+
+	1. Get source handles for all the inputs you are interested in.
+		- Attempting to get a handle for one instance of an input more than once will return the same handle
+	2. Create a listener
+	3. Assign inputs to your listener.
+		- Inputs can be assigned or released from a listener at any time.
+		- An input can be assigned to more than one listener.
+	4. Loop on getting listener events
+	5. When complete destroy the listener
+*/
+
+// Include various ginput types
+#include "ginput_mouse.h"
+#include "ginput_keyboard.h"
+#include "ginput_toggle.h"
+#include "ginput_dial.h"
+
+#endif /* GFX_USE_GINPUT */
+
+#endif /* _GINPUT_H */
+/** @} */
diff --git a/src/ginput/ginput.mk b/src/ginput/ginput.mk
new file mode 100644
index 00000000..c814afa2
--- /dev/null
+++ b/src/ginput/ginput.mk
@@ -0,0 +1,6 @@
+GFXSRC +=   $(GFXLIB)/src/ginput/ginput.c \
+			$(GFXLIB)/src/ginput/ginput_mouse.c \
+			$(GFXLIB)/src/ginput/ginput_keyboard.c \
+			$(GFXLIB)/src/ginput/ginput_keyboard_microcode.c \
+			$(GFXLIB)/src/ginput/ginput_toggle.c \
+			$(GFXLIB)/src/ginput/ginput_dial.c
diff --git a/src/ginput/ginput_dial.c b/src/ginput/ginput_dial.c
index 6af89b31..6c4f872b 100644
--- a/src/ginput/ginput_dial.c
+++ b/src/ginput/ginput_dial.c
@@ -17,7 +17,7 @@
 
 #if GFX_USE_GINPUT && GINPUT_NEED_DIAL
 
-#include "driver_dial.h"
+#include "ginput_driver_dial.h"
 
 static GTIMER_DECL(DialTimer);
 static struct DialStatus_t {
diff --git a/src/ginput/ginput_driver_dial.h b/src/ginput/ginput_driver_dial.h
new file mode 100644
index 00000000..146ffc8d
--- /dev/null
+++ b/src/ginput/ginput_driver_dial.h
@@ -0,0 +1,45 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/ginput_driver_dial.h
+ * @brief   GINPUT header file for dial drivers.
+ *
+ * @defgroup Dial Dial
+ * @ingroup GINPUT
+ * @{
+ */
+
+#ifndef _LLD_GINPUT_DIAL_H
+#define _LLD_GINPUT_DIAL_H
+
+#if GINPUT_NEED_DIAL || defined(__DOXYGEN__)
+
+#include "ginput_lld_dial_config.h"
+
+typedef void (*DialCallbackFn)(uint16_t instance, uint16_t rawvalue);
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	void ginput_lld_dial_init(void);
+	void ginput_lld_dial_poll(DialCallbackFn fn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GINPUT && GINPUT_NEED_TOGGLE */
+
+#endif /* _LLD_GINPUT_TOGGLE_H */
+/** @} */
+
diff --git a/src/ginput/ginput_driver_keyboard.h b/src/ginput/ginput_driver_keyboard.h
new file mode 100644
index 00000000..62a00339
--- /dev/null
+++ b/src/ginput/ginput_driver_keyboard.h
@@ -0,0 +1,129 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/ginput_driver_keyboard.h
+ * @brief   GINPUT LLD header file for keyboard drivers.
+ *
+ * @defgroup Keyboard Keyboard
+ * @ingroup GINPUT
+ * @{
+ */
+
+#ifndef _LLD_GINPUT_KEYBOARD_H
+#define _LLD_GINPUT_KEYBOARD_H
+
+#if GINPUT_NEED_KEYBOARD //|| defined(__DOXYGEN__)
+
+// Include the GDRIVER infrastructure
+#include "src/gdriver/gdriver.h"
+
+typedef struct GKeyboard {
+	GDriver			d;					// The driver overheads and vmt
+	uint16_t		cntc;				// The byte count in c
+	uint16_t		cntsc;				// The byte count in sc
+	char			c[8];				// The utf8 code for the current key
+	char			sc[8];				// The scancode for the current key
+	uint32_t		keystate;			// The keyboard state.
+	uint16_t		flags;
+		#define GKEYBOARD_FLG_NEEDREAD	0x0001
+	uint16_t		laystate;			// The layout state.
+	const uint8_t *	pLayout;			// The current keyboard layout
+	// Other driver specific fields may follow.
+} GKeyboard;
+
+typedef struct GKeyboardVMT {
+	GDriverVMT	d;											// Device flags are part of the general vmt
+		#define GKEYBOARD_VFLG_NOPOLL			0x0001		// Do not poll this device - it is purely interrupt driven
+		#define GKEYBOARD_VFLG_DYNAMICONLY		0x8000		// This keyboard driver should not be statically initialized eg Win32
+	const uint8_t *	defLayout;								// The default keyboard layout
+	bool_t	(*init)(GKeyboard *m, unsigned driverinstance);	// Required
+	void	(*deinit)(GKeyboard *m);						// Optional
+	int		(*getdata)(GKeyboard *k, uint8_t *pch, int sz);	// Required. Get zero or more scancode bytes. Returns the number of scancode bytes returns
+	void	(*putdata)(GKeyboard *k, char ch);				// Optional. Send a single byte to the keyboard.
+} GKeyboardVMT;
+
+#define gkvmt(m)		((const GKeyboardVMT const *)((m)->d.vmt))
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+// If we are not using multiple keyboards then hard-code the VMT name
+#if !defined(GINPUT_KEYBOARD_DRIVER_LIST)
+	#undef GKEYBOARD_DRIVER_VMT
+	#define GKEYBOARD_DRIVER_VMT		GKEYBOARDVMT_OnlyOne
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+	/**
+	 * @brief	Initialize a keyboard driver
+	 *
+	 * @param[in] g					The keyboard driver
+	 * @param[in] param				Unused by keyboard
+	 * @param[in] driverinstance	The driver instance		ToDo: Add some more details
+	 * @param[in] systeminstance	The mouse instance		ToDo: Add some more details
+	 *
+	 * @return	TRUE on success, FALSE otherwise
+	 * @note	This routine is provided by the high level code for
+	 * 			use in the driver VMT's GMouseVMT.d structure.
+	 *
+	 * @notapi
+	 */
+	bool_t _gkeyboardInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance);
+
+	/**
+	 * @brief	Routine that is called after initialization
+	 *
+	 * @param[in] g		The keyboard driver
+	 * @note	This routine is provided by the high level code for
+	 * 			use in the driver VMT's GKeyboardVMT.d structure.
+	 *
+	 * @notapi
+	 */
+	void _gkeyboardPostInitDriver(GDriver *g);
+
+	/**
+	 * @brief	Deinitialize a keyboard driver
+	 *
+	 * @param[in] g		The kerboard driver
+	 * @note	This routine is provided by the high level code for
+	 * 			use in the driver VMT's GKeyboardVMT.d structure.
+	 *
+	 * @notapi
+	 */
+	void _gkeyboardDeInitDriver(GDriver *g);
+
+	/**
+	 * @brief	Wakeup the high level code so that it attempts another read
+	 *
+	 * @note	This routine is provided to low level drivers by the high level code
+	 *
+	 * @notapi
+	 */
+	void _gkeyboardWakeup(GKeyboard *k);
+
+	/**
+	 * @brief	Wakeup the high level code so that it attempts another read
+	 *
+	 * @note	This routine is provided to low level drivers by the high level code
+	 *
+	 * @iclass
+	 * @notapi
+	 */
+	void _gkeyboardWakeupI(GKeyboard *k);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GINPUT_NEED_KEYBOARD */
+
+#endif /* _LLD_GINPUT_KEYBOARD_H */
+/** @} */
diff --git a/src/ginput/ginput_driver_mouse.h b/src/ginput/ginput_driver_mouse.h
new file mode 100644
index 00000000..93d01124
--- /dev/null
+++ b/src/ginput/ginput_driver_mouse.h
@@ -0,0 +1,174 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/ginput_driver_mouse.h
+ * @brief   GINPUT LLD header file for mouse/touch drivers.
+ *
+ * @defgroup Mouse Mouse
+ * @ingroup GINPUT
+ * @{
+ */
+
+#ifndef _LLD_GINPUT_MOUSE_H
+#define _LLD_GINPUT_MOUSE_H
+
+#if GINPUT_NEED_MOUSE //|| defined(__DOXYGEN__)
+
+// Include the GDRIVER infrastructure
+#include "src/gdriver/gdriver.h"
+
+typedef struct GMouseReading {
+	coord_t		x, y, z;
+	uint16_t	buttons;
+	} GMouseReading;
+
+#if !GINPUT_TOUCH_NOCALIBRATE
+	typedef struct GMouseCalibration {
+		float	ax;
+		float	bx;
+		float	cx;
+		float	ay;
+		float	by;
+		float	cy;
+	} GMouseCalibration;
+#endif
+
+typedef struct GMouse {
+	GDriver								d;					// The driver overheads and vmt
+	GMouseReading						r;					// The current position and state
+	uint16_t							flags;				// Flags
+			#define GMOUSE_FLG_CLICK_TIMER		0x0001				// Currently timing a click
+			#define GMOUSE_FLG_INDELTA			0x0002				// Currently in a up/down transition test
+			#define GMOUSE_FLG_CLIP				0x0004				// Clip reading to the display
+			#define GMOUSE_FLG_CALIBRATE		0x0008				// Calibrate readings
+			#define GMOUSE_FLG_IN_CAL			0x0010				// Currently in calibration routine
+			#define GMOUSE_FLG_FINGERMODE		0x0020				// Mouse is currently in finger mode
+			#define GMOUSE_FLG_NEEDREAD			0x0040				// The mouse needs reading
+			#define GMOUSE_FLG_DRIVER_FIRST		0x0100				// The first flag available for the driver
+	point								clickpos;			// The position of the last click event
+	systemticks_t						clicktime;			// The time of the last click event
+	GDisplay *							display;			// The display the mouse is associated with
+	#if !GINPUT_TOUCH_NOCALIBRATE
+		GMouseCalibration				caldata;			// The calibration data
+	#endif
+	// Other driver specific fields may follow.
+} GMouse;
+
+typedef struct GMouseJitter {
+	coord_t		calibrate;									// Maximum error for a calibration to succeed
+	coord_t		click;										// Movement allowed without discarding the CLICK or CLICKCXT event
+	coord_t		move;										// Movement allowed without discarding the MOVE event
+} GMouseJitter;
+
+typedef struct GMouseVMT {
+	GDriverVMT	d;											// Device flags are part of the general vmt
+		#define GMOUSE_VFLG_TOUCH			0x0001			// This is a touch device (rather than a mouse). Button 1 is calculated from z value.
+		#define GMOUSE_VFLG_NOPOLL			0x0002			// Do not poll this device - it is purely interrupt driven
+		#define GMOUSE_VFLG_SELFROTATION	0x0004			// This device returns readings that are aligned with the display orientation
+		#define GMOUSE_VFLG_DEFAULTFINGER	0x0008			// Default to finger mode
+		#define GMOUSE_VFLG_CALIBRATE		0x0010			// This device requires calibration
+		#define GMOUSE_VFLG_CAL_EXTREMES	0x0020			// Use edge to edge calibration
+		#define GMOUSE_VFLG_CAL_TEST		0x0040			// Test the results of the calibration
+		#define GMOUSE_VFLG_ONLY_DOWN		0x0100			// This device returns a valid position only when the mouse is down
+		#define GMOUSE_VFLG_POORUPDOWN		0x0200			// Position readings during up/down are unreliable
+		#define GMOUSE_VFLG_DYNAMICONLY		0x8000			// This mouse driver should not be statically initialized eg Win32
+	coord_t		z_max;										// TOUCH: Maximum possible z value (fully touched)
+	coord_t		z_min;										// TOUCH: Minimum possible z value (touch off screen). Note may also be > z_max
+	coord_t		z_touchon;									// TOUCH: z values between z_max and this are a solid touch on
+	coord_t		z_touchoff;									// TOUCH: z values between z_min and this are a solid touch off
+
+	GMouseJitter	pen_jitter;								// PEN MODE: Jitter settings
+	GMouseJitter	finger_jitter;							// FINGER MODE: Jitter settings
+
+	bool_t	(*init)(GMouse *m, unsigned driverinstance);	// Required
+	void	(*deinit)(GMouse *m);							// Optional
+	bool_t	(*get)(GMouse *m, GMouseReading *prd);			// Required
+	void	(*calsave)(GMouse *m, const void *buf, size_t sz);	// Optional
+	bool_t	(*calload)(GMouse *m, void *buf, size_t sz);	// Optional
+} GMouseVMT;
+
+#define gmvmt(m)		((const GMouseVMT const *)((m)->d.vmt))
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+// If we are not using multiple mice then hard-code the VMT name
+#if !defined(GINPUT_MOUSE_DRIVER_LIST)
+	#undef GMOUSE_DRIVER_VMT
+	#define GMOUSE_DRIVER_VMT		GMOUSEVMT_OnlyOne
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+	/**
+	 * @brief	Initialize a mouse driver
+	 *
+	 * @param[in] g					The mouse driver
+	 * @param[in] display			The display to which the mouse shall be assigned
+	 * @param[in] driverinstance	The driver instance		ToDo: Add some more details
+	 * @param[in] systeminstance	The mouse instance		ToDo: Add some more details
+	 *
+	 * @return	TRUE on success, FALSE otherwise
+	 * @note	This routine is provided by the high level code for
+	 * 			use in the driver VMT's GMouseVMT.d structure.
+	 *
+	 * @notapi
+	 */
+	bool_t _gmouseInitDriver(GDriver *g, void *display, unsigned driverinstance, unsigned systeminstance);
+
+	/**
+	 * @brief	Routine that is called after initialization
+	 *
+	 * @param[in] g		The mouse driver
+	 * @note	This routine is provided by the high level code for
+	 * 			use in the driver VMT's GMouseVMT.d structure.
+	 *
+	 * @notapi
+	 */
+	void _gmousePostInitDriver(GDriver *g);
+
+	/**
+	 * @brief	Deinitialize a mouse driver
+	 *
+	 * @param[in] g		The mouse driver
+	 * @note	This routine is provided by the high level code for
+	 * 			use in the driver VMT's GMouseVMT.d structure.
+	 *
+	 * @notapi
+	 */
+	void _gmouseDeInitDriver(GDriver *g);
+
+	/**
+	 * @brief	Wakeup the high level code so that it attempts another read
+	 *
+	 * @note	This routine is provided to low level drivers by the high level code
+	 *
+	 * @notapi
+	 */
+	void _gmouseWakeup(GMouse *m);
+
+	/**
+	 * @brief	Wakeup the high level code so that it attempts another read
+	 *
+	 * @note	This routine is provided to low level drivers by the high level code
+	 *
+	 * @iclass
+	 * @notapi
+	 */
+	void _gmouseWakeupI(GMouse *m);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GINPUT_NEED_MOUSE */
+
+#endif /* _LLD_GINPUT_MOUSE_H */
+/** @} */
diff --git a/src/ginput/ginput_driver_toggle.h b/src/ginput/ginput_driver_toggle.h
new file mode 100644
index 00000000..0dced07b
--- /dev/null
+++ b/src/ginput/ginput_driver_toggle.h
@@ -0,0 +1,61 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/ginput_driver_toggle.h
+ * @brief   GINPUT header file for toggle drivers.
+ *
+ * @defgroup Toggle Toggle
+ * @ingroup GINPUT
+ * @{
+ */
+
+#ifndef _LLD_GINPUT_TOGGLE_H
+#define _LLD_GINPUT_TOGGLE_H
+
+#if GINPUT_NEED_TOGGLE || defined(__DOXYGEN__)
+
+// Describes how the toggle bits are obtained
+typedef struct GToggleConfig_t {
+	void		*id;
+	unsigned	mask;
+	unsigned	invert;
+	unsigned	mode;
+} GToggleConfig;
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	extern const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES];
+	
+	void ginput_lld_toggle_init(const GToggleConfig *ptc);
+	unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc);
+
+	/* This routine is provided to low level drivers to wakeup a value read from a thread context.
+	 *	Particularly useful if GINPUT_TOGGLE_POLL_PERIOD = TIME_INFINITE
+	 */
+	void ginputToggleWakeup(void);
+
+	/* This routine is provided to low level drivers to wakeup a value read from an ISR
+	 *	Particularly useful if GINPUT_TOGGLE_POLL_PERIOD = TIME_INFINITE
+	 */
+	void ginputToggleWakeupI(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GINPUT && GINPUT_NEED_TOGGLE */
+
+#endif /* _LLD_GINPUT_TOGGLE_H */
+/** @} */
+
diff --git a/src/ginput/ginput_ginput.c b/src/ginput/ginput_ginput.c
deleted file mode 100644
index becefc19..00000000
--- a/src/ginput/ginput_ginput.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/ginput_ginput.c
- * @brief   GINPUT subsystem common code.
- *
- * @addtogroup GINPUT
- * @{
- */
-#include "gfx.h"
-
-#if GFX_USE_GINPUT
-
-#if GINPUT_NEED_MOUSE
-    extern void _gmouseInit(void);
-    extern void _gmouseDeinit(void);
-#endif
-#if GINPUT_NEED_KEYBOARD
-    extern void _gkeyboardInit(void);
-    extern void _gkeyboardDeinit(void);
-#endif
-
-void _ginputInit(void)
-{
-    #if GINPUT_NEED_MOUSE
-        _gmouseInit();
-    #endif
-	#if GINPUT_NEED_KEYBOARD
-		_gkeyboardInit();
-	#endif
-	/**
-	 * This should really call an init routine for each ginput sub-system.
-	 * Maybe we'll do this later.
-	 */
-}
-
-void _ginputDeinit(void)
-{
-	#if GINPUT_NEED_KEYBOARD
-		_gkeyboardDeinit();
-	#endif
-    #if GINPUT_NEED_MOUSE
-        _gmouseDeinit();
-    #endif
-}
-
-#endif /* GFX_USE_GINPUT */
-/** @} */
-
diff --git a/src/ginput/ginput_keyboard.c b/src/ginput/ginput_keyboard.c
index 2d284eaa..eac2e9e0 100644
--- a/src/ginput/ginput_keyboard.c
+++ b/src/ginput/ginput_keyboard.c
@@ -21,8 +21,8 @@
 #endif
 
 // Get the keyboard driver interface
-#include "driver_keyboard.h"
-#include "keyboard_microcode.h"
+#include "ginput_driver_keyboard.h"
+#include "ginput_keyboard_microcode.h"
 
 // The keyboard poll timer
 static GTIMER_DECL(KeyboardTimer);
diff --git a/src/ginput/ginput_keyboard_microcode.c b/src/ginput/ginput_keyboard_microcode.c
new file mode 100644
index 00000000..e3c04d5f
--- /dev/null
+++ b/src/ginput/ginput_keyboard_microcode.c
@@ -0,0 +1,73 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/keyboard_microcode.c
+ * @brief   GINPUT keyboard standard microcode definitions.
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD && !GKEYBOARD_LAYOUT_OFF
+
+#include "keyboard_microcode.h"
+
+#if GKEYBOARD_LAYOUT_SCANCODE2_US
+
+	#error "Keyboard Layout SCANCODE2_US is not fully implemented yet"
+
+	uint8_t	KeyboardLayout_ScancodeSet2_US[] = {
+		KMC_HEADERSTART, KMC_HEADER_ID1, KMC_HEADER_ID2, KMC_HEADER_VER_1,
+
+		KMC_RECORDSTART, 0x03,													// Handle E0 codes (ignore for now assuming a single character)
+			KMC_TEST_LASTCODE, 0xE0,
+			KMC_ACT_DONE,
+		KMC_RECORDSTART, 0x03,
+			KMC_TEST_CODE, 0xE0,
+			KMC_ACT_STOP,
+
+		KMC_RECORDSTART, 0x03,													// Handle E1 codes (ignore for now assuming a single character)
+			KMC_TEST_LASTCODE, 0xE1,
+			KMC_ACT_DONE,
+		KMC_RECORDSTART, 0x03,
+			KMC_TEST_CODE, 0xE1,
+			KMC_ACT_STOP,
+
+		KMC_RECORDSTART, 0x03,													// Handle E2 codes (ignore for now assuming a single character)
+			KMC_TEST_LASTCODE, 0xE2,
+			KMC_ACT_DONE,
+		KMC_RECORDSTART, 0x03,
+			KMC_TEST_CODE, 0xE2,
+			KMC_ACT_STOP,
+
+		KMC_RECORDSTART, 0x06,													// KeyUp
+			KMC_TEST_CODEBIT, 0x80,
+			KMC_ACT_STATEBIT, GKEYSTATE_KEYUP_BIT,
+			KMC_ACT_CODEBIT, 0x80 | KMC_BIT_CLEAR,
+
+		KMC_RECORDSTART, 0x05,													// CapsLock (on keyup to avoid repeats)
+			KMC_TEST_CODE, 0x58,
+			KMC_TEST_STATEBIT, GKEYSTATE_KEYUP_BIT | KMC_BIT_CLEAR,
+			KMC_ACT_DONE,
+		KMC_RECORDSTART, 0x05,
+			KMC_TEST_CODE, 0x58,
+			KMC_ACT_STATEBIT, GKEYSTATE_CAPSLOCK_BIT | KMC_BIT_INVERT,
+			KMC_ACT_DONE,
+
+		KMC_RECORDSTART, 0x05,													// Detect Shift Keys
+			//KMC_ACT_LAYOUTBIT, SCANCODESET2_LAYOUT_E0_BIT | KMC_BIT_CLEAR,
+			KMC_ACT_STOP,
+
+		KMC_RECORDSTART, 0x03,
+			KMC_ACT_CHARRANGE, 0x00,
+			KMC_ACT_DONE,
+
+		KMC_RECORDSTART, 0x00,
+	};
+#endif // GKEYBOARD_LAYOUT_SCANCODE2_US
+
+#endif // GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD && !GKEYBOARD_LAYOUT_OFF
diff --git a/src/ginput/ginput_keyboard_microcode.h b/src/ginput/ginput_keyboard_microcode.h
new file mode 100644
index 00000000..c18e94e5
--- /dev/null
+++ b/src/ginput/ginput_keyboard_microcode.h
@@ -0,0 +1,107 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/keyboard_microcode.h
+ * @brief   GINPUT keyboard layout microcode definition.
+ */
+
+#ifndef _KEYBOARD_MICROCODE_H
+#define _KEYBOARD_MICROCODE_H
+
+/*
+ * Keyboard Layout Microcode Definition
+ *
+ * Each time a byte is received from the keyboard it is processed through the layout microcode engine. This enables conversion from
+ * 	scancodes to ascii, internationalization, and various other tricky keyboard behavior.
+ * Note a "code" is defined as a single byte of data from the keyboard, a "scancode" is one or more "codes" that are sent in response to one keyboard press or release.
+ *
+ * The layout microcode can even be switched on the fly by the application to effect such changes as changing from US English to Russian layouts.
+ *	They could conceivably even be loaded from disk at run-time.
+ *
+ * In the interest of efficiency there is very little error checking. Make sure your layout microcode has been debugged properly before releasing
+ * 	to production code.
+ *
+ * Layout microcode consists of a header followed by 1 or more records.
+ *
+ * The header consists of a KMC_HEADERSTART and associated bytes. The is used only to check it looks like it might be layout microcode and to specify the
+ * 	version of microcode. Future versions of layout microcode will always have the same header at least to the version number.
+ *
+ * Each record is delimited by a KMC_RECORDSTART. Each record can contain a maximum of 255 bytes.
+ * 	A record length of zero indicates the end of the layout microcode.
+ *
+ * A record consists a mixture of tests and actions (normally the tests are first). If a test fails the rest of this record is skipped and the next
+ * 	record is processed. This has the effect of AND'ing multiple tests that occur together.
+ * 	KMC_TEST_INIT and KMC_TEST_ERROR are special. These tests must be the first byte in their respective record as without this test being there, there
+ * 	is an implicit test that a code has actually been received.
+ * 	If no records have successful tests for this code then by extension no actions are executed. That is, the code is ignored.
+ * 	After fully processing a record, the next record is processed. This can be prevented by using the KMC_ACT_STOP action. When encountered all processing
+ * 	on this code stops.
+ *
+ * Some tests set a pseudo variable called "diff". This is then used by some actions. At the start of a new record "diff" is set to "code" (or 0 for the init and
+ * 	error conditions).
+ * Some tests and actions do bit operations on either the saved key-state or on the code itself. Bit numbers (which can range from 0 to 31) test or affect the
+ * 	"set" state of the bit. OR'ing KMC_BIT_CLEAR with the bit number test or affect the "clear" state of the bit. For example, KMC_ACT_STATEBIT with a parameter
+ * 	of 10 will set bit 10 of the key-state. KMC_ACT_STATEBIT with a parameter of (10 | KMC_BIT_CLEAR) will clear bit 10 of the key-state.
+ *
+ */
+
+#define KMC_HEADERSTART		0x00	// Followed by:	ID1 ID2 VER		- This is the start of layout microcode.
+	#define KMC_HEADER_ID1		'L'
+	#define KMC_HEADER_ID2		'M'
+	#define KMC_HEADER_VER_1	0x01
+
+	#define KMC_HEADER_VER_CURRENT	KMC_HEADER_VER_1	// The current version number
+	#define KMC_HEADER_VER_MIN		KMC_HEADER_VER_1	// The minimum version number accepted
+	#define KMC_HEADER_VER_MAX		KMC_HEADER_VER_1	// The maximum version number accepted
+
+#define KMC_RECORDSTART		0x01	// Followed by:	nn b0 b1 ... b(nn-1)	- nn bytes of test and action follow, nn = 00 means end of all tests
+
+#define KMC_TEST_INIT		0x10	// Followed by:	nothing			- The layout is initializing
+#define KMC_TEST_ERROR		0x11	// Followed by:	nothing			- The keyboard has signaled an error
+#define KMC_TEST_CODE		0x12	// Followed by:	aa				- Code must equal aa. Diff is set to 0
+#define KMC_TEST_CODERANGE	0x13	// Followed by:	aa bb			- Code must be between aa and bb (inclusive). Diff is set to (code - aa)
+#define KMC_TEST_CODETABLE	0x14	// Followed by:	n m1 m2 ...		- Code must equal an m value. There are n possible m values. Diff is set to 0 to n-1 (the match position)
+#define KMC_TEST_STATEBIT	0x15	// Followed by:	b				- Test if a key-state bit is set/clear. b = 0 to 31 or b = (0 | KMC_BIT_CLEAR) to (31 | KMC_BIT_CLEAR)
+#define KMC_TEST_STATEOR	0x16	// Followed by:	b1 b2			- Test two key-state bits and OR the result
+#define KMC_TEST_STATEAND	0x17	// Followed by:	b1 b2			- Test two key-state bits and AND the result
+#define KMC_TEST_LAYOUTBIT	0x18	// Followed by:	b				- Test if a layout bit is set/clear. b = 0 to 15 or b = (0 | KMC_BIT_CLEAR) to (15 | KMC_BIT_CLEAR)
+#define KMC_TEST_LAYOUTOR	0x19	// Followed by:	b1 b2			- Test two layout bits and OR the result
+#define KMC_TEST_LAYOUTAND	0x1A	// Followed by:	b1 b2			- Test two layout bits and AND the result
+#define KMC_TEST_CODEBIT	0x1B	// Followed by:	b				- Test if a code bit is set/clear. b = 0 to 7 or b = (0 | KMC_BIT_CLEAR) to (7 | KMC_BIT_CLEAR)
+#define KMC_TEST_CODEOR		0x1C	// Followed by:	b1 b2			- Test two code bits and OR the result
+#define KMC_TEST_CODEAND	0x1D	// Followed by:	b1 b2			- Test two code bits and AND the result
+#define KMC_TEST_LASTCODE	0x1E	// Followed by:	aa				- Test if the last scancode was aa
+#define KMC_TEST_SHIFT		0x20	// Followed by: nothing			- Test if a shift key is down
+#define KMC_TEST_NOSHIFT	0x21	// Followed by: nothing			- Test if a shift key is not down
+#define KMC_TEST_CTRL		0x22	// Followed by: nothing			- Test if a control key is down
+#define KMC_TEST_NOCTRL		0x23	// Followed by: nothing			- Test if a control key is not down
+#define KMC_TEST_ALT		0x24	// Followed by: nothing			- Test if an alt key is down
+#define KMC_TEST_NOALT		0x25	// Followed by: nothing			- Test if an alt key is not down
+#define KMC_TEST_CAPS		0x26	// Followed by: nothing			- Test if capslock as modified by shift is active
+#define KMC_TEST_NOCAPS		0x27	// Followed by: nothing			- Test if capslock as modified by shift is not active
+#define KMC_TEST_NUMLOCK	0x28	// Followed by: nothing			- Test if numlock is active
+#define KMC_TEST_NONUMLOCK	0x29	// Followed by: nothing			- Test if numlock is not active
+
+#define KMC_ACT_STOP		0xFF	// Followed by:	nothing			- Stop processing this code
+#define KMC_ACT_DONE		0xFE	// Followed by:	nothing			- Finished processing this scancode sequence. (also implies STOP)
+#define KMC_ACT_RESET		0xFD	// Followed by:	nothing			- Empty all buffers
+#define KMC_ACT_STATEBIT	0x80	// Followed by:	b				- Set or clear bit b in key-state. b = 0 to 31 or b = (0 | KMC_BIT_CLEAR) to (31 | KMC_BIT_CLEAR)
+#define KMC_ACT_LAYOUTBIT	0x81	// Followed by:	b				- Set or clear bit b in layout bits. b = 0 to 15 or b = (0 | KMC_BIT_CLEAR) to (15 | KMC_BIT_CLEAR)
+#define KMC_ACT_CODEBIT		0x82	// Followed by:	b				- Set or clear bit b in code. b = 0 to 7 or b = (0 | KMC_BIT_CLEAR) to (7 | KMC_BIT_CLEAR)
+#define KMC_ACT_CHAR		0x83	// Followed by:	nn				- Append char nn to output buffer
+#define KMC_ACT_CHARCODE	0x84	// Followed by:	nothing			- Append the code to output buffer
+#define KMC_ACT_CHARRANGE	0x85	// Followed by:	nn				- Append char nn + Diff to output
+#define KMC_ACT_CHARTABLE	0x86	// Followed by:	n c1 c2 ...		- Append char to output based on c[Diff]. If Diff is greater than n then nothing is appended.
+#define KMC_ACT_CLEAR		0x87	// Followed by: nothing			- Clear the output buffer
+#define KMC_ACT_CHARADD		0x88	// Followed by:	nn				- Multiple the last char in output buffer by nn (assume 0 if none) and add Diff
+#define KMC_ACT_DATA		0x89	// Followed by:	nn				- Send nn back to the keyboard
+
+#define KMC_BIT_CLEAR		0x80	// The bit number is being used for a bit clear operation rather than a bit set operation.
+#define KMC_BIT_INVERT		0x40	// Invert the bit rather than setting or clearing it.
+
+#endif /* _KEYBOARD_MICROCODE_H */
diff --git a/src/ginput/ginput_mouse.c b/src/ginput/ginput_mouse.c
index 9ecf7dc7..f88c2ded 100644
--- a/src/ginput/ginput_mouse.c
+++ b/src/ginput/ginput_mouse.c
@@ -46,7 +46,7 @@
 #define CALIBRATION_ERROR_HEIGHT		40
 
 // Get the mouse driver interface
-#include "driver_mouse.h"
+#include "ginput_driver_mouse.h"
 
 // The mouse poll timer
 static GTIMER_DECL(MouseTimer);
diff --git a/src/ginput/ginput_options.h b/src/ginput/ginput_options.h
new file mode 100644
index 00000000..3d3478d2
--- /dev/null
+++ b/src/ginput/ginput_options.h
@@ -0,0 +1,221 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/ginput_options.h
+ * @brief   GINPUT sub-system options header file.
+ *
+ * @addtogroup GINPUT
+ * @{
+ */
+
+#ifndef _GINPUT_OPTIONS_H
+#define _GINPUT_OPTIONS_H
+
+/**
+ * @name    GINPUT Functionality to be included
+ * @{
+ */
+	/**
+	 * @brief   Should mouse/touch functions be included.
+	 * @details	Defaults to FALSE
+	 * @note	Also add a mouse/touch hardware driver to your makefile.
+	 * 			Eg.
+	 * 				include $(GFXLIB)/drivers/ginput/touch/MCU/driver.mk
+	 */
+	#ifndef GINPUT_NEED_MOUSE
+		#define GINPUT_NEED_MOUSE		FALSE
+	#endif
+	/**
+	 * @brief   Should keyboard functions be included.
+	 * @details	Defaults to FALSE
+	 * @note	Also add a keyboard hardware driver to your makefile.
+	 * 			Eg.
+	 * 				include $(GFXLIB)/drivers/ginput/keyboard/XXXX/driver.mk
+	 */
+	#ifndef GINPUT_NEED_KEYBOARD
+		#define GINPUT_NEED_KEYBOARD	FALSE
+	#endif
+	/**
+	 * @brief   Should hardware toggle/switch/button functions be included.
+	 * @details	Defaults to FALSE
+	 * @note	Also add a toggle hardware driver to your makefile.
+	 * 			Eg.
+	 * 				include $(GFXLIB)/drivers/ginput/toggle/Pal/driver.mk
+	 */
+	#ifndef GINPUT_NEED_TOGGLE
+		#define GINPUT_NEED_TOGGLE		FALSE
+	#endif
+	/**
+	 * @brief   Should analog dial functions be included.
+	 * @details	Defaults to FALSE
+	 * @note	Also add a dial hardware driver to your makefile.
+	 * 			Eg.
+	 * 				include $(GFXLIB)/drivers/ginput/dial/analog/driver.mk
+	 */
+	#ifndef GINPUT_NEED_DIAL
+		#define GINPUT_NEED_DIAL		FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GINPUT Optional Sizing Parameters
+ * @{
+ */
+/**
+ * @}
+ *
+ * @name    GINPUT Optional Low Level Driver Defines
+ * @{
+ */
+	/**
+	 * @brief   Start touch devices without loading or running calibration.
+	 * @details	Defaults to FALSE
+	 * @note	This is used if you want to manually control the initial calibration
+	 * 			process. In practice this is only useful for a touch driver test program.
+	 */
+	#ifndef GINPUT_TOUCH_STARTRAW
+		#define GINPUT_TOUCH_STARTRAW					FALSE
+	#endif
+ 	/**
+	 * @brief   Turn off the touch calibration GUI.
+	 * @details	Defaults to FALSE
+	 * @note	Turning off the calibration GUI just turns off the manual calibration
+	 * 			process. Readings may still be calibrated if calibration data
+	 * 			can be loaded.
+	 * @note	Calibration requires a lot of code. If your device doesn't require it
+	 * 			using this option can save a lot of space.
+	 */
+	#ifndef GINPUT_TOUCH_NOCALIBRATE_GUI
+		#define GINPUT_TOUCH_NOCALIBRATE_GUI			FALSE
+	#endif
+	/**
+	 * @brief   Turn off all touch calibration support.
+	 * @details	Defaults to FALSE
+	 * @note	With this set to TRUE touch readings will not be calibrated.
+	 * @note	This automatically turns off the calibration GUI too!
+	 * @note	Calibration requires a lot of code. If your device doesn't require it
+	 * 			using this option can save a lot of space.
+	 */
+	#ifndef GINPUT_TOUCH_NOCALIBRATE
+		#define GINPUT_TOUCH_NOCALIBRATE				FALSE
+	#endif
+	/**
+	 * @brief   Turn off all touch support.
+	 * @details	Defaults to FALSE
+	 * @note	This automatically turns off all calibration and the calibration GUI too!
+	 * @note	Touch device handling requires a lot of code. If your device doesn't require it
+	 * 			using this option can save a lot of space.
+	 */
+	#ifndef GINPUT_TOUCH_NOTOUCH
+		#define GINPUT_TOUCH_NOTOUCH					FALSE
+	#endif
+	/**
+	 * @brief   Milliseconds between mouse polls.
+	 * @details	Defaults to 25 milliseconds
+	 * @note	How often mice should be polled. More often leads to smoother mouse movement
+	 * 			but increases CPU usage.
+	 */
+	#ifndef GINPUT_MOUSE_POLL_PERIOD
+		#define GINPUT_MOUSE_POLL_PERIOD				25
+	#endif
+
+	/**
+	 * @brief   Maximum length of CLICK in milliseconds
+	 * @details	Defaults to 300 milliseconds
+	 * @note	Mouse down to Mouse up times greater than this are not clicks.
+	 */
+	#ifndef GINPUT_MOUSE_CLICK_TIME
+		#define GINPUT_MOUSE_CLICK_TIME					300
+	#endif
+	/**
+	 * @brief   Milliseconds to generate a CXTCLICK on a touch device.
+	 * @details	Defaults to 500 milliseconds
+	 * @note	If you hold the touch down for longer than this a CXTCLICK is generated
+	 * 			but only on a touch device.
+	 */
+	#ifndef GINPUT_TOUCH_CXTCLICK_TIME
+		#define GINPUT_TOUCH_CXTCLICK_TIME				500
+	#endif
+   /**
+     * @brief   There is a user supplied routine to load mouse calibration data
+	 * @details	Defaults to FALSE
+     * @note    If TRUE the user must supply the @p LoadMouseCalibration() routine.
+     */
+	#ifndef GINPUT_TOUCH_USER_CALIBRATION_LOAD
+		#define GINPUT_TOUCH_USER_CALIBRATION_LOAD		FALSE
+	#endif
+   /**
+     * @brief   There is a user supplied routine to save mouse calibration data
+	 * @details	Defaults to FALSE
+     * @note    If TRUE the user must supply the @p SaveMouseCalibration() routine.
+     */
+	#ifndef GINPUT_TOUCH_USER_CALIBRATION_SAVE
+		#define GINPUT_TOUCH_USER_CALIBRATION_SAVE		FALSE
+	#endif
+   /**
+     * @brief   Define multiple static mice
+	 * @details	When not defined the system automatically detects a single linked mouse driver
+	 * @note	The references to GMOUSEVMT_Win32 in the definition would be replaced
+	 * 			by the names of the VMT for each of the static mice you want to
+	 * 			include.
+	 * @note	Dynamic mice associated automatically with a display eg Win32, X or GFXnet
+	 * 			do not need to be specified in this list as the associated display driver will register
+	 * 			them automatically as the display is created.
+     */
+	#if defined(__DOXYGEN__)
+		#define GMOUSE_DRIVER_LIST						GMOUSEVMT_Win32, GMOUSEVMT_Win32
+	#endif
+	/**
+	 * @brief   Milliseconds between keyboard polls.
+	 * @details	Defaults to 200 milliseconds
+	 * @note	How often keyboards should be polled.
+	 */
+	#ifndef GINPUT_KEYBOARD_POLL_PERIOD
+		#define GINPUT_KEYBOARD_POLL_PERIOD				200
+	#endif
+   /**
+     * @brief   Define multiple static keyboards
+	 * @details	When not defined the system automatically detects a single linked keyboard driver
+	 * @note	The references to GKEYBOARDVMT_Win32 in the definition would be replaced
+	 * 			by the names of the VMT for each of the static keyboards you want to
+	 * 			include.
+	 * @note	Dynamic keyboards associated automatically with a display eg Win32, X or GFXnet
+	 * 			do not need to be specified in this list as the display driver will register
+	 * 			them automatically as the display is created.
+     */
+	#if defined(__DOXYGEN__)
+		#define GKEYBOARD_DRIVER_LIST					GMOUSEVMT_Win32, GMOUSEVMT_Win32
+	#endif
+   /**
+     * @brief   Turn off the layout engine.
+	 * @details	When defined the layout engine is removed from the code and characters
+	 * 			are passed directly from the keyboard driver to the application.
+	 * @note	Turning off the layout engine just saves code if it is not needed.
+     */
+	#ifndef GKEYBOARD_LAYOUT_OFF
+		#define GKEYBOARD_LAYOUT_OFF					FALSE
+	#endif
+	/**
+	 * @brief   Various Keyboard Layouts that can be included.
+	 * @details	A keyboard layout controls conversion of scancodes to characters
+	 * 			and enables one keyboard to have multiple language mappings.
+	 * @note	Defining a layout does not make it active. The keyboard driver
+	 * 			must have it active as the default or the application must
+	 * 			use @p ginputSetKeyboardLayout() to set the active layout.
+	 * @note	Multiple layouts can be included but only one will be active
+	 * 			at a time (per keyboard).
+	 * @{
+	 */
+	#ifndef GKEYBOARD_LAYOUT_SCANCODE2_US
+		#define GKEYBOARD_LAYOUT_SCANCODE2_US			FALSE				// US Keyboard using the ScanCode 2 set.
+	#endif
+	/** @} */
+/** @} */
+
+#endif /* _GINPUT_OPTIONS_H */
+/** @} */
diff --git a/src/ginput/ginput_rules.h b/src/ginput/ginput_rules.h
new file mode 100644
index 00000000..6d997f90
--- /dev/null
+++ b/src/ginput/ginput_rules.h
@@ -0,0 +1,52 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/ginput/ginput_rules.h
+ * @brief   GINPUT safety rules header file.
+ *
+ * @addtogroup GINPUT
+ * @{
+ */
+
+#ifndef _GINPUT_RULES_H
+#define _GINPUT_RULES_H
+
+#if GFX_USE_GINPUT
+	#if !GFX_USE_GEVENT
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GINPUT: GFX_USE_GEVENT is required if GFX_USE_GINPUT is TRUE. It has been turned on for you."
+		#endif
+		#undef GFX_USE_GEVENT
+		#define	GFX_USE_GEVENT		TRUE
+	#endif
+	#if !GFX_USE_GTIMER
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GINPUT: GFX_USE_GTIMER is required if GFX_USE_GINPUT is TRUE. It has been turned on for you."
+		#endif
+		#undef GFX_USE_GTIMER
+		#define	GFX_USE_GTIMER		TRUE
+	#endif
+	#if GINPUT_NEED_MOUSE
+		#if GINPUT_TOUCH_NOTOUCH
+			// No warning needed for this
+			#undef GINPUT_TOUCH_NOCALIBRATE
+			#define GINPUT_TOUCH_NOCALIBRATE	TRUE
+		#endif
+		#if GINPUT_TOUCH_NOCALIBRATE
+			// No warning needed for this
+			#undef GINPUT_TOUCH_NOCALIBRATE_GUI
+			#define GINPUT_TOUCH_NOCALIBRATE_GUI	TRUE
+		#endif
+		#if !GINPUT_TOUCH_NOTOUCH && GINPUT_MOUSE_CLICK_TIME > GINPUT_TOUCH_CXTCLICK_TIME
+			#error "GINPUT MOUSE: The GINPUT_MOUSE_CLICK_TIME must be <= GINPUT_TOUCH_CXTCLICK_TIME"
+		#endif
+	#endif
+#endif
+
+#endif /* _GINPUT_RULES_H */
+/** @} */
diff --git a/src/ginput/ginput_toggle.c b/src/ginput/ginput_toggle.c
index 4c6dc9ae..9ef945fa 100644
--- a/src/ginput/ginput_toggle.c
+++ b/src/ginput/ginput_toggle.c
@@ -17,7 +17,7 @@
 
 #if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) || defined(__DOXYGEN__)
 
-#include "driver_toggle.h"
+#include "ginput_driver_toggle.h"
 
 #define GINPUT_TOGGLE_ISON		0x01
 #define GINPUT_TOGGLE_INVERT	0x02
diff --git a/src/ginput/keyboard_microcode.c b/src/ginput/keyboard_microcode.c
deleted file mode 100644
index e3c04d5f..00000000
--- a/src/ginput/keyboard_microcode.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/keyboard_microcode.c
- * @brief   GINPUT keyboard standard microcode definitions.
- */
-
-#include "gfx.h"
-
-#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD && !GKEYBOARD_LAYOUT_OFF
-
-#include "keyboard_microcode.h"
-
-#if GKEYBOARD_LAYOUT_SCANCODE2_US
-
-	#error "Keyboard Layout SCANCODE2_US is not fully implemented yet"
-
-	uint8_t	KeyboardLayout_ScancodeSet2_US[] = {
-		KMC_HEADERSTART, KMC_HEADER_ID1, KMC_HEADER_ID2, KMC_HEADER_VER_1,
-
-		KMC_RECORDSTART, 0x03,													// Handle E0 codes (ignore for now assuming a single character)
-			KMC_TEST_LASTCODE, 0xE0,
-			KMC_ACT_DONE,
-		KMC_RECORDSTART, 0x03,
-			KMC_TEST_CODE, 0xE0,
-			KMC_ACT_STOP,
-
-		KMC_RECORDSTART, 0x03,													// Handle E1 codes (ignore for now assuming a single character)
-			KMC_TEST_LASTCODE, 0xE1,
-			KMC_ACT_DONE,
-		KMC_RECORDSTART, 0x03,
-			KMC_TEST_CODE, 0xE1,
-			KMC_ACT_STOP,
-
-		KMC_RECORDSTART, 0x03,													// Handle E2 codes (ignore for now assuming a single character)
-			KMC_TEST_LASTCODE, 0xE2,
-			KMC_ACT_DONE,
-		KMC_RECORDSTART, 0x03,
-			KMC_TEST_CODE, 0xE2,
-			KMC_ACT_STOP,
-
-		KMC_RECORDSTART, 0x06,													// KeyUp
-			KMC_TEST_CODEBIT, 0x80,
-			KMC_ACT_STATEBIT, GKEYSTATE_KEYUP_BIT,
-			KMC_ACT_CODEBIT, 0x80 | KMC_BIT_CLEAR,
-
-		KMC_RECORDSTART, 0x05,													// CapsLock (on keyup to avoid repeats)
-			KMC_TEST_CODE, 0x58,
-			KMC_TEST_STATEBIT, GKEYSTATE_KEYUP_BIT | KMC_BIT_CLEAR,
-			KMC_ACT_DONE,
-		KMC_RECORDSTART, 0x05,
-			KMC_TEST_CODE, 0x58,
-			KMC_ACT_STATEBIT, GKEYSTATE_CAPSLOCK_BIT | KMC_BIT_INVERT,
-			KMC_ACT_DONE,
-
-		KMC_RECORDSTART, 0x05,													// Detect Shift Keys
-			//KMC_ACT_LAYOUTBIT, SCANCODESET2_LAYOUT_E0_BIT | KMC_BIT_CLEAR,
-			KMC_ACT_STOP,
-
-		KMC_RECORDSTART, 0x03,
-			KMC_ACT_CHARRANGE, 0x00,
-			KMC_ACT_DONE,
-
-		KMC_RECORDSTART, 0x00,
-	};
-#endif // GKEYBOARD_LAYOUT_SCANCODE2_US
-
-#endif // GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD && !GKEYBOARD_LAYOUT_OFF
diff --git a/src/ginput/keyboard_microcode.h b/src/ginput/keyboard_microcode.h
deleted file mode 100644
index c18e94e5..00000000
--- a/src/ginput/keyboard_microcode.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/keyboard_microcode.h
- * @brief   GINPUT keyboard layout microcode definition.
- */
-
-#ifndef _KEYBOARD_MICROCODE_H
-#define _KEYBOARD_MICROCODE_H
-
-/*
- * Keyboard Layout Microcode Definition
- *
- * Each time a byte is received from the keyboard it is processed through the layout microcode engine. This enables conversion from
- * 	scancodes to ascii, internationalization, and various other tricky keyboard behavior.
- * Note a "code" is defined as a single byte of data from the keyboard, a "scancode" is one or more "codes" that are sent in response to one keyboard press or release.
- *
- * The layout microcode can even be switched on the fly by the application to effect such changes as changing from US English to Russian layouts.
- *	They could conceivably even be loaded from disk at run-time.
- *
- * In the interest of efficiency there is very little error checking. Make sure your layout microcode has been debugged properly before releasing
- * 	to production code.
- *
- * Layout microcode consists of a header followed by 1 or more records.
- *
- * The header consists of a KMC_HEADERSTART and associated bytes. The is used only to check it looks like it might be layout microcode and to specify the
- * 	version of microcode. Future versions of layout microcode will always have the same header at least to the version number.
- *
- * Each record is delimited by a KMC_RECORDSTART. Each record can contain a maximum of 255 bytes.
- * 	A record length of zero indicates the end of the layout microcode.
- *
- * A record consists a mixture of tests and actions (normally the tests are first). If a test fails the rest of this record is skipped and the next
- * 	record is processed. This has the effect of AND'ing multiple tests that occur together.
- * 	KMC_TEST_INIT and KMC_TEST_ERROR are special. These tests must be the first byte in their respective record as without this test being there, there
- * 	is an implicit test that a code has actually been received.
- * 	If no records have successful tests for this code then by extension no actions are executed. That is, the code is ignored.
- * 	After fully processing a record, the next record is processed. This can be prevented by using the KMC_ACT_STOP action. When encountered all processing
- * 	on this code stops.
- *
- * Some tests set a pseudo variable called "diff". This is then used by some actions. At the start of a new record "diff" is set to "code" (or 0 for the init and
- * 	error conditions).
- * Some tests and actions do bit operations on either the saved key-state or on the code itself. Bit numbers (which can range from 0 to 31) test or affect the
- * 	"set" state of the bit. OR'ing KMC_BIT_CLEAR with the bit number test or affect the "clear" state of the bit. For example, KMC_ACT_STATEBIT with a parameter
- * 	of 10 will set bit 10 of the key-state. KMC_ACT_STATEBIT with a parameter of (10 | KMC_BIT_CLEAR) will clear bit 10 of the key-state.
- *
- */
-
-#define KMC_HEADERSTART		0x00	// Followed by:	ID1 ID2 VER		- This is the start of layout microcode.
-	#define KMC_HEADER_ID1		'L'
-	#define KMC_HEADER_ID2		'M'
-	#define KMC_HEADER_VER_1	0x01
-
-	#define KMC_HEADER_VER_CURRENT	KMC_HEADER_VER_1	// The current version number
-	#define KMC_HEADER_VER_MIN		KMC_HEADER_VER_1	// The minimum version number accepted
-	#define KMC_HEADER_VER_MAX		KMC_HEADER_VER_1	// The maximum version number accepted
-
-#define KMC_RECORDSTART		0x01	// Followed by:	nn b0 b1 ... b(nn-1)	- nn bytes of test and action follow, nn = 00 means end of all tests
-
-#define KMC_TEST_INIT		0x10	// Followed by:	nothing			- The layout is initializing
-#define KMC_TEST_ERROR		0x11	// Followed by:	nothing			- The keyboard has signaled an error
-#define KMC_TEST_CODE		0x12	// Followed by:	aa				- Code must equal aa. Diff is set to 0
-#define KMC_TEST_CODERANGE	0x13	// Followed by:	aa bb			- Code must be between aa and bb (inclusive). Diff is set to (code - aa)
-#define KMC_TEST_CODETABLE	0x14	// Followed by:	n m1 m2 ...		- Code must equal an m value. There are n possible m values. Diff is set to 0 to n-1 (the match position)
-#define KMC_TEST_STATEBIT	0x15	// Followed by:	b				- Test if a key-state bit is set/clear. b = 0 to 31 or b = (0 | KMC_BIT_CLEAR) to (31 | KMC_BIT_CLEAR)
-#define KMC_TEST_STATEOR	0x16	// Followed by:	b1 b2			- Test two key-state bits and OR the result
-#define KMC_TEST_STATEAND	0x17	// Followed by:	b1 b2			- Test two key-state bits and AND the result
-#define KMC_TEST_LAYOUTBIT	0x18	// Followed by:	b				- Test if a layout bit is set/clear. b = 0 to 15 or b = (0 | KMC_BIT_CLEAR) to (15 | KMC_BIT_CLEAR)
-#define KMC_TEST_LAYOUTOR	0x19	// Followed by:	b1 b2			- Test two layout bits and OR the result
-#define KMC_TEST_LAYOUTAND	0x1A	// Followed by:	b1 b2			- Test two layout bits and AND the result
-#define KMC_TEST_CODEBIT	0x1B	// Followed by:	b				- Test if a code bit is set/clear. b = 0 to 7 or b = (0 | KMC_BIT_CLEAR) to (7 | KMC_BIT_CLEAR)
-#define KMC_TEST_CODEOR		0x1C	// Followed by:	b1 b2			- Test two code bits and OR the result
-#define KMC_TEST_CODEAND	0x1D	// Followed by:	b1 b2			- Test two code bits and AND the result
-#define KMC_TEST_LASTCODE	0x1E	// Followed by:	aa				- Test if the last scancode was aa
-#define KMC_TEST_SHIFT		0x20	// Followed by: nothing			- Test if a shift key is down
-#define KMC_TEST_NOSHIFT	0x21	// Followed by: nothing			- Test if a shift key is not down
-#define KMC_TEST_CTRL		0x22	// Followed by: nothing			- Test if a control key is down
-#define KMC_TEST_NOCTRL		0x23	// Followed by: nothing			- Test if a control key is not down
-#define KMC_TEST_ALT		0x24	// Followed by: nothing			- Test if an alt key is down
-#define KMC_TEST_NOALT		0x25	// Followed by: nothing			- Test if an alt key is not down
-#define KMC_TEST_CAPS		0x26	// Followed by: nothing			- Test if capslock as modified by shift is active
-#define KMC_TEST_NOCAPS		0x27	// Followed by: nothing			- Test if capslock as modified by shift is not active
-#define KMC_TEST_NUMLOCK	0x28	// Followed by: nothing			- Test if numlock is active
-#define KMC_TEST_NONUMLOCK	0x29	// Followed by: nothing			- Test if numlock is not active
-
-#define KMC_ACT_STOP		0xFF	// Followed by:	nothing			- Stop processing this code
-#define KMC_ACT_DONE		0xFE	// Followed by:	nothing			- Finished processing this scancode sequence. (also implies STOP)
-#define KMC_ACT_RESET		0xFD	// Followed by:	nothing			- Empty all buffers
-#define KMC_ACT_STATEBIT	0x80	// Followed by:	b				- Set or clear bit b in key-state. b = 0 to 31 or b = (0 | KMC_BIT_CLEAR) to (31 | KMC_BIT_CLEAR)
-#define KMC_ACT_LAYOUTBIT	0x81	// Followed by:	b				- Set or clear bit b in layout bits. b = 0 to 15 or b = (0 | KMC_BIT_CLEAR) to (15 | KMC_BIT_CLEAR)
-#define KMC_ACT_CODEBIT		0x82	// Followed by:	b				- Set or clear bit b in code. b = 0 to 7 or b = (0 | KMC_BIT_CLEAR) to (7 | KMC_BIT_CLEAR)
-#define KMC_ACT_CHAR		0x83	// Followed by:	nn				- Append char nn to output buffer
-#define KMC_ACT_CHARCODE	0x84	// Followed by:	nothing			- Append the code to output buffer
-#define KMC_ACT_CHARRANGE	0x85	// Followed by:	nn				- Append char nn + Diff to output
-#define KMC_ACT_CHARTABLE	0x86	// Followed by:	n c1 c2 ...		- Append char to output based on c[Diff]. If Diff is greater than n then nothing is appended.
-#define KMC_ACT_CLEAR		0x87	// Followed by: nothing			- Clear the output buffer
-#define KMC_ACT_CHARADD		0x88	// Followed by:	nn				- Multiple the last char in output buffer by nn (assume 0 if none) and add Diff
-#define KMC_ACT_DATA		0x89	// Followed by:	nn				- Send nn back to the keyboard
-
-#define KMC_BIT_CLEAR		0x80	// The bit number is being used for a bit clear operation rather than a bit set operation.
-#define KMC_BIT_INVERT		0x40	// Invert the bit rather than setting or clearing it.
-
-#endif /* _KEYBOARD_MICROCODE_H */
diff --git a/src/ginput/sys_defs.h b/src/ginput/sys_defs.h
deleted file mode 100644
index cab1e15d..00000000
--- a/src/ginput/sys_defs.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/sys_defs.h
- *
- * @addtogroup GINPUT
- *
- * @brief		Module to interface different hardware input sources such as touchscreens
- *
- * @details		GINPUT provides an easy and common interface to use different input devices
- *				such as touchscreens and mices.
- *
- * @pre			GFX_USE_GINPUT must be set to TRUE in your gfxconf.h
- *
- * @{
- */
-#ifndef _GINPUT_H
-#define _GINPUT_H
-
-#include "gfx.h"
-
-#if GFX_USE_GINPUT || defined(__DOXYGEN__)
-
-/* How to use...
-
-	1. Get source handles for all the inputs you are interested in.
-		- Attempting to get a handle for one instance of an input more than once will return the same handle
-	2. Create a listener
-	3. Assign inputs to your listener.
-		- Inputs can be assigned or released from a listener at any time.
-		- An input can be assigned to more than one listener.
-	4. Loop on getting listener events
-	5. When complete destroy the listener
-*/
-
-// Include various ginput types
-#include "ginput_mouse.h"
-#include "ginput_keyboard.h"
-#include "ginput_toggle.h"
-#include "ginput_dial.h"
-
-#endif /* GFX_USE_GINPUT */
-
-#endif /* _GINPUT_H */
-/** @} */
diff --git a/src/ginput/sys_make.mk b/src/ginput/sys_make.mk
deleted file mode 100644
index 6adb2e4c..00000000
--- a/src/ginput/sys_make.mk
+++ /dev/null
@@ -1,6 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/ginput/ginput_ginput.c \
-			$(GFXLIB)/src/ginput/ginput_mouse.c \
-			$(GFXLIB)/src/ginput/ginput_keyboard.c \
-			$(GFXLIB)/src/ginput/keyboard_microcode.c \
-			$(GFXLIB)/src/ginput/ginput_toggle.c \
-			$(GFXLIB)/src/ginput/ginput_dial.c
diff --git a/src/ginput/sys_options.h b/src/ginput/sys_options.h
deleted file mode 100644
index 9c1b0d30..00000000
--- a/src/ginput/sys_options.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/sys_options.h
- * @brief   GINPUT sub-system options header file.
- *
- * @addtogroup GINPUT
- * @{
- */
-
-#ifndef _GINPUT_OPTIONS_H
-#define _GINPUT_OPTIONS_H
-
-/**
- * @name    GINPUT Functionality to be included
- * @{
- */
-	/**
-	 * @brief   Should mouse/touch functions be included.
-	 * @details	Defaults to FALSE
-	 * @note	Also add a mouse/touch hardware driver to your makefile.
-	 * 			Eg.
-	 * 				include $(GFXLIB)/drivers/ginput/touch/MCU/driver.mk
-	 */
-	#ifndef GINPUT_NEED_MOUSE
-		#define GINPUT_NEED_MOUSE		FALSE
-	#endif
-	/**
-	 * @brief   Should keyboard functions be included.
-	 * @details	Defaults to FALSE
-	 * @note	Also add a keyboard hardware driver to your makefile.
-	 * 			Eg.
-	 * 				include $(GFXLIB)/drivers/ginput/keyboard/XXXX/driver.mk
-	 */
-	#ifndef GINPUT_NEED_KEYBOARD
-		#define GINPUT_NEED_KEYBOARD	FALSE
-	#endif
-	/**
-	 * @brief   Should hardware toggle/switch/button functions be included.
-	 * @details	Defaults to FALSE
-	 * @note	Also add a toggle hardware driver to your makefile.
-	 * 			Eg.
-	 * 				include $(GFXLIB)/drivers/ginput/toggle/Pal/driver.mk
-	 */
-	#ifndef GINPUT_NEED_TOGGLE
-		#define GINPUT_NEED_TOGGLE		FALSE
-	#endif
-	/**
-	 * @brief   Should analog dial functions be included.
-	 * @details	Defaults to FALSE
-	 * @note	Also add a dial hardware driver to your makefile.
-	 * 			Eg.
-	 * 				include $(GFXLIB)/drivers/ginput/dial/analog/driver.mk
-	 */
-	#ifndef GINPUT_NEED_DIAL
-		#define GINPUT_NEED_DIAL		FALSE
-	#endif
-/**
- * @}
- *
- * @name    GINPUT Optional Sizing Parameters
- * @{
- */
-/**
- * @}
- *
- * @name    GINPUT Optional Low Level Driver Defines
- * @{
- */
-	/**
-	 * @brief   Start touch devices without loading or running calibration.
-	 * @details	Defaults to FALSE
-	 * @note	This is used if you want to manually control the initial calibration
-	 * 			process. In practice this is only useful for a touch driver test program.
-	 */
-	#ifndef GINPUT_TOUCH_STARTRAW
-		#define GINPUT_TOUCH_STARTRAW					FALSE
-	#endif
- 	/**
-	 * @brief   Turn off the touch calibration GUI.
-	 * @details	Defaults to FALSE
-	 * @note	Turning off the calibration GUI just turns off the manual calibration
-	 * 			process. Readings may still be calibrated if calibration data
-	 * 			can be loaded.
-	 * @note	Calibration requires a lot of code. If your device doesn't require it
-	 * 			using this option can save a lot of space.
-	 */
-	#ifndef GINPUT_TOUCH_NOCALIBRATE_GUI
-		#define GINPUT_TOUCH_NOCALIBRATE_GUI			FALSE
-	#endif
-	/**
-	 * @brief   Turn off all touch calibration support.
-	 * @details	Defaults to FALSE
-	 * @note	With this set to TRUE touch readings will not be calibrated.
-	 * @note	This automatically turns off the calibration GUI too!
-	 * @note	Calibration requires a lot of code. If your device doesn't require it
-	 * 			using this option can save a lot of space.
-	 */
-	#ifndef GINPUT_TOUCH_NOCALIBRATE
-		#define GINPUT_TOUCH_NOCALIBRATE				FALSE
-	#endif
-	/**
-	 * @brief   Turn off all touch support.
-	 * @details	Defaults to FALSE
-	 * @note	This automatically turns off all calibration and the calibration GUI too!
-	 * @note	Touch device handling requires a lot of code. If your device doesn't require it
-	 * 			using this option can save a lot of space.
-	 */
-	#ifndef GINPUT_TOUCH_NOTOUCH
-		#define GINPUT_TOUCH_NOTOUCH					FALSE
-	#endif
-	/**
-	 * @brief   Milliseconds between mouse polls.
-	 * @details	Defaults to 25 milliseconds
-	 * @note	How often mice should be polled. More often leads to smoother mouse movement
-	 * 			but increases CPU usage.
-	 */
-	#ifndef GINPUT_MOUSE_POLL_PERIOD
-		#define GINPUT_MOUSE_POLL_PERIOD				25
-	#endif
-
-	/**
-	 * @brief   Maximum length of CLICK in milliseconds
-	 * @details	Defaults to 300 milliseconds
-	 * @note	Mouse down to Mouse up times greater than this are not clicks.
-	 */
-	#ifndef GINPUT_MOUSE_CLICK_TIME
-		#define GINPUT_MOUSE_CLICK_TIME					300
-	#endif
-	/**
-	 * @brief   Milliseconds to generate a CXTCLICK on a touch device.
-	 * @details	Defaults to 500 milliseconds
-	 * @note	If you hold the touch down for longer than this a CXTCLICK is generated
-	 * 			but only on a touch device.
-	 */
-	#ifndef GINPUT_TOUCH_CXTCLICK_TIME
-		#define GINPUT_TOUCH_CXTCLICK_TIME				500
-	#endif
-   /**
-     * @brief   There is a user supplied routine to load mouse calibration data
-	 * @details	Defaults to FALSE
-     * @note    If TRUE the user must supply the @p LoadMouseCalibration() routine.
-     */
-	#ifndef GINPUT_TOUCH_USER_CALIBRATION_LOAD
-		#define GINPUT_TOUCH_USER_CALIBRATION_LOAD		FALSE
-	#endif
-   /**
-     * @brief   There is a user supplied routine to save mouse calibration data
-	 * @details	Defaults to FALSE
-     * @note    If TRUE the user must supply the @p SaveMouseCalibration() routine.
-     */
-	#ifndef GINPUT_TOUCH_USER_CALIBRATION_SAVE
-		#define GINPUT_TOUCH_USER_CALIBRATION_SAVE		FALSE
-	#endif
-   /**
-     * @brief   Define multiple static mice
-	 * @details	When not defined the system automatically detects a single linked mouse driver
-	 * @note	The references to GMOUSEVMT_Win32 in the definition would be replaced
-	 * 			by the names of the VMT for each of the static mice you want to
-	 * 			include.
-	 * @note	Dynamic mice associated automatically with a display eg Win32, X or GFXnet
-	 * 			do not need to be specified in this list as the associated display driver will register
-	 * 			them automatically as the display is created.
-     */
-	#if defined(__DOXYGEN__)
-		#define GMOUSE_DRIVER_LIST						GMOUSEVMT_Win32, GMOUSEVMT_Win32
-	#endif
-	/**
-	 * @brief   Milliseconds between keyboard polls.
-	 * @details	Defaults to 200 milliseconds
-	 * @note	How often keyboards should be polled.
-	 */
-	#ifndef GINPUT_KEYBOARD_POLL_PERIOD
-		#define GINPUT_KEYBOARD_POLL_PERIOD				200
-	#endif
-   /**
-     * @brief   Define multiple static keyboards
-	 * @details	When not defined the system automatically detects a single linked keyboard driver
-	 * @note	The references to GKEYBOARDVMT_Win32 in the definition would be replaced
-	 * 			by the names of the VMT for each of the static keyboards you want to
-	 * 			include.
-	 * @note	Dynamic keyboards associated automatically with a display eg Win32, X or GFXnet
-	 * 			do not need to be specified in this list as the display driver will register
-	 * 			them automatically as the display is created.
-     */
-	#if defined(__DOXYGEN__)
-		#define GKEYBOARD_DRIVER_LIST					GMOUSEVMT_Win32, GMOUSEVMT_Win32
-	#endif
-   /**
-     * @brief   Turn off the layout engine.
-	 * @details	When defined the layout engine is removed from the code and characters
-	 * 			are passed directly from the keyboard driver to the application.
-	 * @note	Turning off the layout engine just saves code if it is not needed.
-     */
-	#ifndef GKEYBOARD_LAYOUT_OFF
-		#define GKEYBOARD_LAYOUT_OFF					FALSE
-	#endif
-	/**
-	 * @brief   Various Keyboard Layouts that can be included.
-	 * @details	A keyboard layout controls conversion of scancodes to characters
-	 * 			and enables one keyboard to have multiple language mappings.
-	 * @note	Defining a layout does not make it active. The keyboard driver
-	 * 			must have it active as the default or the application must
-	 * 			use @p ginputSetKeyboardLayout() to set the active layout.
-	 * @note	Multiple layouts can be included but only one will be active
-	 * 			at a time (per keyboard).
-	 * @{
-	 */
-	#ifndef GKEYBOARD_LAYOUT_SCANCODE2_US
-		#define GKEYBOARD_LAYOUT_SCANCODE2_US			FALSE				// US Keyboard using the ScanCode 2 set.
-	#endif
-	/** @} */
-/** @} */
-
-#endif /* _GINPUT_OPTIONS_H */
-/** @} */
diff --git a/src/ginput/sys_rules.h b/src/ginput/sys_rules.h
deleted file mode 100644
index d9a367ce..00000000
--- a/src/ginput/sys_rules.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/ginput/sys_rules.h
- * @brief   GINPUT safety rules header file.
- *
- * @addtogroup GINPUT
- * @{
- */
-
-#ifndef _GINPUT_RULES_H
-#define _GINPUT_RULES_H
-
-#if GFX_USE_GINPUT
-	#if !GFX_USE_GEVENT
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GINPUT: GFX_USE_GEVENT is required if GFX_USE_GINPUT is TRUE. It has been turned on for you."
-		#endif
-		#undef GFX_USE_GEVENT
-		#define	GFX_USE_GEVENT		TRUE
-	#endif
-	#if !GFX_USE_GTIMER
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GINPUT: GFX_USE_GTIMER is required if GFX_USE_GINPUT is TRUE. It has been turned on for you."
-		#endif
-		#undef GFX_USE_GTIMER
-		#define	GFX_USE_GTIMER		TRUE
-	#endif
-	#if GINPUT_NEED_MOUSE
-		#if GINPUT_TOUCH_NOTOUCH
-			// No warning needed for this
-			#undef GINPUT_TOUCH_NOCALIBRATE
-			#define GINPUT_TOUCH_NOCALIBRATE	TRUE
-		#endif
-		#if GINPUT_TOUCH_NOCALIBRATE
-			// No warning needed for this
-			#undef GINPUT_TOUCH_NOCALIBRATE_GUI
-			#define GINPUT_TOUCH_NOCALIBRATE_GUI	TRUE
-		#endif
-		#if !GINPUT_TOUCH_NOTOUCH && GINPUT_MOUSE_CLICK_TIME > GINPUT_TOUCH_CXTCLICK_TIME
-			#error "GINPUT MOUSE: The GINPUT_MOUSE_CLICK_TIME must be <= GINPUT_TOUCH_CXTCLICK_TIME"
-		#endif
-	#endif
-#endif
-
-#endif /* _GINPUT_RULES_H */
-/** @} */
diff --git a/src/gmisc/gmisc.c b/src/gmisc/gmisc.c
new file mode 100644
index 00000000..9bcc7bbe
--- /dev/null
+++ b/src/gmisc/gmisc.c
@@ -0,0 +1,22 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GMISC
+
+void _gmiscInit(void)
+{
+
+}
+
+void _gmiscDeinit(void)
+{
+
+}
+
+#endif /* GFX_USE_GMISC */
diff --git a/src/gmisc/gmisc.h b/src/gmisc/gmisc.h
new file mode 100644
index 00000000..8f858682
--- /dev/null
+++ b/src/gmisc/gmisc.h
@@ -0,0 +1,471 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gmisc/gmisc.h
+ * @brief   GMISC - Miscellaneous Routines header file.
+ *
+ * @addtogroup GMISC
+ *
+ * @brief	Module which contains different features such as array conversions
+ *
+ * @{
+ */
+
+#ifndef _GMISC_H
+#define _GMISC_H
+
+#include "gfx.h"
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+// Forward definition
+typedef struct point point;
+
+/**
+ * @brief	Sample data formats
+ * @note	These are defined regardless of whether you use the GMISC module
+ * 			or not as they are used in lots of places.
+ */
+typedef enum ArrayDataFormat_e {
+	ARRAY_DATA_UNKNOWN = 0,
+	ARRAY_DATA_4BITUNSIGNED = 4,	ARRAY_DATA_4BITSIGNED = 5,
+	ARRAY_DATA_8BITUNSIGNED = 8,	ARRAY_DATA_8BITSIGNED = 9,
+	ARRAY_DATA_10BITUNSIGNED = 10,	ARRAY_DATA_10BITSIGNED = 11,
+	ARRAY_DATA_12BITUNSIGNED = 12,	ARRAY_DATA_12BITSIGNED = 13,
+	ARRAY_DATA_14BITUNSIGNED = 14,	ARRAY_DATA_14BITSIGNED = 15,
+	ARRAY_DATA_16BITUNSIGNED = 16,	ARRAY_DATA_16BITSIGNED = 17,
+	} ArrayDataFormat;
+
+/**
+ * @brief	Is the sample data format a "signed" data format?
+ */
+#define gfxSampleFormatIsSigned(fmt)	((fmt) & 1)
+
+/**
+ * @brief	How many bits are in the sample data format
+ */
+#define gfxSampleFormatBits(fmt)	((fmt) & ~1)
+
+/**
+ * @brief   The type for a fixed point type.
+ * @details	The top 16 bits are the integer component, the bottom 16 bits are the real component.
+ */
+typedef int32_t	fixed;
+
+/**
+ * @brief   Macros to convert to and from a fixed point.
+ * @{
+ */
+#define FIXED(x)			((fixed)(x)<<16)						/* @< integer to fixed */
+#define NONFIXED(x)			((x)>>16)								/* @< fixed to integer */
+#define FIXED0_5			32768									/* @< 0.5 as a fixed (used for rounding) */
+#define FP2FIXED(x)			((fixed)((x)*65536.0))					/* @< floating point to fixed */
+#define FIXED2FP(x)			((double)(x)/65536.0)					/* @< fixed to floating point */
+#define FIXEDMUL(a,b)		((fixed)((((long long)(a))*(b))>>16))	/* @< fixed,fixed multiplication */
+#define FIXEDMULINT(a,b)	((a)*(b))								/* @< integer,fixed multiplication */
+/** @} */
+
+/**
+ * @brief   The famous number pi
+ */
+#define PI	3.1415926535897932384626433832795028841971693993751
+
+/**
+ * @brief   pi as a fixed point
+ */
+#define FIXED_PI	FP2FIXED(PI)
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if GFX_USE_GMISC || defined(__DOXYGEN__)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if GMISC_NEED_ARRAYOPS || defined(__DOXYGEN__)
+	/**
+	 * @brief				Convert from one array format to another array format.
+	 * @pre					Requires GFX_USE_GMISC and GMISC_NEED_ARRAYOPS
+	 *
+	 * @param[in] srcfmt		The format of the source array
+	 * @param[in] src			The source array
+	 * @param[in] dstfmt		The format of the destination array
+	 * @param[in] dst			The dstination array
+	 * @param[in] cnt			The number of array elements to convert
+	 *
+	 * @note				Assumes the destination buffer is large enough for the resultant data.
+	 * @note				This routine is optimised to perform as fast as possible.
+	 * @note				No type checking is performed on the source format. It is assumed to
+	 * 						have only valid values eg. ARRAY_DATA_4BITSIGNED will have values
+	 * 							0000 -> 0111 for positive numbers and 1111 -> 1000 for negative numbers
+	 * 							Bits 5 -> 8 in the storage byte are treated in an undefined manner.
+	 * @note				If srcfmt or dstfmt is an unknown format, this routine does nothing
+	 * 						with no warning that something is wrong
+	 *
+	 * @api
+	 */
+	void gmiscArrayConvert(ArrayDataFormat srcfmt, void *src, ArrayDataFormat dstfmt, void *dst, size_t cnt);
+
+	#if 0
+		void gmiscArrayTranslate(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int trans);
+
+		void gmiscArrayMultiply(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mult);
+
+		void gmiscArrayDivide(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mdiv);
+
+		void gmiscArrayMultDiv(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mult, int div);
+
+		void gmiscArrayAdd(ArrayDataFormat fmt, void *src1, void *src2, void *dst, size_t cnt);
+
+		void gmiscArrayAddNoOverflow(ArrayDataFormat fmt, void *src1, void *src2, void *dst, size_t cnt);
+	#endif
+#endif
+
+#if GMISC_NEED_FASTTRIG || defined(__DOXYGEN__)
+		extern const double sintabledouble[];
+
+		/**
+		 * @brief	Fast Table Based Trig functions
+		 * @return	A double in the range -1.0 .. 0.0 .. 1.0
+		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_FASTTRIG
+		 *
+		 * @param[in] degrees	The angle in degrees (not radians)
+		 *
+		 * @note	These functions use degrees rather than radians to describe the angle.
+		 *
+		 * @api
+		 * @{
+		 */
+		double fsin(int degrees);
+		double fcos(int degrees);
+		/** @}
+		 *
+		 * @brief	Fast Table Based Trig functions
+		 * @return	A double in the range -1.0 .. 0.0 .. 1.0
+		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_FASTTRIG
+		 *
+		 * @param[in] degrees	The angle in degrees 0 .. 359
+		 *
+		 * @note	These functions use degrees rather than radians to describe the angle.
+		 * @note	These functions are super fast but require the parameter to be in range.
+		 * 			Use the lowercase functions if the parameter may not be in range or if a
+		 * 			required trig function is not supported in this form.
+		 *
+		 * @api
+		 * @{
+		 */
+		#define FSIN(degrees) 	sintabledouble[degrees];
+		/** @} */
+#endif
+
+#if GMISC_NEED_FIXEDTRIG || defined(__DOXYGEN__)
+		extern const fixed sintablefixed[];
+
+		/**
+		 * @brief	Fast Table Based Trig functions
+		 * @return	A fixed point in the range -1.0 .. 0.0 .. 1.0
+		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG
+		 *
+		 * @param[in] degrees	The angle in degrees (not radians)
+		 *
+		 * @note	These functions use degrees rather than radians to describe the angle.
+		 *
+		 * @api
+		 * @{
+		 */
+		fixed ffsin(int degrees);
+		fixed ffcos(int degrees);
+		/** @}
+		 *
+		 * @brief	Fast Table Based Trig functions
+		 * @return	A fixed point in the range -1.0 .. 0.0 .. 1.0
+		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG
+		 *
+		 * @param[in] degrees	The angle in degrees 0 .. 359
+		 *
+		 * @note	These functions use degrees rather than radians to describe the angle.
+		 * @note	These functions are super fast but require the parameter to be in range.
+		 * 			Use the lowercase functions if the parameter may not be in range or if a
+		 * 			required trig function is not supported in this form.
+		 *
+		 * @api
+		 * @{
+		 */
+		#define FFSIN(degrees) 	sintablefixed[degrees];
+		/** @} */
+#endif
+
+#if GMISC_NEED_INVSQRT || defined(__DOXYGEN__)
+		/**
+		 * @brief	Fast inverse square root function (x^-1/2)
+		 * @return	The approximate inverse square root
+		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_INVSQRT
+		 *
+		 * @param[in] n	The number to find the inverse square root of
+		 *
+		 * @note	This function generates an approximate result. Higher accuracy (at the expense
+		 * 			of speed) can be obtained by modifying the source code (the necessary line
+		 * 			is already there - just commented out).
+		 * @note	This function relies on the internal machine format of a float and a long.
+		 * 			If your machine architecture is very unusual this function may not work.
+		 *
+		 * @api
+		 */
+		float invsqrt(float n);
+#endif
+
+#if GMISC_NEED_MATRIXFLOAT2D || defined(__DOXYGEN__)
+
+	/**
+	 * @brief	A matrix for doing 2D graphics using floats
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
+	 */
+	typedef struct MatrixFloat2D {
+		float	a00, a01, a02;
+		float	a10, a11, a12;
+		float	a20, a21, a22;
+	} MatrixFloat2D;
+
+	/**
+	 * @brief	Apply the matrix to a set of points
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
+	 *
+	 * @param[in] dst	The destination array of points
+	 * @param[in] src	The source array of points
+	 * @param[in] m		The matrix to apply
+	 * @param[in] cnt	How many points are in the array
+	 *
+	 * @note	In-place matrix application is allowed ie. dst = src
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFloat2DApplyToPoints(point *dst, const point *src, const MatrixFloat2D *m, int cnt);
+
+	/**
+	 * @brief	Set the 2D matrix to the identity matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
+	 *
+	 * @param[in] m		The matrix to set to identity
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFloat2DSetIdentity(MatrixFloat2D *m);
+
+	/**
+	 * @brief	Multiple two 2D matrixes together
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
+	 *
+	 * @param[in] dst	The destination matrix
+	 * @param[in] src1	The first source matrix
+	 * @param[in] src2	The second source matrix
+	 *
+	 * @note	In-place matrix application is NOT allowed ie. dst != src1, dst != src2
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFloat2DMultiply(MatrixFloat2D *dst, const MatrixFloat2D *src1, const MatrixFloat2D *src2);
+
+	/**
+	 * @brief	Add an x,y translation to a matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
+	 *
+	 * @param[in] dst		The destination matrix
+	 * @param[in] src		The source matrix. Can be NULL
+	 * @param[in] tx, ty	The x and y translation to apply
+	 *
+	 * @note	In-place matrix operation is NOT allowed ie. dst != src
+	 * @note	If no source matrix is provided, it is equivalent to applying the operation
+	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFloat2DApplyTranslation(MatrixFloat2D *dst, const MatrixFloat2D *src, float tx, float ty);
+
+	/**
+	 * @brief	Add x,y scaling to a matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
+	 *
+	 * @param[in] dst		The destination matrix
+	 * @param[in] src		The source matrix. Can be NULL
+	 * @param[in] sx, sy	The scaling to apply in the x and y direction. Negative numbers give reflection.
+	 *
+	 * @note	In-place matrix operation is NOT allowed ie. dst != src
+	 * @note	If no source matrix is provided, it is equivalent to applying the operation
+	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFloat2DApplyScale(MatrixFloat2D *dst, const MatrixFloat2D *src, float sx, float sy);
+
+	/**
+	 * @brief	Add x,y shear to a matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
+	 *
+	 * @param[in] dst		The destination matrix
+	 * @param[in] src		The source matrix. Can be NULL
+	 * @param[in] sx, sy	The shear to apply in the x and y direction.
+	 *
+	 * @note	In-place matrix operation is NOT allowed ie. dst != src
+	 * @note	If no source matrix is provided, it is equivalent to applying the operation
+	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFloat2DApplyShear(MatrixFloat2D *dst, const MatrixFloat2D *src, float sx, float sy);
+
+	/**
+	 * @brief	Add rotation to a matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
+	 *
+	 * @param[in] dst		The destination matrix
+	 * @param[in] src		The source matrix. Can be NULL
+	 * @param[in] angle		The angle to apply in degrees (not radians).
+	 *
+	 * @note	In-place matrix operation is NOT allowed ie. dst != src
+	 * @note	If no source matrix is provided, it is equivalent to applying the operation
+	 * 			to an identity matrix. It also is a much simpler operation.
+	 * @note	If GMISC_NEED_FASTTRIG is defined then the fast table sin and cos lookup's will be used
+	 * 			rather than the C library versions.
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFloat2DApplyRotation(MatrixFloat2D *dst, const MatrixFloat2D *src, int angle);
+#endif
+
+#if GMISC_NEED_MATRIXFIXED2D || defined(__DOXYGEN__)
+
+	/**
+	 * @brief	A matrix for doing 2D graphics using fixed point maths
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
+	 */
+	typedef struct MatrixFixed2D {
+		fixed	a00, a01, a02;
+		fixed	a10, a11, a12;
+		fixed	a20, a21, a22;
+	} MatrixFixed2D;
+
+	/**
+	 * @brief	Apply the matrix to a set of points
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
+	 *
+	 * @param[in] dst	The destination array of points
+	 * @param[in] src	The source array of points
+	 * @param[in] m		The matrix to apply
+	 * @param[in] cnt	How many points are in the array
+	 *
+	 * @note	In-place matrix application is allowed ie. dst = src
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFixed2DApplyToPoints(point *dst, const point *src, const MatrixFixed2D *m, int cnt);
+
+	/**
+	 * @brief	Set the 2D matrix to the identity matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
+	 *
+	 * @param[in] m		The matrix to set to identity
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFixed2DSetIdentity(MatrixFixed2D *m);
+
+	/**
+	 * @brief	Multiple two 2D matrixes together
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
+	 *
+	 * @param[in] dst	The destination matrix
+	 * @param[in] src1	The first source matrix
+	 * @param[in] src2	The second source matrix
+	 *
+	 * @note	In-place matrix application is NOT allowed ie. dst != src1, dst != src2
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFixed2DMultiply(MatrixFixed2D *dst, const MatrixFixed2D *src1, const MatrixFixed2D *src2);
+
+	/**
+	 * @brief	Add an x,y translation to a matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
+	 *
+	 * @param[in] dst		The destination matrix
+	 * @param[in] src		The source matrix. Can be NULL
+	 * @param[in] tx, ty	The x and y translation to apply
+	 *
+	 * @note	In-place matrix operation is NOT allowed ie. dst != src
+	 * @note	If no source matrix is provided, it is equivalent to applying the operation
+	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFixed2DApplyTranslation(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed tx, fixed ty);
+
+	/**
+	 * @brief	Add x,y scaling to a matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
+	 *
+	 * @param[in] dst		The destination matrix
+	 * @param[in] src		The source matrix. Can be NULL
+	 * @param[in] sx, sy	The scaling to apply in the x and y direction. Negative numbers give reflection.
+	 *
+	 * @note	In-place matrix operation is NOT allowed ie. dst != src
+	 * @note	If no source matrix is provided, it is equivalent to applying the operation
+	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFixed2DApplyScale(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed sx, fixed sy);
+
+	/**
+	 * @brief	Add x,y shear to a matrix
+	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
+	 *
+	 * @param[in] dst		The destination matrix
+	 * @param[in] src		The source matrix. Can be NULL
+	 * @param[in] sx, sy	The shear to apply in the x and y direction.
+	 *
+	 * @note	In-place matrix operation is NOT allowed ie. dst != src
+	 * @note	If no source matrix is provided, it is equivalent to applying the operation
+	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
+	 *
+	 * @api
+	 */
+	void gmiscMatrixFixed2DApplyShear(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed sx, fixed sy);
+
+	#if GMISC_NEED_FIXEDTRIG || defined(__DOXYGEN__)
+		/**
+		 * @brief	Add rotation to a matrix
+		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D and GMISC_NEED_FIXEDTRIG
+		 *
+		 * @param[in] dst		The destination matrix
+		 * @param[in] src		The source matrix. Can be NULL
+		 * @param[in] angle		The angle to apply in degrees (not radians).
+		 *
+		 * @note	In-place matrix operation is NOT allowed ie. dst != src
+		 * @note	If no source matrix is provided, it is equivalent to applying the operation
+		 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
+		 *
+		 * @api
+		 */
+		void gmiscMatrixFixed2DApplyRotation(MatrixFixed2D *dst, const MatrixFixed2D *src, int angle);
+	#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_MISC */
+
+#endif /* _GMISC_H */
+/** @} */
+
diff --git a/src/gmisc/gmisc.mk b/src/gmisc/gmisc.mk
new file mode 100644
index 00000000..fa2e382f
--- /dev/null
+++ b/src/gmisc/gmisc.mk
@@ -0,0 +1,4 @@
+GFXSRC +=   $(GFXLIB)/src/gmisc/gmisc.c	\
+			$(GFXLIB)/src/gmisc/gmisc_arrayops.c	\
+			$(GFXLIB)/src/gmisc/gmisc_matrix2d.c	\
+			$(GFXLIB)/src/gmisc/gmisc_trig.c
diff --git a/src/gmisc/gmisc_arrayops.c b/src/gmisc/gmisc_arrayops.c
index 6e5442cd..350a787c 100644
--- a/src/gmisc/gmisc_arrayops.c
+++ b/src/gmisc/gmisc_arrayops.c
@@ -5,13 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gmisc/gmisc_arrayops.c
- * @brief   GMISC Array Operations code.
- *
- * @addtogroup GMISC
- * @{
- */
 #include "gfx.h"
 
 #if GFX_USE_GMISC && GMISC_NEED_ARRAYOPS
@@ -223,4 +216,3 @@ void gmiscArrayConvert(ArrayDataFormat srcfmt, void *src, ArrayDataFormat dstfmt
 }
 
 #endif /* GFX_USE_GMISC && GMISC_NEED_ARRAYOPS */
-/** @} */
diff --git a/src/gmisc/gmisc_gmisc.c b/src/gmisc/gmisc_gmisc.c
deleted file mode 100644
index 3121182f..00000000
--- a/src/gmisc/gmisc_gmisc.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gmisc/gmisc_gmisc.c
- * @brief   GMISC Functions.
- *
- */
-#include "gfx.h"
-
-#if GFX_USE_GMISC
-
-void _gmiscInit(void)
-{
-
-}
-
-void _gmiscDeinit(void)
-{
-
-}
-
-#endif /* GFX_USE_GMISC */
diff --git a/src/gmisc/gmisc_matrix2d.c b/src/gmisc/gmisc_matrix2d.c
index dd13603e..84b90c23 100644
--- a/src/gmisc/gmisc_matrix2d.c
+++ b/src/gmisc/gmisc_matrix2d.c
@@ -5,10 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gmisc/gmisc_matrix2d.c
- * @brief   GMISC 2D matrix operations code.
- */
 #include "gfx.h"
 
 #if GFX_USE_GMISC
diff --git a/src/gmisc/gmisc_options.h b/src/gmisc/gmisc_options.h
new file mode 100644
index 00000000..7f175fd7
--- /dev/null
+++ b/src/gmisc/gmisc_options.h
@@ -0,0 +1,85 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gmisc/gmisc_options.h
+ * @brief   GMISC - Miscellaneous Routines options header file.
+ *
+ * @addtogroup GMISC
+ * @{
+ */
+
+#ifndef _GMISC_OPTIONS_H
+#define _GMISC_OPTIONS_H
+
+/**
+ * @name    GMISC Functionality to be included
+ * @{
+ */
+	/**
+	 * @brief   Include array operation functions
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GMISC_NEED_ARRAYOPS
+		#define GMISC_NEED_ARRAYOPS			FALSE
+	#endif
+	/**
+	 * @brief   Include fast floating point trig functions (fsin, fcos)
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GMISC_NEED_FASTTRIG
+		#define GMISC_NEED_FASTTRIG			FALSE
+	#endif
+	/**
+	 * @brief   Include fast fixed point trig functions (ffsin, ffcos)
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GMISC_NEED_FIXEDTRIG
+		#define GMISC_NEED_FIXEDTRIG		FALSE
+	#endif
+	/**
+	 * @brief   Include fast inverse square root (x^-1/2)
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GMISC_NEED_INVSQRT
+		#define GMISC_NEED_INVSQRT		FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GMISC Optional Parameters
+ * @{
+ */
+	/**
+	 * @brief	Modifies the @p invsqrt() function to assume a different integer to floating point endianness.
+	 * @note	Normally the floating point format and the integer format have
+	 * 			the same endianness. Unfortunately there are some strange
+	 * 			processors that don't eg. some very early ARM devices.
+	 * 			For those where the endianness doesn't match you can fix it by
+	 * 			defining GMISC_INVSQRT_MIXED_ENDIAN.
+	 * @note	This still assumes the processor is using an ieee floating point format.
+	 *
+	 * If you have a software floating point that uses a non-standard
+	 * floating point format (or very strange hardware) then define
+	 * GMISC_INVSQRT_REAL_SLOW and it will do it the hard way.
+	 */
+	#ifndef GMISC_INVSQRT_MIXED_ENDIAN
+		#define GMISC_INVSQRT_MIXED_ENDIAN	FALSE
+	#endif
+	/**
+	 * @brief	Modifies the @p invsqrt() function to do things the long slow way.
+	 * @note	This causes the @p invsqrt() function to work regardless of the
+	 * 			processor floating point format.
+	 * @note	This makes the @p invsqrt() function very slow.
+	 */
+	#ifndef GMISC_INVSQRT_REAL_SLOW
+		#define GMISC_INVSQRT_REAL_SLOW		FALSE
+	#endif
+/** @} */
+
+#endif /* _GMISC_OPTIONS_H */
+/** @} */
diff --git a/src/gmisc/gmisc_rules.h b/src/gmisc/gmisc_rules.h
new file mode 100644
index 00000000..44a19846
--- /dev/null
+++ b/src/gmisc/gmisc_rules.h
@@ -0,0 +1,23 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gmisc/gmisc_rules.h
+ * @brief   GMISC safety rules header file.
+ *
+ * @addtogroup GMISC
+ * @{
+ */
+
+#ifndef _GMISC_RULES_H
+#define _GMISC_RULES_H
+
+#if GFX_USE_GMISC
+#endif
+
+#endif /* _GMISC_RULES_H */
+/** @} */
diff --git a/src/gmisc/gmisc_trig.c b/src/gmisc/gmisc_trig.c
index 7314f389..12d06be2 100644
--- a/src/gmisc/gmisc_trig.c
+++ b/src/gmisc/gmisc_trig.c
@@ -5,13 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gmisc/gmisc_trig.c
- * @brief   GMISC Trig Functions.
- *
- * @addtogroup GMISC
- * @{
- */
 #include "gfx.h"
 
 #if GFX_USE_GMISC
@@ -187,4 +180,3 @@
 #endif
 
 #endif /* GFX_USE_GMISC */
-/** @} */
diff --git a/src/gmisc/sys_defs.h b/src/gmisc/sys_defs.h
deleted file mode 100644
index 813fa07e..00000000
--- a/src/gmisc/sys_defs.h
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gmisc/sys_defs.h
- * @brief   GMISC - Miscellaneous Routines header file.
- *
- * @addtogroup GMISC
- *
- * @brief	Module which contains different features such as array conversions
- *
- * @{
- */
-
-#ifndef _GMISC_H
-#define _GMISC_H
-
-#include "gfx.h"
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-// Forward definition
-typedef struct point point;
-
-/**
- * @brief	Sample data formats
- * @note	These are defined regardless of whether you use the GMISC module
- * 			or not as they are used in lots of places.
- */
-typedef enum ArrayDataFormat_e {
-	ARRAY_DATA_UNKNOWN = 0,
-	ARRAY_DATA_4BITUNSIGNED = 4,	ARRAY_DATA_4BITSIGNED = 5,
-	ARRAY_DATA_8BITUNSIGNED = 8,	ARRAY_DATA_8BITSIGNED = 9,
-	ARRAY_DATA_10BITUNSIGNED = 10,	ARRAY_DATA_10BITSIGNED = 11,
-	ARRAY_DATA_12BITUNSIGNED = 12,	ARRAY_DATA_12BITSIGNED = 13,
-	ARRAY_DATA_14BITUNSIGNED = 14,	ARRAY_DATA_14BITSIGNED = 15,
-	ARRAY_DATA_16BITUNSIGNED = 16,	ARRAY_DATA_16BITSIGNED = 17,
-	} ArrayDataFormat;
-
-/**
- * @brief	Is the sample data format a "signed" data format?
- */
-#define gfxSampleFormatIsSigned(fmt)	((fmt) & 1)
-
-/**
- * @brief	How many bits are in the sample data format
- */
-#define gfxSampleFormatBits(fmt)	((fmt) & ~1)
-
-/**
- * @brief   The type for a fixed point type.
- * @details	The top 16 bits are the integer component, the bottom 16 bits are the real component.
- */
-typedef int32_t	fixed;
-
-/**
- * @brief   Macros to convert to and from a fixed point.
- * @{
- */
-#define FIXED(x)			((fixed)(x)<<16)						/* @< integer to fixed */
-#define NONFIXED(x)			((x)>>16)								/* @< fixed to integer */
-#define FIXED0_5			32768									/* @< 0.5 as a fixed (used for rounding) */
-#define FP2FIXED(x)			((fixed)((x)*65536.0))					/* @< floating point to fixed */
-#define FIXED2FP(x)			((double)(x)/65536.0)					/* @< fixed to floating point */
-#define FIXEDMUL(a,b)		((fixed)((((long long)(a))*(b))>>16))	/* @< fixed,fixed multiplication */
-#define FIXEDMULINT(a,b)	((a)*(b))								/* @< integer,fixed multiplication */
-/** @} */
-
-/**
- * @brief   The famous number pi
- */
-#define PI	3.1415926535897932384626433832795028841971693993751
-
-/**
- * @brief   pi as a fixed point
- */
-#define FIXED_PI	FP2FIXED(PI)
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#if GFX_USE_GMISC || defined(__DOXYGEN__)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if GMISC_NEED_ARRAYOPS || defined(__DOXYGEN__)
-	/**
-	 * @brief				Convert from one array format to another array format.
-	 * @pre					Requires GFX_USE_GMISC and GMISC_NEED_ARRAYOPS
-	 *
-	 * @param[in] srcfmt		The format of the source array
-	 * @param[in] src			The source array
-	 * @param[in] dstfmt		The format of the destination array
-	 * @param[in] dst			The dstination array
-	 * @param[in] cnt			The number of array elements to convert
-	 *
-	 * @note				Assumes the destination buffer is large enough for the resultant data.
-	 * @note				This routine is optimised to perform as fast as possible.
-	 * @note				No type checking is performed on the source format. It is assumed to
-	 * 						have only valid values eg. ARRAY_DATA_4BITSIGNED will have values
-	 * 							0000 -> 0111 for positive numbers and 1111 -> 1000 for negative numbers
-	 * 							Bits 5 -> 8 in the storage byte are treated in an undefined manner.
-	 * @note				If srcfmt or dstfmt is an unknown format, this routine does nothing
-	 * 						with no warning that something is wrong
-	 *
-	 * @api
-	 */
-	void gmiscArrayConvert(ArrayDataFormat srcfmt, void *src, ArrayDataFormat dstfmt, void *dst, size_t cnt);
-
-	#if 0
-		void gmiscArrayTranslate(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int trans);
-
-		void gmiscArrayMultiply(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mult);
-
-		void gmiscArrayDivide(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mdiv);
-
-		void gmiscArrayMultDiv(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mult, int div);
-
-		void gmiscArrayAdd(ArrayDataFormat fmt, void *src1, void *src2, void *dst, size_t cnt);
-
-		void gmiscArrayAddNoOverflow(ArrayDataFormat fmt, void *src1, void *src2, void *dst, size_t cnt);
-	#endif
-#endif
-
-#if GMISC_NEED_FASTTRIG || defined(__DOXYGEN__)
-		extern const double sintabledouble[];
-
-		/**
-		 * @brief	Fast Table Based Trig functions
-		 * @return	A double in the range -1.0 .. 0.0 .. 1.0
-		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_FASTTRIG
-		 *
-		 * @param[in] degrees	The angle in degrees (not radians)
-		 *
-		 * @note	These functions use degrees rather than radians to describe the angle.
-		 *
-		 * @api
-		 * @{
-		 */
-		double fsin(int degrees);
-		double fcos(int degrees);
-		/** @}
-		 *
-		 * @brief	Fast Table Based Trig functions
-		 * @return	A double in the range -1.0 .. 0.0 .. 1.0
-		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_FASTTRIG
-		 *
-		 * @param[in] degrees	The angle in degrees 0 .. 359
-		 *
-		 * @note	These functions use degrees rather than radians to describe the angle.
-		 * @note	These functions are super fast but require the parameter to be in range.
-		 * 			Use the lowercase functions if the parameter may not be in range or if a
-		 * 			required trig function is not supported in this form.
-		 *
-		 * @api
-		 * @{
-		 */
-		#define FSIN(degrees) 	sintabledouble[degrees];
-		/** @} */
-#endif
-
-#if GMISC_NEED_FIXEDTRIG || defined(__DOXYGEN__)
-		extern const fixed sintablefixed[];
-
-		/**
-		 * @brief	Fast Table Based Trig functions
-		 * @return	A fixed point in the range -1.0 .. 0.0 .. 1.0
-		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG
-		 *
-		 * @param[in] degrees	The angle in degrees (not radians)
-		 *
-		 * @note	These functions use degrees rather than radians to describe the angle.
-		 *
-		 * @api
-		 * @{
-		 */
-		fixed ffsin(int degrees);
-		fixed ffcos(int degrees);
-		/** @}
-		 *
-		 * @brief	Fast Table Based Trig functions
-		 * @return	A fixed point in the range -1.0 .. 0.0 .. 1.0
-		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG
-		 *
-		 * @param[in] degrees	The angle in degrees 0 .. 359
-		 *
-		 * @note	These functions use degrees rather than radians to describe the angle.
-		 * @note	These functions are super fast but require the parameter to be in range.
-		 * 			Use the lowercase functions if the parameter may not be in range or if a
-		 * 			required trig function is not supported in this form.
-		 *
-		 * @api
-		 * @{
-		 */
-		#define FFSIN(degrees) 	sintablefixed[degrees];
-		/** @} */
-#endif
-
-#if GMISC_NEED_INVSQRT || defined(__DOXYGEN__)
-		/**
-		 * @brief	Fast inverse square root function (x^-1/2)
-		 * @return	The approximate inverse square root
-		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_INVSQRT
-		 *
-		 * @param[in] n	The number to find the inverse square root of
-		 *
-		 * @note	This function generates an approximate result. Higher accuracy (at the expense
-		 * 			of speed) can be obtained by modifying the source code (the necessary line
-		 * 			is already there - just commented out).
-		 * @note	This function relies on the internal machine format of a float and a long.
-		 * 			If your machine architecture is very unusual this function may not work.
-		 *
-		 * @api
-		 */
-		float invsqrt(float n);
-#endif
-
-#if GMISC_NEED_MATRIXFLOAT2D || defined(__DOXYGEN__)
-
-	/**
-	 * @brief	A matrix for doing 2D graphics using floats
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
-	 */
-	typedef struct MatrixFloat2D {
-		float	a00, a01, a02;
-		float	a10, a11, a12;
-		float	a20, a21, a22;
-	} MatrixFloat2D;
-
-	/**
-	 * @brief	Apply the matrix to a set of points
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
-	 *
-	 * @param[in] dst	The destination array of points
-	 * @param[in] src	The source array of points
-	 * @param[in] m		The matrix to apply
-	 * @param[in] cnt	How many points are in the array
-	 *
-	 * @note	In-place matrix application is allowed ie. dst = src
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFloat2DApplyToPoints(point *dst, const point *src, const MatrixFloat2D *m, int cnt);
-
-	/**
-	 * @brief	Set the 2D matrix to the identity matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
-	 *
-	 * @param[in] m		The matrix to set to identity
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFloat2DSetIdentity(MatrixFloat2D *m);
-
-	/**
-	 * @brief	Multiple two 2D matrixes together
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
-	 *
-	 * @param[in] dst	The destination matrix
-	 * @param[in] src1	The first source matrix
-	 * @param[in] src2	The second source matrix
-	 *
-	 * @note	In-place matrix application is NOT allowed ie. dst != src1, dst != src2
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFloat2DMultiply(MatrixFloat2D *dst, const MatrixFloat2D *src1, const MatrixFloat2D *src2);
-
-	/**
-	 * @brief	Add an x,y translation to a matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
-	 *
-	 * @param[in] dst		The destination matrix
-	 * @param[in] src		The source matrix. Can be NULL
-	 * @param[in] tx, ty	The x and y translation to apply
-	 *
-	 * @note	In-place matrix operation is NOT allowed ie. dst != src
-	 * @note	If no source matrix is provided, it is equivalent to applying the operation
-	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFloat2DApplyTranslation(MatrixFloat2D *dst, const MatrixFloat2D *src, float tx, float ty);
-
-	/**
-	 * @brief	Add x,y scaling to a matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
-	 *
-	 * @param[in] dst		The destination matrix
-	 * @param[in] src		The source matrix. Can be NULL
-	 * @param[in] sx, sy	The scaling to apply in the x and y direction. Negative numbers give reflection.
-	 *
-	 * @note	In-place matrix operation is NOT allowed ie. dst != src
-	 * @note	If no source matrix is provided, it is equivalent to applying the operation
-	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFloat2DApplyScale(MatrixFloat2D *dst, const MatrixFloat2D *src, float sx, float sy);
-
-	/**
-	 * @brief	Add x,y shear to a matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
-	 *
-	 * @param[in] dst		The destination matrix
-	 * @param[in] src		The source matrix. Can be NULL
-	 * @param[in] sx, sy	The shear to apply in the x and y direction.
-	 *
-	 * @note	In-place matrix operation is NOT allowed ie. dst != src
-	 * @note	If no source matrix is provided, it is equivalent to applying the operation
-	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFloat2DApplyShear(MatrixFloat2D *dst, const MatrixFloat2D *src, float sx, float sy);
-
-	/**
-	 * @brief	Add rotation to a matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFLOAT2D
-	 *
-	 * @param[in] dst		The destination matrix
-	 * @param[in] src		The source matrix. Can be NULL
-	 * @param[in] angle		The angle to apply in degrees (not radians).
-	 *
-	 * @note	In-place matrix operation is NOT allowed ie. dst != src
-	 * @note	If no source matrix is provided, it is equivalent to applying the operation
-	 * 			to an identity matrix. It also is a much simpler operation.
-	 * @note	If GMISC_NEED_FASTTRIG is defined then the fast table sin and cos lookup's will be used
-	 * 			rather than the C library versions.
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFloat2DApplyRotation(MatrixFloat2D *dst, const MatrixFloat2D *src, int angle);
-#endif
-
-#if GMISC_NEED_MATRIXFIXED2D || defined(__DOXYGEN__)
-
-	/**
-	 * @brief	A matrix for doing 2D graphics using fixed point maths
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
-	 */
-	typedef struct MatrixFixed2D {
-		fixed	a00, a01, a02;
-		fixed	a10, a11, a12;
-		fixed	a20, a21, a22;
-	} MatrixFixed2D;
-
-	/**
-	 * @brief	Apply the matrix to a set of points
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
-	 *
-	 * @param[in] dst	The destination array of points
-	 * @param[in] src	The source array of points
-	 * @param[in] m		The matrix to apply
-	 * @param[in] cnt	How many points are in the array
-	 *
-	 * @note	In-place matrix application is allowed ie. dst = src
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFixed2DApplyToPoints(point *dst, const point *src, const MatrixFixed2D *m, int cnt);
-
-	/**
-	 * @brief	Set the 2D matrix to the identity matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
-	 *
-	 * @param[in] m		The matrix to set to identity
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFixed2DSetIdentity(MatrixFixed2D *m);
-
-	/**
-	 * @brief	Multiple two 2D matrixes together
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
-	 *
-	 * @param[in] dst	The destination matrix
-	 * @param[in] src1	The first source matrix
-	 * @param[in] src2	The second source matrix
-	 *
-	 * @note	In-place matrix application is NOT allowed ie. dst != src1, dst != src2
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFixed2DMultiply(MatrixFixed2D *dst, const MatrixFixed2D *src1, const MatrixFixed2D *src2);
-
-	/**
-	 * @brief	Add an x,y translation to a matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
-	 *
-	 * @param[in] dst		The destination matrix
-	 * @param[in] src		The source matrix. Can be NULL
-	 * @param[in] tx, ty	The x and y translation to apply
-	 *
-	 * @note	In-place matrix operation is NOT allowed ie. dst != src
-	 * @note	If no source matrix is provided, it is equivalent to applying the operation
-	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFixed2DApplyTranslation(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed tx, fixed ty);
-
-	/**
-	 * @brief	Add x,y scaling to a matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
-	 *
-	 * @param[in] dst		The destination matrix
-	 * @param[in] src		The source matrix. Can be NULL
-	 * @param[in] sx, sy	The scaling to apply in the x and y direction. Negative numbers give reflection.
-	 *
-	 * @note	In-place matrix operation is NOT allowed ie. dst != src
-	 * @note	If no source matrix is provided, it is equivalent to applying the operation
-	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFixed2DApplyScale(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed sx, fixed sy);
-
-	/**
-	 * @brief	Add x,y shear to a matrix
-	 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D
-	 *
-	 * @param[in] dst		The destination matrix
-	 * @param[in] src		The source matrix. Can be NULL
-	 * @param[in] sx, sy	The shear to apply in the x and y direction.
-	 *
-	 * @note	In-place matrix operation is NOT allowed ie. dst != src
-	 * @note	If no source matrix is provided, it is equivalent to applying the operation
-	 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
-	 *
-	 * @api
-	 */
-	void gmiscMatrixFixed2DApplyShear(MatrixFixed2D *dst, const MatrixFixed2D *src, fixed sx, fixed sy);
-
-	#if GMISC_NEED_FIXEDTRIG || defined(__DOXYGEN__)
-		/**
-		 * @brief	Add rotation to a matrix
-		 * @pre		Requires GFX_USE_GMISC and GMISC_NEED_MATRIXFIXED2D and GMISC_NEED_FIXEDTRIG
-		 *
-		 * @param[in] dst		The destination matrix
-		 * @param[in] src		The source matrix. Can be NULL
-		 * @param[in] angle		The angle to apply in degrees (not radians).
-		 *
-		 * @note	In-place matrix operation is NOT allowed ie. dst != src
-		 * @note	If no source matrix is provided, it is equivalent to applying the operation
-		 * 			to an identity matrix. It also is a much simpler operation requiring no multiplication.
-		 *
-		 * @api
-		 */
-		void gmiscMatrixFixed2DApplyRotation(MatrixFixed2D *dst, const MatrixFixed2D *src, int angle);
-	#endif
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_MISC */
-
-#endif /* _GMISC_H */
-/** @} */
-
diff --git a/src/gmisc/sys_make.mk b/src/gmisc/sys_make.mk
deleted file mode 100644
index 203910e6..00000000
--- a/src/gmisc/sys_make.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gmisc/gmisc_gmisc.c	\
-			$(GFXLIB)/src/gmisc/gmisc_arrayops.c	\
-			$(GFXLIB)/src/gmisc/gmisc_matrix2d.c	\
-			$(GFXLIB)/src/gmisc/gmisc_trig.c
diff --git a/src/gmisc/sys_options.h b/src/gmisc/sys_options.h
deleted file mode 100644
index 9cdf37f6..00000000
--- a/src/gmisc/sys_options.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gmisc/sys_options.h
- * @brief   GMISC - Miscellaneous Routines options header file.
- *
- * @addtogroup GMISC
- * @{
- */
-
-#ifndef _GMISC_OPTIONS_H
-#define _GMISC_OPTIONS_H
-
-/**
- * @name    GMISC Functionality to be included
- * @{
- */
-	/**
-	 * @brief   Include array operation functions
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GMISC_NEED_ARRAYOPS
-		#define GMISC_NEED_ARRAYOPS			FALSE
-	#endif
-	/**
-	 * @brief   Include fast floating point trig functions (fsin, fcos)
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GMISC_NEED_FASTTRIG
-		#define GMISC_NEED_FASTTRIG			FALSE
-	#endif
-	/**
-	 * @brief   Include fast fixed point trig functions (ffsin, ffcos)
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GMISC_NEED_FIXEDTRIG
-		#define GMISC_NEED_FIXEDTRIG		FALSE
-	#endif
-	/**
-	 * @brief   Include fast inverse square root (x^-1/2)
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GMISC_NEED_INVSQRT
-		#define GMISC_NEED_INVSQRT		FALSE
-	#endif
-/**
- * @}
- *
- * @name    GMISC Optional Parameters
- * @{
- */
-	/**
-	 * @brief	Modifies the @p invsqrt() function to assume a different integer to floating point endianness.
-	 * @note	Normally the floating point format and the integer format have
-	 * 			the same endianness. Unfortunately there are some strange
-	 * 			processors that don't eg. some very early ARM devices.
-	 * 			For those where the endianness doesn't match you can fix it by
-	 * 			defining GMISC_INVSQRT_MIXED_ENDIAN.
-	 * @note	This still assumes the processor is using an ieee floating point format.
-	 *
-	 * If you have a software floating point that uses a non-standard
-	 * floating point format (or very strange hardware) then define
-	 * GMISC_INVSQRT_REAL_SLOW and it will do it the hard way.
-	 */
-	#ifndef GMISC_INVSQRT_MIXED_ENDIAN
-		#define GMISC_INVSQRT_MIXED_ENDIAN	FALSE
-	#endif
-	/**
-	 * @brief	Modifies the @p invsqrt() function to do things the long slow way.
-	 * @note	This causes the @p invsqrt() function to work regardless of the
-	 * 			processor floating point format.
-	 * @note	This makes the @p invsqrt() function very slow.
-	 */
-	#ifndef GMISC_INVSQRT_REAL_SLOW
-		#define GMISC_INVSQRT_REAL_SLOW		FALSE
-	#endif
-/** @} */
-
-#endif /* _GMISC_OPTIONS_H */
-/** @} */
diff --git a/src/gmisc/sys_rules.h b/src/gmisc/sys_rules.h
deleted file mode 100644
index 6c66907a..00000000
--- a/src/gmisc/sys_rules.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gmisc/sys_rules.h
- * @brief   GMISC safety rules header file.
- *
- * @addtogroup GMISC
- * @{
- */
-
-#ifndef _GMISC_RULES_H
-#define _GMISC_RULES_H
-
-#if GFX_USE_GMISC
-#endif
-
-#endif /* _GMISC_RULES_H */
-/** @} */
diff --git a/src/gos/gos.h b/src/gos/gos.h
new file mode 100644
index 00000000..f1def55a
--- /dev/null
+++ b/src/gos/gos.h
@@ -0,0 +1,470 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gos/gos.h
+ * @brief   GOS - Operating System Support header file
+ *
+ * @addtogroup GOS
+ *
+ * @brief	Module to build a uniform abstraction layer between uGFX and the underlying system
+ *
+ * @note	Some of the routines specified below may be implemented simply as
+ * 			a macro to the real operating system call.
+ * @{
+ */
+
+#ifndef _GOS_H
+#define _GOS_H
+
+#if defined(__DOXYGEN__)
+	/*===========================================================================*/
+	/* Type definitions                                                          */
+	/*===========================================================================*/
+
+	/**
+	 * @name	Various integer sizes
+	 * @note	Your platform may use slightly different definitions to these
+	 * @{
+	 */
+	typedef unsigned char	bool_t;
+	typedef char			int8_t;
+	typedef unsigned char	uint8_t;
+	typedef short			int16_t;
+	typedef unsigned short	uint16_t;
+	typedef long			int32_t;
+	typedef unsigned long	uint32_t;
+	/** @} */
+
+	/**
+	 * @name	Various platform (and operating system) dependent types
+	 * @note	Your platform may use slightly different definitions to these
+	 * @{
+	 */
+	typedef unsigned long	size_t;
+	typedef unsigned long	delaytime_t;
+	typedef unsigned long	systemticks_t;
+	typedef short			semcount_t;
+	typedef int				threadreturn_t;
+	typedef int				threadpriority_t;
+	/** @} */
+
+	/**
+	 * @brief	Declare a thread function
+	 *
+	 * @param[in] fnName	The name of the function
+	 * @param[in] param 	A custom parameter that is passed to the function
+	 */
+	#define DECLARE_THREAD_FUNCTION(fnName, param)	threadreturn_t fnName(void *param)
+
+	/**
+	 * @brief	Declare a thread stack
+	 *
+	 * @param[in] name 		The name of the stack
+	 * @param[in] sz 		The size of the stack
+	 */
+	#define DECLARE_THREAD_STACK(name, sz)			uint8_t name[sz];
+
+	/**
+	 * @name	Various platform (and operating system) constants
+	 * @note	Your platform may use slightly different definitions to these
+	 * @{
+	 */
+	#define FALSE						0
+	#define TRUE						1
+	#define TIME_IMMEDIATE				0
+	#define TIME_INFINITE				((delaytime_t)-1)
+	#define MAX_SEMAPHORE_COUNT			((semcount_t)(((unsigned long)((semcount_t)(-1))) >> 1))
+	#define LOW_PRIORITY				0
+	#define NORMAL_PRIORITY				1
+	#define HIGH_PRIORITY				2
+	/** @} */
+
+	/**
+	 * @brief	A semaphore
+	 * @note	Your operating system will have a proper definition for this structure
+	 */
+	typedef struct {} gfxSem;
+
+	/**
+	 * @brief	A mutex
+	 * @note	Your operating system will have a proper definition for this structure
+	 */
+	typedef struct {} gfxMutex;
+
+	/**
+	 * @brief	A thread handle
+	 * @note	Your operating system will have a proper definition for this.
+	 */
+	typedef void * gfxThreadHandle;
+
+	/*===========================================================================*/
+	/* Function declarations.                                                    */
+	/*===========================================================================*/
+
+	#ifdef __cplusplus
+	extern "C" {
+	#endif
+
+	/**
+	 * @brief	Halt the GFX application due to an error.
+	 *
+	 * @param[in] msg	An optional debug message to show (Can be NULL)
+	 *
+	 * @api
+	 */
+	void gfxHalt(const char *msg);
+
+	/**
+	 * @brief	Exit the GFX application.
+	 *
+	 * @api
+	 */
+	void gfxExit(void);
+
+	/**
+	 * @brief	Allocate memory
+	 * @return	A pointer to the memory allocated or NULL if there is no more memory available
+	 *
+	 * @param[in] sz	The size in bytes of the area to allocate
+	 *
+	 * @api
+	 */
+	void *gfxAlloc(size_t sz);
+
+	/**
+	 * @brief	Re-allocate memory
+	 * @return	A pointer to the new memory area or NULL if there is no more memory available
+	 *
+	 * @param[in] ptr		The old memory area to be increased/decreased in size
+	 * @param[in] oldsz		The size in bytes of the old memory area
+	 * @param[in] newsz		The size in bytes of the new memory area
+	 *
+	 * @note		Some operating systems don't use the oldsz parameter as they implicitly know the size of
+	 * 				old memory area. The parameter must always be supplied however for API compatibility.
+	 * @note		gfxRealloc() can make the area smaller or larger but may have to return a different pointer.
+	 * 				If this occurs the new area contains a copy of the data from the old area. The old memory
+	 * 				pointer should not be used after this routine as the original area may have been freed.
+	 * @note		If there is insufficient memory to create the new memory region, NULL is returned and the
+	 * 				old memory area is left unchanged.
+	 *
+	 * @api
+	 */
+	void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz);
+
+	/**
+	 * @brief	Free memory
+	 *
+	 * @param[in] ptr	The memory to free
+	 *
+	 * @api
+	 */
+	void gfxFree(void *ptr);
+
+	/**
+	 * @brief	Yield the current thread
+	 * @details	Give up the rest of the current time slice for this thread in order to give other threads
+	 * 			a chance to run.
+	 *
+	 * @api
+	 */
+	void gfxYield(void);
+
+	/**
+	 * @brief	Put the current thread to sleep for the specified period in milliseconds
+	 *
+	 * @param[in] ms	The number milliseconds to sleep
+	 *
+	 * @note		Specifying TIME_IMMEDIATE will yield the current thread but return
+	 * 				on the next time slice.
+	 * @note		Specifying TIME_INFINITE will sleep forever.
+	 *
+	 * @api
+	 */
+	void gfxSleepMilliseconds(delaytime_t ms);
+
+	/**
+	 * @brief	Put the current thread to sleep for the specified period in microseconds
+	 *
+	 * @param[in] us	The number microseconds to sleep
+	 *
+	 * @note		Specifying TIME_IMMEDIATE will return immediately (no sleeping)
+	 * @note		Specifying TIME_INFINITE will sleep forever.
+	 *
+	 * @api
+	 */
+	void gfxSleepMicroseconds(delaytime_t us);
+
+	/**
+	 * @brief	Get the current operating system tick time
+	 * @return	The current tick time
+	 *
+	 * @note	A "tick" is an arbitrary period of time that the operating
+	 * 			system uses to mark time.
+	 * @note	The absolute value of this call is relatively meaningless. Its usefulness
+	 * 			is in calculating periods between two calls to this function.
+	 * @note	As the value from this function can wrap it is important that any periods are calculated
+	 * 			as t2 - t1 and then compared to the desired period rather than comparing
+	 * 			t1 + period to t2
+	 *
+	 * @api
+	 */
+	systemticks_t gfxSystemTicks(void);
+
+	/**
+	 * @brief	Convert a given number of millseconds to a number of operating system ticks
+	 * @return	The period in system ticks.
+	 *
+	 * @note	A "tick" is an arbitrary period of time that the operating
+	 * 			system uses to mark time.
+	 *
+	 * @param[in] ms	The number of millseconds
+	 *
+	 * @api
+	 */
+	systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
+
+	/**
+	 * @brief	Lock the operating system to protect a sequence of code
+	 *
+	 * @note	Calling this will lock out all other threads from executing even at interrupt level
+	 * 			within the GFX system. On hardware this may be implemented as a disabling of interrupts,
+	 * 			however in an operating system which hides real interrupt level code it may simply use a
+	 * 			mutex lock.
+	 * @note	The thread MUST NOT block whilst the system is locked. It must execute in this state for
+	 * 			as short a period as possible as this can seriously affect interrupt latency on some
+	 * 			platforms.
+	 * @note	While locked only interrupt level (iclass) GFX routines may be called.
+	 *
+	 * @api
+	 */
+	void gfxSystemLock(void);
+
+	/**
+	 * @brief	Unlock the operating system previous locked by gfxSystemLock()
+	 *
+	 * @api
+	 */
+	void gfxSystemUnlock(void);
+
+	/**
+	 * @brief	Initialise a mutex to protect a region of code from other threads.
+	 *
+	 * @param[in]	pmutex	A pointer to the mutex
+	 *
+	 * @note	Whilst a counting semaphore with a limit of 1 can be used for similiar purposes
+	 * 			on many operating systems using a seperate mutex structure is more efficient.
+	 *
+	 * @api
+	 */
+	void gfxMutexInit(gfxMutex *pmutex);
+
+	/**
+	 * @brief	Destroy a Mutex.
+	 *
+	 * @param[in]	pmutex	A pointer to the mutex
+	 *
+	 * @api
+	 */
+	void gfxMutexDestroy(gfxMutex *pmutex);
+
+	/**
+	 * @brief	Enter the critical code region protected by the mutex.
+	 * @details	Blocks until there is no other thread in the critical region.
+	 *
+	 * @param[in]	pmutex	A pointer to the mutex
+	 *
+	 * @api
+	 */
+	void gfxMutexEnter(gfxMutex *pmutex);
+
+	/**
+	 * @brief	Exit the critical code region protected by the mutex.
+	 * @details	May cause another thread waiting on the mutex to now be placed into the run queue.
+	 *
+	 * @param[in]	pmutex	A pointer to the mutex
+	 *
+	 * @api
+	 */
+	void gfxMutexExit(gfxMutex *pmutex);
+
+	/**
+	 * @brief	Initialise a Counted Semaphore
+	 *
+	 * @param[in] psem		A pointer to the semaphore
+	 * @param[in] val		The initial value of the semaphore
+	 * @param[in] limit		The maxmimum value of the semaphore
+	 *
+	 * @note	Operations defined for counted semaphores:
+	 * 				Signal: The semaphore counter is increased and if the result is non-positive then a waiting thread
+	 * 						 is queued for execution. Note that once the thread reaches "limit", further signals are
+	 * 						 ignored.
+	 * 				Wait: The semaphore counter is decreased and if the result becomes negative the thread is queued
+	 * 						in the semaphore and suspended.
+	 *
+	 * @api
+	 */
+	void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
+
+	/**
+	 * @brief	Destroy a Counted Semaphore
+	 *
+	 * @param[in] psem		A pointer to the semaphore
+	 *
+	 * @note	Any threads waiting on the semaphore will be released
+	 *
+	 * @api
+	 */
+	void gfxSemDestroy(gfxSem *psem);
+
+	/**
+	 * @brief	Wait on a semaphore
+	 * @details	The semaphore counter is decreased and if the result becomes negative the thread waits for it to become
+	 * 				non-negative again
+	 * @return	FALSE if the wait timeout occurred otherwise TRUE
+	 *
+	 * @param[in] psem		A pointer to the semaphore
+	 * @param[in] ms		The maximum time to wait for the semaphore
+	 *
+	 * @api
+	 */
+	bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
+
+	/**
+	 * @brief	Test if a wait on a semaphore can be satisfied immediately
+	 * @details	Equivalent to @p gfxSemWait(psem, TIME_IMMEDIATE) except it can be called at interrupt level
+	 * @return	FALSE if the wait would occur occurred otherwise TRUE
+	 *
+	 * @param[in] psem		A pointer to the semaphore
+	 *
+	 * @iclass
+	 * @api
+	 */
+	bool_t gfxSemWaitI(gfxSem *psem);
+
+	/**
+	 * @brief	Signal a semaphore
+	 * @details	The semaphore counter is increased and if the result is non-positive then a waiting thread
+	 * 						 is queued for execution. Note that once the thread reaches "limit", further signals are
+	 * 						 ignored.
+	 *
+	 * @param[in] psem		A pointer to the semaphore
+	 *
+	 * @api
+	 */
+	void gfxSemSignal(gfxSem *psem);
+
+	/**
+	 * @brief	Signal a semaphore
+	 * @details	The semaphore counter is increased and if the result is non-positive then a waiting thread
+	 * 						 is queued for execution. Note that once the thread reaches "limit", further signals are
+	 * 						 ignored.
+	 *
+	 * @param[in] psem		A pointer to the semaphore
+	 *
+	 * @iclass
+	 * @api
+	 */
+	void gfxSemSignalI(gfxSem *psem);
+
+	/**
+	 * @brief	Get the current semaphore count
+	 * @return	The current semaphore count
+	 *
+	 * @param[in] psem		A pointer to the semaphore
+	 *
+	 * @api
+	 */
+	semcount_t gfxSemCounter(gfxSem *psem);
+
+	/**
+	 * @brief	Get the current semaphore count
+	 * @return	The current semaphore count
+	 *
+	 * @param[in] psem		A pointer to the semaphore
+	 *
+	 * @iclass
+	 * @api
+	 */
+	semcount_t gfxSemCounterI(gfxSem *psem);
+
+	/**
+	 * @brief	Start a new thread.
+	 * @return	Returns a thread handle if the thread was started, NULL on an error
+	 *
+	 * @param[in]	stackarea	A pointer to the area for the new threads stack or NULL to dynamically allocate it
+	 * @param[in]	stacksz		The size of the thread stack. 0 means the default operating system size although this
+	 * 							is only valid when stackarea is dynamically allocated.
+	 * @param[in]	prio		The priority of the new thread
+	 * @param[in]	fn			The function the new thread will run
+	 * @param[in]	param		A parameter to pass the thread function.
+	 *
+	 * @api
+	 */
+	gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
+
+	/**
+	 * @brief	Wait for a thread to finish.
+	 * @return	Returns the thread exit code.
+	 *
+	 * @param[in]	thread		The Thread Handle
+	 *
+	 * @note		This will also close the thread handle as it is no longer useful
+	 * 				once the thread has ended.
+	 * @api
+	 */
+	threadreturn_t gfxThreadWait(gfxThreadHandle thread);
+
+	/**
+	 * @brief	Get the current thread handle.
+	 * @return	A thread handle
+	 *
+	 * @api
+	 */
+	gfxThreadHandle gfxThreadMe(void);
+
+	/**
+	 * @brief	Close the thread handle.
+	 *
+	 * @param[in]	thread		The Thread Handle
+	 *
+	 * @note	This does not affect the thread, it just closes our handle to the thread.
+	 *
+	 * @api
+	 */
+	void gfxThreadClose(gfxThreadHandle thread);
+
+	#ifdef __cplusplus
+	}
+	#endif
+
+/**
+ * All the above was just for the doxygen documentation. All the implementation of the above
+ * (without any of the documentation overheads) is in the files below.
+ */
+#elif GFX_USE_OS_RAWRTOS
+ 	#include "src/gos/gos_rawrtos.h"
+#elif GFX_USE_OS_CHIBIOS
+	#include "src/gos/gos_chibios.h"
+#elif GFX_USE_OS_FREERTOS
+	#include "src/gos/gos_freertos.h"
+#elif GFX_USE_OS_WIN32
+	#include "src/gos/gos_win32.h"
+#elif GFX_USE_OS_LINUX
+	#include "src/gos/gos_linux.h"
+#elif GFX_USE_OS_OSX
+	#include "src/gos/gos_osx.h"
+#elif GFX_USE_OS_RAW32
+	#include "src/gos/gos_raw32.h"
+#elif GFX_USE_OS_ECOS
+	#include "src/gos/gos_ecos.h"
+#else
+	#error "Your operating system is not supported yet"
+#endif
+
+#endif /* _GOS_H */
+/** @} */
diff --git a/src/gos/gos.mk b/src/gos/gos.mk
new file mode 100644
index 00000000..a7b3dec6
--- /dev/null
+++ b/src/gos/gos.mk
@@ -0,0 +1,9 @@
+GFXSRC +=   $(GFXLIB)/src/gos/gos_chibios.c	\
+			$(GFXLIB)/src/gos/gos_freertos.c \
+			$(GFXLIB)/src/gos/gos_win32.c \
+			$(GFXLIB)/src/gos/gos_linux.c \
+			$(GFXLIB)/src/gos/gos_osx.c \
+			$(GFXLIB)/src/gos/gos_raw32.c \
+			$(GFXLIB)/src/gos/gos_ecos.c \
+			$(GFXLIB)/src/gos/gos_rawrtos.c
+
diff --git a/src/gos/gos_options.h b/src/gos/gos_options.h
new file mode 100644
index 00000000..611acfb7
--- /dev/null
+++ b/src/gos/gos_options.h
@@ -0,0 +1,115 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gos/gos_options.h
+ * @brief   GOS - Operating System options header file.
+ *
+ * @addtogroup GOS
+ * @{
+ */
+
+#ifndef _GOS_OPTIONS_H
+#define _GOS_OPTIONS_H
+
+/**
+ * @name    The operating system to use. One (and only one) of these must be defined.
+ * @{
+ */
+	/**
+	 * @brief   Use ChibiOS
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFX_USE_OS_CHIBIOS
+		#define GFX_USE_OS_CHIBIOS		FALSE
+	#endif
+	/**
+	 * @brief   Use FreeRTOS
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFX_USE_OS_FREERTOS
+		#define GFX_USE_OS_FREERTOS		FALSE
+	#endif
+	/**
+	 * @brief   Use Win32
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFX_USE_OS_WIN32
+		#define GFX_USE_OS_WIN32		FALSE
+	#endif
+	/**
+	 * @brief   Use a linux based system running X11
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFX_USE_OS_LINUX
+		#define GFX_USE_OS_LINUX		FALSE
+	#endif
+	/**
+	 * @brief   Use a Mac OS-X based system
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFX_USE_OS_OSX
+		#define GFX_USE_OS_OSX			FALSE
+	#endif
+	/**
+	 * @brief   Use a Raw 32 bit CPU based system
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFX_USE_OS_RAW32
+		#define GFX_USE_OS_RAW32		FALSE
+	#endif
+	/**
+	 * @brief   Use a eCos
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GFX_USE_OS_ECOS
+		#define GFX_USE_OS_ECOS			FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GOS Optional Parameters
+ * @{
+ */
+ 	/**
+ 	 * @brief	Should uGFX avoid initializing the operating system
+ 	 * @details	Defaults to FALSE
+ 	 * @note	This is not relevant to all operating systems eg Win32 never initializes the
+ 	 * 			operating system as uGFX runs as an application outside the boot process.
+ 	 * @note	Operating system initialization is not necessarily implemented for all
+ 	 * 			operating systems yet even when it is relevant. These operating systems
+ 	 * 			will display a compile warning reminding you to initialize the operating
+ 	 * 			system in your application code. Note that on these operating systems the
+ 	 * 			demo applications will not work without modification.
+ 	 */
+ 	#ifndef GFX_NO_OS_INIT
+ 		#define GFX_NO_OS_INIT			FALSE
+ 	#endif
+ 	/**
+ 	 * @brief	Should uGFX stuff be added to the FreeRTOS+Tracer
+ 	 * @details	Defaults to FALSE
+ 	 */
+ 	#ifndef GFX_FREERTOS_USE_TRACE
+ 		#define GFX_FREERTOS_USE_TRACE	FALSE
+ 	#endif
+ 	/**
+ 	 * @brief	How much RAM should uGFX use for the heap
+ 	 * @details	Defaults to 0. Only valid with GFX_USE_OS_RAW32
+ 	 * @note	If 0 then the standard C runtime malloc(), free() and realloc()
+ 	 * 			are used.
+ 	 * @note	If it is non-zero then this is the number of bytes of RAM
+ 	 * 			to use for the heap (gfxAlloc() and gfxFree()). No C
+ 	 * 			runtime routines will be used and a new routine @p gfxAddHeapBlock()
+ 	 * 			is added allowing the user to add extra memory blocks to the heap.
+ 	 */
+	#ifndef GOS_RAW_HEAP_SIZE
+		#define GOS_RAW_HEAP_SIZE		0
+	#endif
+/** @} */
+
+#endif /* _GOS_OPTIONS_H */
+/** @} */
diff --git a/src/gos/gos_rawrtos.c b/src/gos/gos_rawrtos.c
index cd684208..c47c85bf 100644
--- a/src/gos/gos_rawrtos.c
+++ b/src/gos/gos_rawrtos.c
@@ -1,3 +1,10 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
 #include "gfx.h"
 
 #if GFX_USE_OS_RAWRTOS
diff --git a/src/gos/gos_rules.h b/src/gos/gos_rules.h
new file mode 100644
index 00000000..0a86f86e
--- /dev/null
+++ b/src/gos/gos_rules.h
@@ -0,0 +1,36 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gos/gos_rules.h
+ * @brief   GOS safety rules header file.
+ *
+ * @addtogroup GOS
+ * @{
+ */
+
+#ifndef _GOS_RULES_H
+#define _GOS_RULES_H
+
+#if !GFX_USE_OS_CHIBIOS && !GFX_USE_OS_WIN32 && !GFX_USE_OS_LINUX && !GFX_USE_OS_OSX && !GFX_USE_OS_RAW32 && !GFX_USE_OS_FREERTOS && !GFX_USE_OS_ECOS && !GFX_USE_OS_RAWRTOS
+	#if GFX_DISPLAY_RULE_WARNINGS
+		#warning "GOS: No Operating System has been defined. ChibiOS (GFX_USE_OS_CHIBIOS) has been turned on for you."
+	#endif
+	#undef GFX_USE_OS_CHIBIOS
+	#define GFX_USE_OS_CHIBIOS	TRUE
+#endif
+
+#if GFX_USE_OS_CHIBIOS + GFX_USE_OS_WIN32 + GFX_USE_OS_LINUX + GFX_USE_OS_OSX + GFX_USE_OS_RAW32 + GFX_USE_OS_FREERTOS + GFX_USE_OS_ECOS + GFX_USE_OS_RAWRTOS != 1 * TRUE
+	#error "GOS: More than one operation system has been defined as TRUE."
+#endif
+
+#if GFX_FREERTOS_USE_TRACE && !GFX_USE_OS_FREERTOS
+ 	#error "GOS: GFX_FREERTOS_USE_TRACE is only available for the FreeRTOS port."
+#endif
+
+#endif /* _GOS_RULES_H */
+/** @} */
diff --git a/src/gos/gos_win32.c b/src/gos/gos_win32.c
index 0ae9e618..a7e0943b 100644
--- a/src/gos/gos_win32.c
+++ b/src/gos/gos_win32.c
@@ -5,10 +5,6 @@
  *              http://ugfx.org/license.html
  */
 
-/**
- * @file    src/gos/gos_win32.c
- * @brief   GOS Win32 Operating System support.
- */
 #include "gfx.h"
 
 #if GFX_USE_OS_WIN32
diff --git a/src/gos/sys_defs.h b/src/gos/sys_defs.h
deleted file mode 100644
index 7e1348bb..00000000
--- a/src/gos/sys_defs.h
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gos/sys_defs.h
- * @brief   GOS - Operating System Support header file
- *
- * @addtogroup GOS
- *
- * @brief	Module to build a uniform abstraction layer between uGFX and the underlying system
- *
- * @note	Some of the routines specified below may be implemented simply as
- * 			a macro to the real operating system call.
- * @{
- */
-
-#ifndef _GOS_H
-#define _GOS_H
-
-#if defined(__DOXYGEN__)
-	/*===========================================================================*/
-	/* Type definitions                                                          */
-	/*===========================================================================*/
-
-	/**
-	 * @name	Various integer sizes
-	 * @note	Your platform may use slightly different definitions to these
-	 * @{
-	 */
-	typedef unsigned char	bool_t;
-	typedef char			int8_t;
-	typedef unsigned char	uint8_t;
-	typedef short			int16_t;
-	typedef unsigned short	uint16_t;
-	typedef long			int32_t;
-	typedef unsigned long	uint32_t;
-	/** @} */
-
-	/**
-	 * @name	Various platform (and operating system) dependent types
-	 * @note	Your platform may use slightly different definitions to these
-	 * @{
-	 */
-	typedef unsigned long	size_t;
-	typedef unsigned long	delaytime_t;
-	typedef unsigned long	systemticks_t;
-	typedef short			semcount_t;
-	typedef int				threadreturn_t;
-	typedef int				threadpriority_t;
-	/** @} */
-
-	/**
-	 * @brief	Declare a thread function
-	 *
-	 * @param[in] fnName	The name of the function
-	 * @param[in] param 	A custom parameter that is passed to the function
-	 */
-	#define DECLARE_THREAD_FUNCTION(fnName, param)	threadreturn_t fnName(void *param)
-
-	/**
-	 * @brief	Declare a thread stack
-	 *
-	 * @param[in] name 		The name of the stack
-	 * @param[in] sz 		The size of the stack
-	 */
-	#define DECLARE_THREAD_STACK(name, sz)			uint8_t name[sz];
-
-	/**
-	 * @name	Various platform (and operating system) constants
-	 * @note	Your platform may use slightly different definitions to these
-	 * @{
-	 */
-	#define FALSE						0
-	#define TRUE						1
-	#define TIME_IMMEDIATE				0
-	#define TIME_INFINITE				((delaytime_t)-1)
-	#define MAX_SEMAPHORE_COUNT			((semcount_t)(((unsigned long)((semcount_t)(-1))) >> 1))
-	#define LOW_PRIORITY				0
-	#define NORMAL_PRIORITY				1
-	#define HIGH_PRIORITY				2
-	/** @} */
-
-	/**
-	 * @brief	A semaphore
-	 * @note	Your operating system will have a proper definition for this structure
-	 */
-	typedef struct {} gfxSem;
-
-	/**
-	 * @brief	A mutex
-	 * @note	Your operating system will have a proper definition for this structure
-	 */
-	typedef struct {} gfxMutex;
-
-	/**
-	 * @brief	A thread handle
-	 * @note	Your operating system will have a proper definition for this.
-	 */
-	typedef void * gfxThreadHandle;
-
-	/*===========================================================================*/
-	/* Function declarations.                                                    */
-	/*===========================================================================*/
-
-	#ifdef __cplusplus
-	extern "C" {
-	#endif
-
-	/**
-	 * @brief	Halt the GFX application due to an error.
-	 *
-	 * @param[in] msg	An optional debug message to show (Can be NULL)
-	 *
-	 * @api
-	 */
-	void gfxHalt(const char *msg);
-
-	/**
-	 * @brief	Exit the GFX application.
-	 *
-	 * @api
-	 */
-	void gfxExit(void);
-
-	/**
-	 * @brief	Allocate memory
-	 * @return	A pointer to the memory allocated or NULL if there is no more memory available
-	 *
-	 * @param[in] sz	The size in bytes of the area to allocate
-	 *
-	 * @api
-	 */
-	void *gfxAlloc(size_t sz);
-
-	/**
-	 * @brief	Re-allocate memory
-	 * @return	A pointer to the new memory area or NULL if there is no more memory available
-	 *
-	 * @param[in] ptr		The old memory area to be increased/decreased in size
-	 * @param[in] oldsz		The size in bytes of the old memory area
-	 * @param[in] newsz		The size in bytes of the new memory area
-	 *
-	 * @note		Some operating systems don't use the oldsz parameter as they implicitly know the size of
-	 * 				old memory area. The parameter must always be supplied however for API compatibility.
-	 * @note		gfxRealloc() can make the area smaller or larger but may have to return a different pointer.
-	 * 				If this occurs the new area contains a copy of the data from the old area. The old memory
-	 * 				pointer should not be used after this routine as the original area may have been freed.
-	 * @note		If there is insufficient memory to create the new memory region, NULL is returned and the
-	 * 				old memory area is left unchanged.
-	 *
-	 * @api
-	 */
-	void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz);
-
-	/**
-	 * @brief	Free memory
-	 *
-	 * @param[in] ptr	The memory to free
-	 *
-	 * @api
-	 */
-	void gfxFree(void *ptr);
-
-	/**
-	 * @brief	Yield the current thread
-	 * @details	Give up the rest of the current time slice for this thread in order to give other threads
-	 * 			a chance to run.
-	 *
-	 * @api
-	 */
-	void gfxYield(void);
-
-	/**
-	 * @brief	Put the current thread to sleep for the specified period in milliseconds
-	 *
-	 * @param[in] ms	The number milliseconds to sleep
-	 *
-	 * @note		Specifying TIME_IMMEDIATE will yield the current thread but return
-	 * 				on the next time slice.
-	 * @note		Specifying TIME_INFINITE will sleep forever.
-	 *
-	 * @api
-	 */
-	void gfxSleepMilliseconds(delaytime_t ms);
-
-	/**
-	 * @brief	Put the current thread to sleep for the specified period in microseconds
-	 *
-	 * @param[in] us	The number microseconds to sleep
-	 *
-	 * @note		Specifying TIME_IMMEDIATE will return immediately (no sleeping)
-	 * @note		Specifying TIME_INFINITE will sleep forever.
-	 *
-	 * @api
-	 */
-	void gfxSleepMicroseconds(delaytime_t us);
-
-	/**
-	 * @brief	Get the current operating system tick time
-	 * @return	The current tick time
-	 *
-	 * @note	A "tick" is an arbitrary period of time that the operating
-	 * 			system uses to mark time.
-	 * @note	The absolute value of this call is relatively meaningless. Its usefulness
-	 * 			is in calculating periods between two calls to this function.
-	 * @note	As the value from this function can wrap it is important that any periods are calculated
-	 * 			as t2 - t1 and then compared to the desired period rather than comparing
-	 * 			t1 + period to t2
-	 *
-	 * @api
-	 */
-	systemticks_t gfxSystemTicks(void);
-
-	/**
-	 * @brief	Convert a given number of millseconds to a number of operating system ticks
-	 * @return	The period in system ticks.
-	 *
-	 * @note	A "tick" is an arbitrary period of time that the operating
-	 * 			system uses to mark time.
-	 *
-	 * @param[in] ms	The number of millseconds
-	 *
-	 * @api
-	 */
-	systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
-
-	/**
-	 * @brief	Lock the operating system to protect a sequence of code
-	 *
-	 * @note	Calling this will lock out all other threads from executing even at interrupt level
-	 * 			within the GFX system. On hardware this may be implemented as a disabling of interrupts,
-	 * 			however in an operating system which hides real interrupt level code it may simply use a
-	 * 			mutex lock.
-	 * @note	The thread MUST NOT block whilst the system is locked. It must execute in this state for
-	 * 			as short a period as possible as this can seriously affect interrupt latency on some
-	 * 			platforms.
-	 * @note	While locked only interrupt level (iclass) GFX routines may be called.
-	 *
-	 * @api
-	 */
-	void gfxSystemLock(void);
-
-	/**
-	 * @brief	Unlock the operating system previous locked by gfxSystemLock()
-	 *
-	 * @api
-	 */
-	void gfxSystemUnlock(void);
-
-	/**
-	 * @brief	Initialise a mutex to protect a region of code from other threads.
-	 *
-	 * @param[in]	pmutex	A pointer to the mutex
-	 *
-	 * @note	Whilst a counting semaphore with a limit of 1 can be used for similiar purposes
-	 * 			on many operating systems using a seperate mutex structure is more efficient.
-	 *
-	 * @api
-	 */
-	void gfxMutexInit(gfxMutex *pmutex);
-
-	/**
-	 * @brief	Destroy a Mutex.
-	 *
-	 * @param[in]	pmutex	A pointer to the mutex
-	 *
-	 * @api
-	 */
-	void gfxMutexDestroy(gfxMutex *pmutex);
-
-	/**
-	 * @brief	Enter the critical code region protected by the mutex.
-	 * @details	Blocks until there is no other thread in the critical region.
-	 *
-	 * @param[in]	pmutex	A pointer to the mutex
-	 *
-	 * @api
-	 */
-	void gfxMutexEnter(gfxMutex *pmutex);
-
-	/**
-	 * @brief	Exit the critical code region protected by the mutex.
-	 * @details	May cause another thread waiting on the mutex to now be placed into the run queue.
-	 *
-	 * @param[in]	pmutex	A pointer to the mutex
-	 *
-	 * @api
-	 */
-	void gfxMutexExit(gfxMutex *pmutex);
-
-	/**
-	 * @brief	Initialise a Counted Semaphore
-	 *
-	 * @param[in] psem		A pointer to the semaphore
-	 * @param[in] val		The initial value of the semaphore
-	 * @param[in] limit		The maxmimum value of the semaphore
-	 *
-	 * @note	Operations defined for counted semaphores:
-	 * 				Signal: The semaphore counter is increased and if the result is non-positive then a waiting thread
-	 * 						 is queued for execution. Note that once the thread reaches "limit", further signals are
-	 * 						 ignored.
-	 * 				Wait: The semaphore counter is decreased and if the result becomes negative the thread is queued
-	 * 						in the semaphore and suspended.
-	 *
-	 * @api
-	 */
-	void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
-
-	/**
-	 * @brief	Destroy a Counted Semaphore
-	 *
-	 * @param[in] psem		A pointer to the semaphore
-	 *
-	 * @note	Any threads waiting on the semaphore will be released
-	 *
-	 * @api
-	 */
-	void gfxSemDestroy(gfxSem *psem);
-
-	/**
-	 * @brief	Wait on a semaphore
-	 * @details	The semaphore counter is decreased and if the result becomes negative the thread waits for it to become
-	 * 				non-negative again
-	 * @return	FALSE if the wait timeout occurred otherwise TRUE
-	 *
-	 * @param[in] psem		A pointer to the semaphore
-	 * @param[in] ms		The maximum time to wait for the semaphore
-	 *
-	 * @api
-	 */
-	bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
-
-	/**
-	 * @brief	Test if a wait on a semaphore can be satisfied immediately
-	 * @details	Equivalent to @p gfxSemWait(psem, TIME_IMMEDIATE) except it can be called at interrupt level
-	 * @return	FALSE if the wait would occur occurred otherwise TRUE
-	 *
-	 * @param[in] psem		A pointer to the semaphore
-	 *
-	 * @iclass
-	 * @api
-	 */
-	bool_t gfxSemWaitI(gfxSem *psem);
-
-	/**
-	 * @brief	Signal a semaphore
-	 * @details	The semaphore counter is increased and if the result is non-positive then a waiting thread
-	 * 						 is queued for execution. Note that once the thread reaches "limit", further signals are
-	 * 						 ignored.
-	 *
-	 * @param[in] psem		A pointer to the semaphore
-	 *
-	 * @api
-	 */
-	void gfxSemSignal(gfxSem *psem);
-
-	/**
-	 * @brief	Signal a semaphore
-	 * @details	The semaphore counter is increased and if the result is non-positive then a waiting thread
-	 * 						 is queued for execution. Note that once the thread reaches "limit", further signals are
-	 * 						 ignored.
-	 *
-	 * @param[in] psem		A pointer to the semaphore
-	 *
-	 * @iclass
-	 * @api
-	 */
-	void gfxSemSignalI(gfxSem *psem);
-
-	/**
-	 * @brief	Get the current semaphore count
-	 * @return	The current semaphore count
-	 *
-	 * @param[in] psem		A pointer to the semaphore
-	 *
-	 * @api
-	 */
-	semcount_t gfxSemCounter(gfxSem *psem);
-
-	/**
-	 * @brief	Get the current semaphore count
-	 * @return	The current semaphore count
-	 *
-	 * @param[in] psem		A pointer to the semaphore
-	 *
-	 * @iclass
-	 * @api
-	 */
-	semcount_t gfxSemCounterI(gfxSem *psem);
-
-	/**
-	 * @brief	Start a new thread.
-	 * @return	Returns a thread handle if the thread was started, NULL on an error
-	 *
-	 * @param[in]	stackarea	A pointer to the area for the new threads stack or NULL to dynamically allocate it
-	 * @param[in]	stacksz		The size of the thread stack. 0 means the default operating system size although this
-	 * 							is only valid when stackarea is dynamically allocated.
-	 * @param[in]	prio		The priority of the new thread
-	 * @param[in]	fn			The function the new thread will run
-	 * @param[in]	param		A parameter to pass the thread function.
-	 *
-	 * @api
-	 */
-	gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
-
-	/**
-	 * @brief	Wait for a thread to finish.
-	 * @return	Returns the thread exit code.
-	 *
-	 * @param[in]	thread		The Thread Handle
-	 *
-	 * @note		This will also close the thread handle as it is no longer useful
-	 * 				once the thread has ended.
-	 * @api
-	 */
-	threadreturn_t gfxThreadWait(gfxThreadHandle thread);
-
-	/**
-	 * @brief	Get the current thread handle.
-	 * @return	A thread handle
-	 *
-	 * @api
-	 */
-	gfxThreadHandle gfxThreadMe(void);
-
-	/**
-	 * @brief	Close the thread handle.
-	 *
-	 * @param[in]	thread		The Thread Handle
-	 *
-	 * @note	This does not affect the thread, it just closes our handle to the thread.
-	 *
-	 * @api
-	 */
-	void gfxThreadClose(gfxThreadHandle thread);
-
-	#ifdef __cplusplus
-	}
-	#endif
-
-/**
- * All the above was just for the doxygen documentation. All the implementation of the above
- * (without any of the documentation overheads) is in the files below.
- */
-#elif GFX_USE_OS_RAWRTOS
- 	#include "src/gos/gos_rawrtos.h"
-#elif GFX_USE_OS_CHIBIOS
-	#include "src/gos/gos_chibios.h"
-#elif GFX_USE_OS_FREERTOS
-	#include "src/gos/gos_freertos.h"
-#elif GFX_USE_OS_WIN32
-	#include "src/gos/gos_win32.h"
-#elif GFX_USE_OS_LINUX
-	#include "src/gos/gos_linux.h"
-#elif GFX_USE_OS_OSX
-	#include "src/gos/gos_osx.h"
-#elif GFX_USE_OS_RAW32
-	#include "src/gos/gos_raw32.h"
-#elif GFX_USE_OS_ECOS
-	#include "src/gos/gos_ecos.h"
-#else
-	#error "Your operating system is not supported yet"
-#endif
-
-#endif /* _GOS_H */
-/** @} */
diff --git a/src/gos/sys_make.mk b/src/gos/sys_make.mk
deleted file mode 100644
index a7b3dec6..00000000
--- a/src/gos/sys_make.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gos/gos_chibios.c	\
-			$(GFXLIB)/src/gos/gos_freertos.c \
-			$(GFXLIB)/src/gos/gos_win32.c \
-			$(GFXLIB)/src/gos/gos_linux.c \
-			$(GFXLIB)/src/gos/gos_osx.c \
-			$(GFXLIB)/src/gos/gos_raw32.c \
-			$(GFXLIB)/src/gos/gos_ecos.c \
-			$(GFXLIB)/src/gos/gos_rawrtos.c
-
diff --git a/src/gos/sys_options.h b/src/gos/sys_options.h
deleted file mode 100644
index 45e398dd..00000000
--- a/src/gos/sys_options.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gos/sys_options.h
- * @brief   GOS - Operating System options header file.
- *
- * @addtogroup GOS
- * @{
- */
-
-#ifndef _GOS_OPTIONS_H
-#define _GOS_OPTIONS_H
-
-/**
- * @name    The operating system to use. One (and only one) of these must be defined.
- * @{
- */
-	/**
-	 * @brief   Use ChibiOS
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFX_USE_OS_CHIBIOS
-		#define GFX_USE_OS_CHIBIOS		FALSE
-	#endif
-	/**
-	 * @brief   Use FreeRTOS
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFX_USE_OS_FREERTOS
-		#define GFX_USE_OS_FREERTOS		FALSE
-	#endif
-	/**
-	 * @brief   Use Win32
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFX_USE_OS_WIN32
-		#define GFX_USE_OS_WIN32		FALSE
-	#endif
-	/**
-	 * @brief   Use a linux based system running X11
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFX_USE_OS_LINUX
-		#define GFX_USE_OS_LINUX		FALSE
-	#endif
-	/**
-	 * @brief   Use a Mac OS-X based system
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFX_USE_OS_OSX
-		#define GFX_USE_OS_OSX			FALSE
-	#endif
-	/**
-	 * @brief   Use a Raw 32 bit CPU based system
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFX_USE_OS_RAW32
-		#define GFX_USE_OS_RAW32		FALSE
-	#endif
-	/**
-	 * @brief   Use a eCos
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GFX_USE_OS_ECOS
-		#define GFX_USE_OS_ECOS			FALSE
-	#endif
-/**
- * @}
- *
- * @name    GOS Optional Parameters
- * @{
- */
- 	/**
- 	 * @brief	Should uGFX avoid initializing the operating system
- 	 * @details	Defaults to FALSE
- 	 * @note	This is not relevant to all operating systems eg Win32 never initializes the
- 	 * 			operating system as uGFX runs as an application outside the boot process.
- 	 * @note	Operating system initialization is not necessarily implemented for all
- 	 * 			operating systems yet even when it is relevant. These operating systems
- 	 * 			will display a compile warning reminding you to initialize the operating
- 	 * 			system in your application code. Note that on these operating systems the
- 	 * 			demo applications will not work without modification.
- 	 */
- 	#ifndef GFX_NO_OS_INIT
- 		#define GFX_NO_OS_INIT			FALSE
- 	#endif
- 	/**
- 	 * @brief	Should uGFX stuff be added to the FreeRTOS+Tracer
- 	 * @details	Defaults to FALSE
- 	 */
- 	#ifndef GFX_FREERTOS_USE_TRACE
- 		#define GFX_FREERTOS_USE_TRACE	FALSE
- 	#endif
- 	/**
- 	 * @brief	How much RAM should uGFX use for the heap
- 	 * @details	Defaults to 0. Only valid with GFX_USE_OS_RAW32
- 	 * @note	If 0 then the standard C runtime malloc(), free() and realloc()
- 	 * 			are used.
- 	 * @note	If it is non-zero then this is the number of bytes of RAM
- 	 * 			to use for the heap (gfxAlloc() and gfxFree()). No C
- 	 * 			runtime routines will be used and a new routine @p gfxAddHeapBlock()
- 	 * 			is added allowing the user to add extra memory blocks to the heap.
- 	 */
-	#ifndef GOS_RAW_HEAP_SIZE
-		#define GOS_RAW_HEAP_SIZE		0
-	#endif
-/** @} */
-
-#endif /* _GOS_OPTIONS_H */
-/** @} */
diff --git a/src/gos/sys_rules.h b/src/gos/sys_rules.h
deleted file mode 100644
index 6d6c7845..00000000
--- a/src/gos/sys_rules.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gos/sys_rules.h
- * @brief   GOS safety rules header file.
- *
- * @addtogroup GOS
- * @{
- */
-
-#ifndef _GOS_RULES_H
-#define _GOS_RULES_H
-
-#if !GFX_USE_OS_CHIBIOS && !GFX_USE_OS_WIN32 && !GFX_USE_OS_LINUX && !GFX_USE_OS_OSX && !GFX_USE_OS_RAW32 && !GFX_USE_OS_FREERTOS && !GFX_USE_OS_ECOS && !GFX_USE_OS_RAWRTOS
-	#if GFX_DISPLAY_RULE_WARNINGS
-		#warning "GOS: No Operating System has been defined. ChibiOS (GFX_USE_OS_CHIBIOS) has been turned on for you."
-	#endif
-	#undef GFX_USE_OS_CHIBIOS
-	#define GFX_USE_OS_CHIBIOS	TRUE
-#endif
-
-#if GFX_USE_OS_CHIBIOS + GFX_USE_OS_WIN32 + GFX_USE_OS_LINUX + GFX_USE_OS_OSX + GFX_USE_OS_RAW32 + GFX_USE_OS_FREERTOS + GFX_USE_OS_ECOS + GFX_USE_OS_RAWRTOS != 1 * TRUE
-	#error "GOS: More than one operation system has been defined as TRUE."
-#endif
-
-#if GFX_FREERTOS_USE_TRACE && !GFX_USE_OS_FREERTOS
- 	#error "GOS: GFX_FREERTOS_USE_TRACE is only available for the FreeRTOS port."
-#endif
-
-#endif /* _GOS_RULES_H */
-/** @} */
diff --git a/src/gqueue/gqueue.c b/src/gqueue/gqueue.c
new file mode 100644
index 00000000..1205143f
--- /dev/null
+++ b/src/gqueue/gqueue.c
@@ -0,0 +1,464 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GQUEUE
+
+#if GQUEUE_NEED_BUFFERS
+	static gfxQueueGSync	bufferFreeList;
+#endif
+
+void _gqueueInit(void)
+{
+	#if GQUEUE_NEED_BUFFERS
+		gfxQueueGSyncInit(&bufferFreeList);
+	#endif
+}
+
+void _gqueueDeinit(void)
+{
+}
+
+#if GQUEUE_NEED_ASYNC
+	void gfxQueueASyncInit(gfxQueueASync *pqueue) {
+		pqueue->head = pqueue->tail = 0;
+	}
+
+	gfxQueueASyncItem *gfxQueueASyncGet(gfxQueueASync *pqueue) {
+		gfxQueueASyncItem	*pi;
+
+		// This is just a shortcut to speed execution
+		if (!pqueue->head)
+			return 0;
+
+		gfxSystemLock();
+		pi = gfxQueueASyncGetI(pqueue);
+		gfxSystemUnlock();
+
+		return pi;
+	}
+	gfxQueueASyncItem *gfxQueueASyncGetI(gfxQueueASync *pqueue) {
+		gfxQueueASyncItem	*pi;
+
+		if ((pi = pqueue->head)) {
+			pqueue->head = pi->next;
+			pi->next = 0;
+		}
+
+		return pi;
+	}
+
+	void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+		gfxSystemLock();
+		gfxQueueASyncPutI(pqueue, pitem);
+		gfxSystemUnlock();
+	}
+	void gfxQueueASyncPutI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+		if (!pitem) return;				// Safety
+		pitem->next = 0;
+		if (!pqueue->head) {
+			pqueue->head = pqueue->tail = pitem;
+		} else {
+			pqueue->tail->next = pitem;
+			pqueue->tail = pitem;
+		}
+	}
+
+	void gfxQueueASyncPush(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+		gfxSystemLock();
+		gfxQueueASyncPushI(pqueue, pitem);
+		gfxSystemUnlock();
+	}
+	void gfxQueueASyncPushI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+		if (!pitem) return;				// Safety
+		pitem->next = pqueue->head;
+		pqueue->head = pitem;
+		if (!pitem->next)
+			pqueue->tail = pitem;
+	}
+
+	void gfxQueueASyncInsert(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem, gfxQueueASyncItem *pafter) {
+		gfxSystemLock();
+		gfxQueueASyncInsertI(pqueue, pitem, pafter);
+		gfxSystemUnlock();
+	}
+	void gfxQueueASyncInsertI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem, gfxQueueASyncItem *pafter) {
+		if (!pitem) return;				// Safety
+
+		if (pafter && gfxQueueASyncIsInI(pqueue, pafter)) {
+			pitem->next = pafter->next;
+			pafter->next = pitem;
+			if (pqueue->tail == pafter)
+				pqueue->tail = pitem;
+		} else {
+			pitem->next = 0;
+			if (!pqueue->head) {
+				pqueue->head = pqueue->tail = pitem;
+			} else {
+				pqueue->tail->next = pitem;
+				pqueue->tail = pitem;
+			}
+		}
+	}
+
+	void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+		gfxSystemLock();
+		gfxQueueASyncRemoveI(pqueue, pitem);
+		gfxSystemUnlock();
+	}
+	void gfxQueueASyncRemoveI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+		gfxQueueASyncItem *pi;
+
+		if (!pitem) return;				// Safety
+		if (pqueue->head) {
+			if (pqueue->head == pitem) {
+				pqueue->head = pitem->next;
+				pitem->next = 0;
+			} else {
+				for(pi = pqueue->head; pi->next; pi = pi->next) {
+					if (pi->next == pitem) {
+						pi->next = pitem->next;
+						if (pqueue->tail == pitem)
+							pqueue->tail = pi;
+						pitem->next = 0;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem) {
+		bool_t	res;
+
+		gfxSystemLock();
+		res = gfxQueueASyncIsInI(pqueue, pitem);
+		gfxSystemUnlock();
+
+		return res;
+	}
+	bool_t gfxQueueASyncIsInI(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem) {
+		gfxQueueASyncItem *pi;
+
+		for(pi = pqueue->head; pi; pi = pi->next) {
+			if (pi == pitem)
+				return TRUE;
+		}
+		return FALSE;
+	}
+#endif
+
+#if GQUEUE_NEED_GSYNC
+	void gfxQueueGSyncInit(gfxQueueGSync *pqueue) {
+		pqueue->head = pqueue->tail = 0;
+		gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT);
+	}
+	void gfxQueueGSyncDeinit(gfxQueueGSync *pqueue) {
+		pqueue->head = pqueue->tail = 0;
+		gfxSemDestroy(&pqueue->sem);
+	}
+
+	gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms) {
+		gfxQueueGSyncItem	*pi;
+
+		if (!gfxSemWait(&pqueue->sem, ms))
+			return 0;
+
+		gfxSystemLock();
+		pi = pqueue->head;
+		pqueue->head = pi->next;
+		pi->next = 0;
+		gfxSystemUnlock();
+
+		return pi;
+	}
+	gfxQueueGSyncItem *gfxQueueGSyncGetI(gfxQueueGSync *pqueue) {
+		gfxQueueGSyncItem	*pi;
+
+		if (!gfxSemWaitI(&pqueue->sem))
+			return 0;
+
+		pi = pqueue->head;
+		pqueue->head = pi->next;
+		pi->next = 0;
+		return pi;
+	}
+
+	void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+		gfxSystemLock();
+		gfxQueueGSyncPutI(pqueue, pitem);
+		gfxSystemUnlock();
+	}
+	void gfxQueueGSyncPutI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+		if (!pitem) return;				// Safety
+		pitem->next = 0;
+		if (!pqueue->head) {
+			pqueue->head = pqueue->tail = pitem;
+		} else {
+			pqueue->tail->next = pitem;
+			pqueue->tail = pitem;
+		}
+		gfxSemSignalI(&pqueue->sem);
+	}
+
+	void gfxQueueGSyncPush(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+		gfxSystemLock();
+		gfxQueueGSyncPushI(pqueue, pitem);
+		gfxSystemUnlock();
+	}
+	void gfxQueueGSyncPushI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+		if (!pitem) return;				// Safety
+		pitem->next = pqueue->head;
+		pqueue->head = pitem;
+		if (!pitem->next)
+			pqueue->tail = pitem;
+		gfxSemSignalI(&pqueue->sem);
+	}
+
+	void gfxQueueGSyncInsert(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem, gfxQueueASyncItem *pafter) {
+		gfxSystemLock();
+		gfxQueueGSyncInsertI(pqueue, pitem, pafter);
+		gfxSystemUnlock();
+	}
+	void gfxQueueGSyncInsertI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem, gfxQueueASyncItem *pafter) {
+		if (!pitem) return;				// Safety
+
+		if (pafter && gfxQueueGSyncIsInI(pqueue, pafter)) {
+			pitem->next = pafter->next;
+			pafter->next = pitem;
+			if (pqueue->tail == pafter)
+				pqueue->tail = pitem;
+		} else {
+			pitem->next = 0;
+			if (!pqueue->head) {
+				pqueue->head = pqueue->tail = pitem;
+			} else {
+				pqueue->tail->next = pitem;
+				pqueue->tail = pitem;
+			}
+		}
+	}
+
+	void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+		gfxSystemLock();
+		gfxQueueGSyncRemoveI(pqueue, pitem);
+		gfxSystemUnlock();
+	}
+	void gfxQueueGSyncRemoveI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+		gfxQueueGSyncItem *pi;
+
+		if (!pitem) return;				// Safety
+		if (pqueue->head) {
+			if (pqueue->head == pitem) {
+				pqueue->head = pitem->next;
+				pitem->next = 0;
+			} else {
+				for(pi = pqueue->head; pi->next; pi = pi->next) {
+					if (pi->next == pitem) {
+						pi->next = pitem->next;
+						if (pqueue->tail == pitem)
+							pqueue->tail = pi;
+						pitem->next = 0;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem) {
+		bool_t		res;
+
+		gfxSystemLock();
+		res = gfxQueueGSyncIsInI(pqueue, pitem);
+		gfxSystemUnlock();
+
+		return res;
+	}
+	bool_t gfxQueueGSyncIsInI(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem) {
+		gfxQueueGSyncItem *pi;
+
+		for(pi = pqueue->head; pi; pi = pi->next) {
+			if (pi == pitem)
+				return TRUE;
+		}
+		return FALSE;
+	}
+#endif
+
+#if GQUEUE_NEED_FSYNC
+	void gfxQueueFSyncInit(gfxQueueFSync *pqueue) {
+		pqueue->head = pqueue->tail = 0;
+		gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT);
+	}
+	void gfxQueueFSyncDeinit(gfxQueueGSync *pqueue) {
+		while(gfxQueueFSyncGet(pqueue, TIME_IMMEDIATE));
+		pqueue->head = pqueue->tail = 0;
+		gfxSemDestroy(&pqueue->sem);
+	}
+
+	gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms) {
+		gfxQueueFSyncItem	*pi;
+
+		if (!gfxSemWait(&pqueue->sem, ms))
+			return 0;
+
+		gfxSystemLock();
+		pi = pqueue->head;
+		pqueue->head = pi->next;
+		pi->next = 0;
+		gfxSystemUnlock();
+
+		gfxSemSignal(&pi->sem);
+		gfxSemDestroy(&pi->sem);
+
+		return pi;
+	}
+
+	bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms) {
+		if (!pitem) return;				// Safety
+		gfxSemInit(&pitem->sem, 0, 1);
+		pitem->next = 0;
+
+		gfxSystemLock();
+		if (!pqueue->head) {
+			pqueue->head = pqueue->tail = pitem;
+		} else {
+			pqueue->tail->next = pitem;
+			pqueue->tail = pitem;
+		}
+		gfxSystemUnlock();
+
+		gfxSemSignal(&pqueue->sem);
+
+		return gfxSemWait(&pitem->sem, ms);
+	}
+
+	bool_t gfxQueueFSyncPush(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms) {
+		if (!pitem) return;				// Safety
+		gfxSemInit(&pitem->sem, 0, 1);
+
+		gfxSystemLock();
+		pitem->next = pqueue->head;
+		pqueue->head = pitem;
+		if (!pitem->next)
+			pqueue->tail = pitem;
+		gfxSystemUnlock();
+
+		gfxSemSignal(&pqueue->sem);
+
+		return gfxSemWait(&pitem->sem, ms);
+	}
+
+	bool_t gfxQueueFSyncInsert(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, gfxQueueASyncItem *pafter, delaytime_t ms) {
+		if (!pitem) return;				// Safety
+		gfxSemInit(&pitem->sem, 0, 1);
+
+		gfxSystemLock();
+		if (pafter && gfxQueueGSyncIsInI(pqueue, pafter)) {
+			pitem->next = pafter->next;
+			pafter->next = pitem;
+			if (pqueue->tail == pafter)
+				pqueue->tail = pitem;
+		} else {
+			pitem->next = 0;
+			if (!pqueue->head) {
+				pqueue->head = pqueue->tail = pitem;
+			} else {
+				pqueue->tail->next = pitem;
+				pqueue->tail = pitem;
+			}
+		}
+		gfxSystemUnlock();
+
+		gfxSemSignal(&pqueue->sem);
+
+		return gfxSemWait(&pitem->sem, ms);
+
+	}
+
+	void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) {
+		gfxQueueFSyncItem *pi;
+
+		if (!pitem) return;				// Safety
+		gfxSystemLock();
+		if (pqueue->head) {
+			if (pqueue->head == pitem) {
+				pqueue->head = pitem->next;
+			found:
+				pitem->next = 0;
+				gfxSystemUnlock();
+				gfxSemSignal(&pitem->sem);
+				gfxSemDestroy(&pitem->sem);
+				return;
+			}
+			for(pi = pqueue->head; pi->next; pi = pi->next) {
+				if (pi->next == pitem) {
+					pi->next = pitem->next;
+					if (pqueue->tail == pitem)
+						pqueue->tail = pi;
+					goto found;
+				}
+			}
+		}
+		gfxSystemUnlock();
+	}
+
+	bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem) {
+		bool_t	res;
+
+		gfxSystemLock();
+		res = gfxQueueFSyncIsInI(pqueue, pitem);
+		gfxSystemUnlock();
+
+		return res;
+	}
+	bool_t gfxQueueFSyncIsInI(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem) {
+		gfxQueueASyncItem *pi;
+
+		for(pi = pqueue->head; pi; pi = pi->next) {
+			if (pi == pitem)
+				return TRUE;
+		}
+		return FALSE;
+	}
+#endif
+
+#if GQUEUE_NEED_BUFFERS
+	bool_t gfxBufferAlloc(unsigned num, size_t size) {
+		GDataBuffer *pd;
+
+		if (num < 1)
+			return FALSE;
+
+		// Round up to a multiple of 4 to prevent problems with structure alignment
+		size = (size + 3) & ~0x03;
+
+		// Allocate the memory
+		if (!(pd = gfxAlloc((size+sizeof(GDataBuffer)) * num)))
+			return FALSE;
+
+		// Add each of them to our free list
+		for(;num--; pd = (GDataBuffer *)((char *)(pd+1)+size)) {
+			pd->size = size;
+			gfxBufferRelease(pd);
+		}
+
+		return TRUE;
+	}
+
+	void gfxBufferRelease(GDataBuffer *pd)		{ gfxQueueGSyncPut(&bufferFreeList, (gfxQueueGSyncItem *)pd); }
+	void gfxBufferReleaseI(GDataBuffer *pd)		{ gfxQueueGSyncPutI(&bufferFreeList, (gfxQueueGSyncItem *)pd); }
+	GDataBuffer *gfxBufferGet(delaytime_t ms)	{ return (GDataBuffer *)gfxQueueGSyncGet(&bufferFreeList, ms); }
+	GDataBuffer *gfxBufferGetI(void)			{ return (GDataBuffer *)gfxQueueGSyncGetI(&bufferFreeList); }
+	bool_t gfxBufferIsAvailable(void)			{ return bufferFreeList.head != 0; }
+
+#endif
+
+
+#endif /* GFX_USE_GQUEUE */
diff --git a/src/gqueue/gqueue.h b/src/gqueue/gqueue.h
new file mode 100644
index 00000000..924024b7
--- /dev/null
+++ b/src/gqueue/gqueue.h
@@ -0,0 +1,412 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gqueue/gqueue.h
+ * @brief   GQUEUE header file.
+ *
+ * @addtogroup GQUEUE
+ *
+ * @brief	Module which provides queue management (only internally used)
+ *
+ * @details	There are 3 types of queues:
+ * 			<ul><li><b>Asynchronous Queues (ASync) </b> - Queue operations never block</li>
+ * 				<li><b>Get Synchronous Queues (GSync) </b> - Queue Get operations block until something is placed in the Queue</li>
+ * 				<li><b>Put Synchronous Queues (PSync)</b> - Queue Put operations block until the element is removed from the Queue</li>
+ * 				<li><b>Fully Synchronous Queues (FSync)</b> - Queue GET and Put operations block</li>
+ * 			</ul>
+ * 			We need 4 types of queues even though fully synchronous queues support all operations including asynchronous
+ * 			operations because fully synchronous queues have the highest storage requirements. The other queue types are
+ * 			optimizations. Efficiency IS important to use (particularly RAM efficiency).
+ * 			In practice we only implement ASync, GSync and FSync queues as PSync queues are of dubious value.
+ * 			<br>
+ * 			We also define GDataBuffer which is a data buffer that supports being queued.
+ * @{
+ */
+
+#ifndef _GQUEUE_H
+#define _GQUEUE_H
+
+#if GFX_USE_GQUEUE || defined(__DOXYGEN__)
+
+/**
+ * @brief	A queue item
+ * @{
+ */
+typedef struct gfxQueueASyncItem {
+	struct gfxQueueASyncItem	*next;
+} gfxQueueASyncItem, gfxQueueGSyncItem;
+
+typedef struct gfxQueueFSyncItem {
+	struct gfxQueueFSyncItem	*next;
+	gfxSem						sem;
+} gfxQueueFSyncItem;
+/** @} */
+
+/**
+ * @brief	A queue
+ * @{
+ */
+typedef struct gfxQueueASync {
+	gfxQueueASyncItem	*head;
+	gfxQueueASyncItem	*tail;
+} gfxQueueASync;
+
+typedef struct gfxQueueGSync {
+	gfxQueueGSyncItem	*head;
+	gfxQueueGSyncItem	*tail;
+	gfxSem				sem;
+} gfxQueueGSync;
+
+typedef struct gfxQueueFSync {
+	gfxQueueFSyncItem	*head;
+	gfxQueueFSyncItem	*tail;
+	gfxSem				sem;
+} gfxQueueFSync;
+/** @} */
+
+/**
+ * @brief	A Data Buffer Queue
+ * @note	This structure is followed immediately by the data itself.
+ * 			When allocating the buffers for the data put this structure
+ * 			at the beginning of the buffer.
+ */
+typedef struct GDataBuffer {
+	gfxQueueGSyncItem	next;		// @< Used for queueing the buffers
+	size_t				size;		// @< The size of the buffer area following this structure (in bytes)
+	size_t				len;		// @< The length of the data in the buffer area (in bytes)
+} GDataBuffer;
+
+/*===========================================================================*/
+/* Function declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name	Initialisation functions
+ * @brief	Initialise a queue.
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ *
+ * @note	Whilst queues are normally FIFO, a GFX queue also supports push and pop operations.
+ * 			A pop operation is the same as normal get from the queue but a push places the item
+ * 			at the head of the queue instead of the tail (as a put would).
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncInit(gfxQueueASync *pqueue);
+void gfxQueueGSyncInit(gfxQueueGSync *pqueue);
+void gfxQueueFSyncInit(gfxQueueFSync *pqueue);
+/** @} */
+
+/**
+ * @name	Deinitialisation functions
+ * @brief	De-Initialise a queue.
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ *
+ * @api
+ * @{
+ */
+#define gfxQueueASyncDeinit(pqueue)
+void gfxQueueGSyncDeinit(gfxQueueGSync *pqueue);
+void gfxQueueFSyncDeinit(gfxQueueFSync *pqueue);
+/** @} */
+
+/**
+ * @name	Get() Functions
+ * @brief	Get an item from the head of the queue (and remove it from the queue).
+ * @return	NULL if the timeout expires before an item is available
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ * @param[in]	ms		The maxmimum time to wait for an item. For ASync queues this parameter is
+ * 						not specified as TIME_IMMEDIATE is assumed.
+ *
+ * @note		The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+gfxQueueASyncItem *gfxQueueASyncGet(gfxQueueASync *pqueue);
+gfxQueueASyncItem *gfxQueueASyncGetI(gfxQueueASync *pqueue);
+gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms);
+gfxQueueGSyncItem *gfxQueueGSyncGetI(gfxQueueGSync *pqueue);
+gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms);
+/** @} */
+
+/**
+ * @name	Put() Functions
+ * @brief	Put an item on the end of the queue.
+ * @return	none for ASync and GSync queues; For FSync queues - FALSE on timeout, otherwise TRUE
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ * @param[in]	pitem	A pointer to the queue item
+ * @param[in]	ms		The maxmimum time to wait for an item to be removed from the queue (only for FSync queues)
+ *
+ * @note		FSync: Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
+ * 				item is removed from the queue. Note that even if the timeout occurs - the item
+ * 				remains in the queue.
+ * @note		The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueASyncPutI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+void gfxQueueGSyncPutI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms);
+/** @} */
+
+/**
+ * @name	Pop() Functions
+ * @brief	Pop an item from the head of the queue (and remove it from the queue).
+ * @details	This is exactly the same as the Get operation above.
+ *
+ * @api
+ * @{
+ */
+#define gfxQueueASyncPop(pqueue)			gfxQueueASyncGet(pqueue)
+#define gfxQueueASyncPopI(pqueue)			gfxQueueASyncGetI(pqueue)
+#define gfxQueueGSyncPop(pqueue, ms)		gfxQueueGSyncGet(pqueue, ms)
+#define gfxQueueFSyncPop(pqueue, ms)		gfxQueueFSyncGet(pqueue, ms)
+/** @} */
+
+/**
+ * @name	Push() Functions
+ * @brief	Push an item into the start of the queue.
+ * @return	none for ASync and GSync queues; For FSync queues - FALSE on timeout, otherwise TRUE
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ * @param[in]	pitem	A pointer to the queue item
+ * @param[in]	ms		The maxmimum time to wait for an item to be popped (only for FSync queues)
+ *
+ * @note		FSync: Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
+ * 				item is removed from the queue. Note that even if the timeout occurs - the item
+ * 				remains in the queue.
+ * @note		The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncPush(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueASyncPushI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueGSyncPush(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+void gfxQueueGSyncPushI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+bool_t gfxQueueFSyncPush(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms);
+/** @} */
+
+/**
+ * @name	Insert() Functions
+ * @brief	Insert an item on the queue after the specified item.
+ * @return	none for ASync and GSync queues; For FSync queues - FALSE on timeout, otherwise TRUE
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ * @param[in]	pitem	A pointer to the queue item
+ * @param[in]	pafter	A pointer to the queue item this new item must be inserted after. If NULL or
+ * 							pafter can't be found in the queue, it puts the new item at the end of the queue.
+ * @param[in]	ms		The maxmimum time to wait for an item to be removed from the queue (only for FSync queues)
+ *
+ * @note		FSync: Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
+ * 				item is removed from the queue. Note that even if the timeout occurs - the item
+ * 				remains in the queue.
+ * @note		The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncInsert(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem, gfxQueueASyncItem *pafter);
+void gfxQueueASyncInsertI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem, gfxQueueASyncItem *pafter);
+void gfxQueueGSyncInsert(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem, gfxQueueASyncItem *pafter);
+void gfxQueueGSyncInsertI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem, gfxQueueASyncItem *pafter);
+bool_t gfxQueueFSyncInsert(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, gfxQueueASyncItem *pafter, delaytime_t ms);
+/** @} */
+
+/**
+ * @name	Remove() Functions
+ * @brief	Remove an item from the queue.
+ * @note	Removes the specified item from the queue where-ever it is in the queue
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ * @param[in]	pitem	A pointer to the queue item
+ *
+ * @note	If the item isn't in the queue the routine just returns.
+ * @note	If a process is waiting on the Put/Push operation for the item, that process
+ * 			will be signaled.
+ * @note	The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueASyncRemoveI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
+void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+void gfxQueueGSyncRemoveI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
+void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem);
+/** @} */
+
+/**
+ * @name	isEmpty() Functions
+ * @brief	Is the queue empty?
+ * @return	TRUE if the queue is empty
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ *
+ * @note	The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+#define gfxQueueASyncIsEmpty(pqueue)		((pqueue)->head == 0)
+#define gfxQueueASyncIsEmptyI(pqueue)		((pqueue)->head == 0)
+#define gfxQueueGSyncIsEmpty(pqueue)		((pqueue)->head == 0)
+#define gfxQueueGSyncIsEmptyI(pqueue)		((pqueue)->head == 0)
+#define gfxQueueFSyncIsEmpty(pqueue)		((pqueue)->head == 0)
+#define gfxQueueFSyncIsEmptyI(pqueue)		((pqueue)->head == 0)
+/** @} */
+
+/**
+ * @name	IsInQueue() Functions
+ * @brief	Is an item in the queue?
+ * @return	TRUE if the item is in the queue?
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ * @param[in]	pitem	A pointer to the queue item
+ *
+ * @note	This operation may be expensive.
+ * @note	The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem);
+bool_t gfxQueueASyncIsInI(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem);
+bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem);
+bool_t gfxQueueGSyncIsInI(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem);
+bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
+bool_t gfxQueueFSyncIsInI(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
+/** @} */
+
+/**
+ * @name	Peek() Functions
+ * @brief	Get the first item from the head of the queue but do not remove it from the queue.
+ * @return	NULL if no item is available.
+ *
+ * @param[in]	pqueue	A pointer to the queue
+ *
+ * @note	This call does not block.
+ * @note	This can be used as the first call to iterate all the elements in the queue.
+ * @note	As that item is still on the queue, it should be treated as read-only. It could
+ * 			also be removed from the queue at any time by another thread (thereby altering the
+ * 			queue item).
+ * @note	The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+#define gfxQueueASyncPeek(pqueue)	((const gfxQueueASyncItem *)((pqueue)->head))
+#define gfxQueueASyncPeekI(pqueue)	((const gfxQueueASyncItem *)((pqueue)->head))
+#define gfxQueueGSyncPeek(pqueue)	((const gfxQueueGSyncItem *)((pqueue)->head))
+#define gfxQueueGSyncPeekI(pqueue)	((const gfxQueueGSyncItem *)((pqueue)->head))
+#define gfxQueueFSyncPeek(pqueue)	((const gfxQueueFSyncItem *)((pqueue)->head))
+#define gfxQueueFSyncPeekI(pqueue)	((const gfxQueueFSyncItem *)((pqueue)->head))
+/** @} */
+
+/**
+ * @name	Next() Functions
+ * @brief	Get the next item in the queue (but do not remove it from the queue).
+ * @return	NULL if no item is available.
+ *
+ * @param[in]	pitem	The previous item in the queue
+ *
+ * @note	This call does not block.
+ * @note	This can be used as subsequent calls to iterate all the elements in the queue.
+ * @note	As that item is still on the queue, it should be treated as read-only. It could
+ * 			also be removed from the queue at any time by another thread (thereby altering the
+ * 			queue item).
+ * @note	The routines ending in "I" are interrupt/system/iclass level routines.
+ *
+ * @api
+ * @{
+ */
+#define gfxQueueASyncNext(pitem)	((const gfxQueueASyncItem *)((pitem)->next))
+#define gfxQueueASyncNextI(pitem)	((const gfxQueueASyncItem *)((pitem)->next))
+#define gfxQueueGSyncNext(pitem)	((const gfxQueueGSyncItem *)((pitem)->next))
+#define gfxQueueGSyncNextI(pitem)	((const gfxQueueGSyncItem *)((pitem)->next))
+#define gfxQueueFSyncNext(pitem)	((const gfxQueueFSyncItem *)((pitem)->next))
+#define gfxQueueFSyncNextI(pitem)	((const gfxQueueFSyncItem *)((pitem)->next))
+/** @} */
+
+/**
+ * @name		BufferAlloc() Functions
+ * @brief		Allocate some buffers and put them on the free list
+ * @return		TRUE is it succeeded. FALSE on allocation failure.
+ *
+ * @param[in] num	The number of buffers to allocate
+ * @param[in] size	The size (in bytes) of each buffer
+ *
+ * @api
+ * @{
+ */
+bool_t gfxBufferAlloc(unsigned num, size_t size);
+/** @} */
+
+/**
+ * @name		BufferIsAvailable() Functions
+ * @brief		Is there one or more buffers currently available on the free list
+ * @return		TRUE if there are buffers in the free list
+ *
+ * @api
+ * @{
+ */
+bool_t gfxBufferIsAvailable(void);
+/** @} */
+
+/**
+ * @name		BufferGet() Functions
+ * @brief		Get a buffer from the free list
+ * @return		A GDataBuffer pointer or NULL if the timeout is exceeded
+ *
+ * @param[in] ms	The maximum amount of time in milliseconds to wait for a buffer if one is not available.
+ *
+ * @api
+ * @{
+ */
+GDataBuffer *gfxBufferGet(delaytime_t ms);
+GDataBuffer *gfxBufferGetI(void);
+/** @} */
+
+/**
+ * @name		BufferRelease) Functions
+ * @brief		Release a buffer back to the free list
+ *
+ * @param[in] pd		The buffer to put (back) on the free-list.
+ *
+ * @note		This call should be used to return any buffers that were taken from
+ * 				the free-list once they have been finished with. It can also be used
+ * 				to put new buffers onto the free-list. Just make sure the "size" field
+ * 				of the GDataBuffer structure has been filled in first.
+ *
+ * @api
+ * @{
+ */
+void gfxBufferRelease(GDataBuffer *pd);
+void gfxBufferReleaseI(GDataBuffer *pd);
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GQUEUE */
+#endif /* _GQUEUE_H */
+/** @} */
diff --git a/src/gqueue/gqueue.mk b/src/gqueue/gqueue.mk
new file mode 100644
index 00000000..ab8a0423
--- /dev/null
+++ b/src/gqueue/gqueue.mk
@@ -0,0 +1 @@
+GFXSRC +=   $(GFXLIB)/src/gqueue/gqueue.c
diff --git a/src/gqueue/gqueue_gqueue.c b/src/gqueue/gqueue_gqueue.c
deleted file mode 100644
index 5a50c64b..00000000
--- a/src/gqueue/gqueue_gqueue.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gqueue/gqueue_gqueue.c
- * @brief   GQUEUE source file.
- */
-
-#include "gfx.h"
-
-#if GFX_USE_GQUEUE
-
-#if GQUEUE_NEED_BUFFERS
-	static gfxQueueGSync	bufferFreeList;
-#endif
-
-void _gqueueInit(void)
-{
-	#if GQUEUE_NEED_BUFFERS
-		gfxQueueGSyncInit(&bufferFreeList);
-	#endif
-}
-
-void _gqueueDeinit(void)
-{
-}
-
-#if GQUEUE_NEED_ASYNC
-	void gfxQueueASyncInit(gfxQueueASync *pqueue) {
-		pqueue->head = pqueue->tail = 0;
-	}
-
-	gfxQueueASyncItem *gfxQueueASyncGet(gfxQueueASync *pqueue) {
-		gfxQueueASyncItem	*pi;
-
-		// This is just a shortcut to speed execution
-		if (!pqueue->head)
-			return 0;
-
-		gfxSystemLock();
-		pi = gfxQueueASyncGetI(pqueue);
-		gfxSystemUnlock();
-
-		return pi;
-	}
-	gfxQueueASyncItem *gfxQueueASyncGetI(gfxQueueASync *pqueue) {
-		gfxQueueASyncItem	*pi;
-
-		if ((pi = pqueue->head)) {
-			pqueue->head = pi->next;
-			pi->next = 0;
-		}
-
-		return pi;
-	}
-
-	void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
-		gfxSystemLock();
-		gfxQueueASyncPutI(pqueue, pitem);
-		gfxSystemUnlock();
-	}
-	void gfxQueueASyncPutI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
-		if (!pitem) return;				// Safety
-		pitem->next = 0;
-		if (!pqueue->head) {
-			pqueue->head = pqueue->tail = pitem;
-		} else {
-			pqueue->tail->next = pitem;
-			pqueue->tail = pitem;
-		}
-	}
-
-	void gfxQueueASyncPush(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
-		gfxSystemLock();
-		gfxQueueASyncPushI(pqueue, pitem);
-		gfxSystemUnlock();
-	}
-	void gfxQueueASyncPushI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
-		if (!pitem) return;				// Safety
-		pitem->next = pqueue->head;
-		pqueue->head = pitem;
-		if (!pitem->next)
-			pqueue->tail = pitem;
-	}
-
-	void gfxQueueASyncInsert(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem, gfxQueueASyncItem *pafter) {
-		gfxSystemLock();
-		gfxQueueASyncInsertI(pqueue, pitem, pafter);
-		gfxSystemUnlock();
-	}
-	void gfxQueueASyncInsertI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem, gfxQueueASyncItem *pafter) {
-		if (!pitem) return;				// Safety
-
-		if (pafter && gfxQueueASyncIsInI(pqueue, pafter)) {
-			pitem->next = pafter->next;
-			pafter->next = pitem;
-			if (pqueue->tail == pafter)
-				pqueue->tail = pitem;
-		} else {
-			pitem->next = 0;
-			if (!pqueue->head) {
-				pqueue->head = pqueue->tail = pitem;
-			} else {
-				pqueue->tail->next = pitem;
-				pqueue->tail = pitem;
-			}
-		}
-	}
-
-	void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
-		gfxSystemLock();
-		gfxQueueASyncRemoveI(pqueue, pitem);
-		gfxSystemUnlock();
-	}
-	void gfxQueueASyncRemoveI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
-		gfxQueueASyncItem *pi;
-
-		if (!pitem) return;				// Safety
-		if (pqueue->head) {
-			if (pqueue->head == pitem) {
-				pqueue->head = pitem->next;
-				pitem->next = 0;
-			} else {
-				for(pi = pqueue->head; pi->next; pi = pi->next) {
-					if (pi->next == pitem) {
-						pi->next = pitem->next;
-						if (pqueue->tail == pitem)
-							pqueue->tail = pi;
-						pitem->next = 0;
-						break;
-					}
-				}
-			}
-		}
-	}
-
-	bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem) {
-		bool_t	res;
-
-		gfxSystemLock();
-		res = gfxQueueASyncIsInI(pqueue, pitem);
-		gfxSystemUnlock();
-
-		return res;
-	}
-	bool_t gfxQueueASyncIsInI(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem) {
-		gfxQueueASyncItem *pi;
-
-		for(pi = pqueue->head; pi; pi = pi->next) {
-			if (pi == pitem)
-				return TRUE;
-		}
-		return FALSE;
-	}
-#endif
-
-#if GQUEUE_NEED_GSYNC
-	void gfxQueueGSyncInit(gfxQueueGSync *pqueue) {
-		pqueue->head = pqueue->tail = 0;
-		gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT);
-	}
-	void gfxQueueGSyncDeinit(gfxQueueGSync *pqueue) {
-		pqueue->head = pqueue->tail = 0;
-		gfxSemDestroy(&pqueue->sem);
-	}
-
-	gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms) {
-		gfxQueueGSyncItem	*pi;
-
-		if (!gfxSemWait(&pqueue->sem, ms))
-			return 0;
-
-		gfxSystemLock();
-		pi = pqueue->head;
-		pqueue->head = pi->next;
-		pi->next = 0;
-		gfxSystemUnlock();
-
-		return pi;
-	}
-	gfxQueueGSyncItem *gfxQueueGSyncGetI(gfxQueueGSync *pqueue) {
-		gfxQueueGSyncItem	*pi;
-
-		if (!gfxSemWaitI(&pqueue->sem))
-			return 0;
-
-		pi = pqueue->head;
-		pqueue->head = pi->next;
-		pi->next = 0;
-		return pi;
-	}
-
-	void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
-		gfxSystemLock();
-		gfxQueueGSyncPutI(pqueue, pitem);
-		gfxSystemUnlock();
-	}
-	void gfxQueueGSyncPutI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
-		if (!pitem) return;				// Safety
-		pitem->next = 0;
-		if (!pqueue->head) {
-			pqueue->head = pqueue->tail = pitem;
-		} else {
-			pqueue->tail->next = pitem;
-			pqueue->tail = pitem;
-		}
-		gfxSemSignalI(&pqueue->sem);
-	}
-
-	void gfxQueueGSyncPush(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
-		gfxSystemLock();
-		gfxQueueGSyncPushI(pqueue, pitem);
-		gfxSystemUnlock();
-	}
-	void gfxQueueGSyncPushI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
-		if (!pitem) return;				// Safety
-		pitem->next = pqueue->head;
-		pqueue->head = pitem;
-		if (!pitem->next)
-			pqueue->tail = pitem;
-		gfxSemSignalI(&pqueue->sem);
-	}
-
-	void gfxQueueGSyncInsert(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem, gfxQueueASyncItem *pafter) {
-		gfxSystemLock();
-		gfxQueueGSyncInsertI(pqueue, pitem, pafter);
-		gfxSystemUnlock();
-	}
-	void gfxQueueGSyncInsertI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem, gfxQueueASyncItem *pafter) {
-		if (!pitem) return;				// Safety
-
-		if (pafter && gfxQueueGSyncIsInI(pqueue, pafter)) {
-			pitem->next = pafter->next;
-			pafter->next = pitem;
-			if (pqueue->tail == pafter)
-				pqueue->tail = pitem;
-		} else {
-			pitem->next = 0;
-			if (!pqueue->head) {
-				pqueue->head = pqueue->tail = pitem;
-			} else {
-				pqueue->tail->next = pitem;
-				pqueue->tail = pitem;
-			}
-		}
-	}
-
-	void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
-		gfxSystemLock();
-		gfxQueueGSyncRemoveI(pqueue, pitem);
-		gfxSystemUnlock();
-	}
-	void gfxQueueGSyncRemoveI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
-		gfxQueueGSyncItem *pi;
-
-		if (!pitem) return;				// Safety
-		if (pqueue->head) {
-			if (pqueue->head == pitem) {
-				pqueue->head = pitem->next;
-				pitem->next = 0;
-			} else {
-				for(pi = pqueue->head; pi->next; pi = pi->next) {
-					if (pi->next == pitem) {
-						pi->next = pitem->next;
-						if (pqueue->tail == pitem)
-							pqueue->tail = pi;
-						pitem->next = 0;
-						break;
-					}
-				}
-			}
-		}
-	}
-
-	bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem) {
-		bool_t		res;
-
-		gfxSystemLock();
-		res = gfxQueueGSyncIsInI(pqueue, pitem);
-		gfxSystemUnlock();
-
-		return res;
-	}
-	bool_t gfxQueueGSyncIsInI(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem) {
-		gfxQueueGSyncItem *pi;
-
-		for(pi = pqueue->head; pi; pi = pi->next) {
-			if (pi == pitem)
-				return TRUE;
-		}
-		return FALSE;
-	}
-#endif
-
-#if GQUEUE_NEED_FSYNC
-	void gfxQueueFSyncInit(gfxQueueFSync *pqueue) {
-		pqueue->head = pqueue->tail = 0;
-		gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT);
-	}
-	void gfxQueueFSyncDeinit(gfxQueueGSync *pqueue) {
-		while(gfxQueueFSyncGet(pqueue, TIME_IMMEDIATE));
-		pqueue->head = pqueue->tail = 0;
-		gfxSemDestroy(&pqueue->sem);
-	}
-
-	gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms) {
-		gfxQueueFSyncItem	*pi;
-
-		if (!gfxSemWait(&pqueue->sem, ms))
-			return 0;
-
-		gfxSystemLock();
-		pi = pqueue->head;
-		pqueue->head = pi->next;
-		pi->next = 0;
-		gfxSystemUnlock();
-
-		gfxSemSignal(&pi->sem);
-		gfxSemDestroy(&pi->sem);
-
-		return pi;
-	}
-
-	bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms) {
-		if (!pitem) return;				// Safety
-		gfxSemInit(&pitem->sem, 0, 1);
-		pitem->next = 0;
-
-		gfxSystemLock();
-		if (!pqueue->head) {
-			pqueue->head = pqueue->tail = pitem;
-		} else {
-			pqueue->tail->next = pitem;
-			pqueue->tail = pitem;
-		}
-		gfxSystemUnlock();
-
-		gfxSemSignal(&pqueue->sem);
-
-		return gfxSemWait(&pitem->sem, ms);
-	}
-
-	bool_t gfxQueueFSyncPush(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms) {
-		if (!pitem) return;				// Safety
-		gfxSemInit(&pitem->sem, 0, 1);
-
-		gfxSystemLock();
-		pitem->next = pqueue->head;
-		pqueue->head = pitem;
-		if (!pitem->next)
-			pqueue->tail = pitem;
-		gfxSystemUnlock();
-
-		gfxSemSignal(&pqueue->sem);
-
-		return gfxSemWait(&pitem->sem, ms);
-	}
-
-	bool_t gfxQueueFSyncInsert(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, gfxQueueASyncItem *pafter, delaytime_t ms) {
-		if (!pitem) return;				// Safety
-		gfxSemInit(&pitem->sem, 0, 1);
-
-		gfxSystemLock();
-		if (pafter && gfxQueueGSyncIsInI(pqueue, pafter)) {
-			pitem->next = pafter->next;
-			pafter->next = pitem;
-			if (pqueue->tail == pafter)
-				pqueue->tail = pitem;
-		} else {
-			pitem->next = 0;
-			if (!pqueue->head) {
-				pqueue->head = pqueue->tail = pitem;
-			} else {
-				pqueue->tail->next = pitem;
-				pqueue->tail = pitem;
-			}
-		}
-		gfxSystemUnlock();
-
-		gfxSemSignal(&pqueue->sem);
-
-		return gfxSemWait(&pitem->sem, ms);
-
-	}
-
-	void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) {
-		gfxQueueFSyncItem *pi;
-
-		if (!pitem) return;				// Safety
-		gfxSystemLock();
-		if (pqueue->head) {
-			if (pqueue->head == pitem) {
-				pqueue->head = pitem->next;
-			found:
-				pitem->next = 0;
-				gfxSystemUnlock();
-				gfxSemSignal(&pitem->sem);
-				gfxSemDestroy(&pitem->sem);
-				return;
-			}
-			for(pi = pqueue->head; pi->next; pi = pi->next) {
-				if (pi->next == pitem) {
-					pi->next = pitem->next;
-					if (pqueue->tail == pitem)
-						pqueue->tail = pi;
-					goto found;
-				}
-			}
-		}
-		gfxSystemUnlock();
-	}
-
-	bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem) {
-		bool_t	res;
-
-		gfxSystemLock();
-		res = gfxQueueFSyncIsInI(pqueue, pitem);
-		gfxSystemUnlock();
-
-		return res;
-	}
-	bool_t gfxQueueFSyncIsInI(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem) {
-		gfxQueueASyncItem *pi;
-
-		for(pi = pqueue->head; pi; pi = pi->next) {
-			if (pi == pitem)
-				return TRUE;
-		}
-		return FALSE;
-	}
-#endif
-
-#if GQUEUE_NEED_BUFFERS
-	bool_t gfxBufferAlloc(unsigned num, size_t size) {
-		GDataBuffer *pd;
-
-		if (num < 1)
-			return FALSE;
-
-		// Round up to a multiple of 4 to prevent problems with structure alignment
-		size = (size + 3) & ~0x03;
-
-		// Allocate the memory
-		if (!(pd = gfxAlloc((size+sizeof(GDataBuffer)) * num)))
-			return FALSE;
-
-		// Add each of them to our free list
-		for(;num--; pd = (GDataBuffer *)((char *)(pd+1)+size)) {
-			pd->size = size;
-			gfxBufferRelease(pd);
-		}
-
-		return TRUE;
-	}
-
-	void gfxBufferRelease(GDataBuffer *pd)		{ gfxQueueGSyncPut(&bufferFreeList, (gfxQueueGSyncItem *)pd); }
-	void gfxBufferReleaseI(GDataBuffer *pd)		{ gfxQueueGSyncPutI(&bufferFreeList, (gfxQueueGSyncItem *)pd); }
-	GDataBuffer *gfxBufferGet(delaytime_t ms)	{ return (GDataBuffer *)gfxQueueGSyncGet(&bufferFreeList, ms); }
-	GDataBuffer *gfxBufferGetI(void)			{ return (GDataBuffer *)gfxQueueGSyncGetI(&bufferFreeList); }
-	bool_t gfxBufferIsAvailable(void)			{ return bufferFreeList.head != 0; }
-
-#endif
-
-
-#endif /* GFX_USE_GQUEUE */
diff --git a/src/gqueue/gqueue_options.h b/src/gqueue/gqueue_options.h
new file mode 100644
index 00000000..a9f7302f
--- /dev/null
+++ b/src/gqueue/gqueue_options.h
@@ -0,0 +1,59 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gqueue/gqueue_options.h
+ * @brief   GQUEUE - Queue options header file.
+ *
+ * @addtogroup GQUEUE
+ * @{
+ */
+
+#ifndef _GQUEUE_OPTIONS_H
+#define _GQUEUE_OPTIONS_H
+
+/**
+ * @name    GQUEUE Functions to include.
+ * @{
+ */
+	/**
+	 * @brief   Enable Asynchronous Queues
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GQUEUE_NEED_ASYNC
+		#define GQUEUE_NEED_ASYNC		FALSE
+	#endif
+	/**
+	 * @brief   Enable Get-Synchronous Queues
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GQUEUE_NEED_GSYNC
+		#define GQUEUE_NEED_GSYNC		FALSE
+	#endif
+	/**
+	 * @brief   Enable Fully Synchronous Queues
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GQUEUE_NEED_FSYNC
+		#define GQUEUE_NEED_FSYNC		FALSE
+	#endif
+	/**
+	 * @brief	Enable Queue-able Data Buffers
+	 */
+	#ifndef GQUEUE_NEED_BUFFERS
+		#define GQUEUE_NEED_BUFFERS		FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GQUEUE Optional Sizing Parameters
+ * @{
+ */
+/** @} */
+
+#endif /* _GQUEUE_OPTIONS_H */
+/** @} */
diff --git a/src/gqueue/gqueue_rules.h b/src/gqueue/gqueue_rules.h
new file mode 100644
index 00000000..0bccb196
--- /dev/null
+++ b/src/gqueue/gqueue_rules.h
@@ -0,0 +1,30 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gqueue/gqueue_rules.h
+ * @brief   GQUEUE safety rules header file.
+ *
+ * @addtogroup GQUEUE
+ * @{
+ */
+
+#ifndef _GQUEUE_RULES_H
+#define _GQUEUE_RULES_H
+
+#if GFX_USE_GQUEUE
+	#if GQUEUE_NEED_BUFFERS && !GQUEUE_NEED_GSYNC
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GQUEUE: GQUEUE_NEED_GSYNC is required if GQUEUE_NEED_BUFFERS is TRUE. It has been turned on for you."
+		#endif
+		#undef GQUEUE_NEED_GSYNC
+		#define	GQUEUE_NEED_GSYNC		TRUE
+	#endif
+#endif
+
+#endif /* _GQUEUE_RULES_H */
+/** @} */
diff --git a/src/gqueue/sys_defs.h b/src/gqueue/sys_defs.h
deleted file mode 100644
index cba22588..00000000
--- a/src/gqueue/sys_defs.h
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gqueue/sys_defs.h
- * @brief   GQUEUE header file.
- *
- * @addtogroup GQUEUE
- *
- * @brief	Module which provides queue management (only internally used)
- *
- * @details	There are 3 types of queues:
- * 			<ul><li><b>Asynchronous Queues (ASync) </b> - Queue operations never block</li>
- * 				<li><b>Get Synchronous Queues (GSync) </b> - Queue Get operations block until something is placed in the Queue</li>
- * 				<li><b>Put Synchronous Queues (PSync)</b> - Queue Put operations block until the element is removed from the Queue</li>
- * 				<li><b>Fully Synchronous Queues (FSync)</b> - Queue GET and Put operations block</li>
- * 			</ul>
- * 			We need 4 types of queues even though fully synchronous queues support all operations including asynchronous
- * 			operations because fully synchronous queues have the highest storage requirements. The other queue types are
- * 			optimizations. Efficiency IS important to use (particularly RAM efficiency).
- * 			In practice we only implement ASync, GSync and FSync queues as PSync queues are of dubious value.
- * 			<br>
- * 			We also define GDataBuffer which is a data buffer that supports being queued.
- * @{
- */
-
-#ifndef _GQUEUE_H
-#define _GQUEUE_H
-
-#if GFX_USE_GQUEUE || defined(__DOXYGEN__)
-
-/**
- * @brief	A queue item
- * @{
- */
-typedef struct gfxQueueASyncItem {
-	struct gfxQueueASyncItem	*next;
-} gfxQueueASyncItem, gfxQueueGSyncItem;
-
-typedef struct gfxQueueFSyncItem {
-	struct gfxQueueFSyncItem	*next;
-	gfxSem						sem;
-} gfxQueueFSyncItem;
-/** @} */
-
-/**
- * @brief	A queue
- * @{
- */
-typedef struct gfxQueueASync {
-	gfxQueueASyncItem	*head;
-	gfxQueueASyncItem	*tail;
-} gfxQueueASync;
-
-typedef struct gfxQueueGSync {
-	gfxQueueGSyncItem	*head;
-	gfxQueueGSyncItem	*tail;
-	gfxSem				sem;
-} gfxQueueGSync;
-
-typedef struct gfxQueueFSync {
-	gfxQueueFSyncItem	*head;
-	gfxQueueFSyncItem	*tail;
-	gfxSem				sem;
-} gfxQueueFSync;
-/** @} */
-
-/**
- * @brief	A Data Buffer Queue
- * @note	This structure is followed immediately by the data itself.
- * 			When allocating the buffers for the data put this structure
- * 			at the beginning of the buffer.
- */
-typedef struct GDataBuffer {
-	gfxQueueGSyncItem	next;		// @< Used for queueing the buffers
-	size_t				size;		// @< The size of the buffer area following this structure (in bytes)
-	size_t				len;		// @< The length of the data in the buffer area (in bytes)
-} GDataBuffer;
-
-/*===========================================================================*/
-/* Function declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @name	Initialisation functions
- * @brief	Initialise a queue.
- *
- * @param[in]	pqueue	A pointer to the queue
- *
- * @note	Whilst queues are normally FIFO, a GFX queue also supports push and pop operations.
- * 			A pop operation is the same as normal get from the queue but a push places the item
- * 			at the head of the queue instead of the tail (as a put would).
- *
- * @api
- * @{
- */
-void gfxQueueASyncInit(gfxQueueASync *pqueue);
-void gfxQueueGSyncInit(gfxQueueGSync *pqueue);
-void gfxQueueFSyncInit(gfxQueueFSync *pqueue);
-/** @} */
-
-/**
- * @name	Deinitialisation functions
- * @brief	De-Initialise a queue.
- *
- * @param[in]	pqueue	A pointer to the queue
- *
- * @api
- * @{
- */
-#define gfxQueueASyncDeinit(pqueue)
-void gfxQueueGSyncDeinit(gfxQueueGSync *pqueue);
-void gfxQueueFSyncDeinit(gfxQueueFSync *pqueue);
-/** @} */
-
-/**
- * @name	Get() Functions
- * @brief	Get an item from the head of the queue (and remove it from the queue).
- * @return	NULL if the timeout expires before an item is available
- *
- * @param[in]	pqueue	A pointer to the queue
- * @param[in]	ms		The maxmimum time to wait for an item. For ASync queues this parameter is
- * 						not specified as TIME_IMMEDIATE is assumed.
- *
- * @note		The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-gfxQueueASyncItem *gfxQueueASyncGet(gfxQueueASync *pqueue);
-gfxQueueASyncItem *gfxQueueASyncGetI(gfxQueueASync *pqueue);
-gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms);
-gfxQueueGSyncItem *gfxQueueGSyncGetI(gfxQueueGSync *pqueue);
-gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms);
-/** @} */
-
-/**
- * @name	Put() Functions
- * @brief	Put an item on the end of the queue.
- * @return	none for ASync and GSync queues; For FSync queues - FALSE on timeout, otherwise TRUE
- *
- * @param[in]	pqueue	A pointer to the queue
- * @param[in]	pitem	A pointer to the queue item
- * @param[in]	ms		The maxmimum time to wait for an item to be removed from the queue (only for FSync queues)
- *
- * @note		FSync: Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
- * 				item is removed from the queue. Note that even if the timeout occurs - the item
- * 				remains in the queue.
- * @note		The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
-void gfxQueueASyncPutI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
-void gfxQueueGSyncPut(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
-void gfxQueueGSyncPutI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
-bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms);
-/** @} */
-
-/**
- * @name	Pop() Functions
- * @brief	Pop an item from the head of the queue (and remove it from the queue).
- * @details	This is exactly the same as the Get operation above.
- *
- * @api
- * @{
- */
-#define gfxQueueASyncPop(pqueue)			gfxQueueASyncGet(pqueue)
-#define gfxQueueASyncPopI(pqueue)			gfxQueueASyncGetI(pqueue)
-#define gfxQueueGSyncPop(pqueue, ms)		gfxQueueGSyncGet(pqueue, ms)
-#define gfxQueueFSyncPop(pqueue, ms)		gfxQueueFSyncGet(pqueue, ms)
-/** @} */
-
-/**
- * @name	Push() Functions
- * @brief	Push an item into the start of the queue.
- * @return	none for ASync and GSync queues; For FSync queues - FALSE on timeout, otherwise TRUE
- *
- * @param[in]	pqueue	A pointer to the queue
- * @param[in]	pitem	A pointer to the queue item
- * @param[in]	ms		The maxmimum time to wait for an item to be popped (only for FSync queues)
- *
- * @note		FSync: Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
- * 				item is removed from the queue. Note that even if the timeout occurs - the item
- * 				remains in the queue.
- * @note		The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-void gfxQueueASyncPush(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
-void gfxQueueASyncPushI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
-void gfxQueueGSyncPush(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
-void gfxQueueGSyncPushI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
-bool_t gfxQueueFSyncPush(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delaytime_t ms);
-/** @} */
-
-/**
- * @name	Insert() Functions
- * @brief	Insert an item on the queue after the specified item.
- * @return	none for ASync and GSync queues; For FSync queues - FALSE on timeout, otherwise TRUE
- *
- * @param[in]	pqueue	A pointer to the queue
- * @param[in]	pitem	A pointer to the queue item
- * @param[in]	pafter	A pointer to the queue item this new item must be inserted after. If NULL or
- * 							pafter can't be found in the queue, it puts the new item at the end of the queue.
- * @param[in]	ms		The maxmimum time to wait for an item to be removed from the queue (only for FSync queues)
- *
- * @note		FSync: Use a delay time of TIME_IMMEDIATE if you don't want to wait until the
- * 				item is removed from the queue. Note that even if the timeout occurs - the item
- * 				remains in the queue.
- * @note		The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-void gfxQueueASyncInsert(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem, gfxQueueASyncItem *pafter);
-void gfxQueueASyncInsertI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem, gfxQueueASyncItem *pafter);
-void gfxQueueGSyncInsert(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem, gfxQueueASyncItem *pafter);
-void gfxQueueGSyncInsertI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem, gfxQueueASyncItem *pafter);
-bool_t gfxQueueFSyncInsert(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, gfxQueueASyncItem *pafter, delaytime_t ms);
-/** @} */
-
-/**
- * @name	Remove() Functions
- * @brief	Remove an item from the queue.
- * @note	Removes the specified item from the queue where-ever it is in the queue
- *
- * @param[in]	pqueue	A pointer to the queue
- * @param[in]	pitem	A pointer to the queue item
- *
- * @note	If the item isn't in the queue the routine just returns.
- * @note	If a process is waiting on the Put/Push operation for the item, that process
- * 			will be signaled.
- * @note	The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
-void gfxQueueASyncRemoveI(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
-void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
-void gfxQueueGSyncRemoveI(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
-void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem);
-/** @} */
-
-/**
- * @name	isEmpty() Functions
- * @brief	Is the queue empty?
- * @return	TRUE if the queue is empty
- *
- * @param[in]	pqueue	A pointer to the queue
- *
- * @note	The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-#define gfxQueueASyncIsEmpty(pqueue)		((pqueue)->head == 0)
-#define gfxQueueASyncIsEmptyI(pqueue)		((pqueue)->head == 0)
-#define gfxQueueGSyncIsEmpty(pqueue)		((pqueue)->head == 0)
-#define gfxQueueGSyncIsEmptyI(pqueue)		((pqueue)->head == 0)
-#define gfxQueueFSyncIsEmpty(pqueue)		((pqueue)->head == 0)
-#define gfxQueueFSyncIsEmptyI(pqueue)		((pqueue)->head == 0)
-/** @} */
-
-/**
- * @name	IsInQueue() Functions
- * @brief	Is an item in the queue?
- * @return	TRUE if the item is in the queue?
- *
- * @param[in]	pqueue	A pointer to the queue
- * @param[in]	pitem	A pointer to the queue item
- *
- * @note	This operation may be expensive.
- * @note	The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem);
-bool_t gfxQueueASyncIsInI(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem);
-bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem);
-bool_t gfxQueueGSyncIsInI(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem);
-bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
-bool_t gfxQueueFSyncIsInI(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
-/** @} */
-
-/**
- * @name	Peek() Functions
- * @brief	Get the first item from the head of the queue but do not remove it from the queue.
- * @return	NULL if no item is available.
- *
- * @param[in]	pqueue	A pointer to the queue
- *
- * @note	This call does not block.
- * @note	This can be used as the first call to iterate all the elements in the queue.
- * @note	As that item is still on the queue, it should be treated as read-only. It could
- * 			also be removed from the queue at any time by another thread (thereby altering the
- * 			queue item).
- * @note	The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-#define gfxQueueASyncPeek(pqueue)	((const gfxQueueASyncItem *)((pqueue)->head))
-#define gfxQueueASyncPeekI(pqueue)	((const gfxQueueASyncItem *)((pqueue)->head))
-#define gfxQueueGSyncPeek(pqueue)	((const gfxQueueGSyncItem *)((pqueue)->head))
-#define gfxQueueGSyncPeekI(pqueue)	((const gfxQueueGSyncItem *)((pqueue)->head))
-#define gfxQueueFSyncPeek(pqueue)	((const gfxQueueFSyncItem *)((pqueue)->head))
-#define gfxQueueFSyncPeekI(pqueue)	((const gfxQueueFSyncItem *)((pqueue)->head))
-/** @} */
-
-/**
- * @name	Next() Functions
- * @brief	Get the next item in the queue (but do not remove it from the queue).
- * @return	NULL if no item is available.
- *
- * @param[in]	pitem	The previous item in the queue
- *
- * @note	This call does not block.
- * @note	This can be used as subsequent calls to iterate all the elements in the queue.
- * @note	As that item is still on the queue, it should be treated as read-only. It could
- * 			also be removed from the queue at any time by another thread (thereby altering the
- * 			queue item).
- * @note	The routines ending in "I" are interrupt/system/iclass level routines.
- *
- * @api
- * @{
- */
-#define gfxQueueASyncNext(pitem)	((const gfxQueueASyncItem *)((pitem)->next))
-#define gfxQueueASyncNextI(pitem)	((const gfxQueueASyncItem *)((pitem)->next))
-#define gfxQueueGSyncNext(pitem)	((const gfxQueueGSyncItem *)((pitem)->next))
-#define gfxQueueGSyncNextI(pitem)	((const gfxQueueGSyncItem *)((pitem)->next))
-#define gfxQueueFSyncNext(pitem)	((const gfxQueueFSyncItem *)((pitem)->next))
-#define gfxQueueFSyncNextI(pitem)	((const gfxQueueFSyncItem *)((pitem)->next))
-/** @} */
-
-/**
- * @name		BufferAlloc() Functions
- * @brief		Allocate some buffers and put them on the free list
- * @return		TRUE is it succeeded. FALSE on allocation failure.
- *
- * @param[in] num	The number of buffers to allocate
- * @param[in] size	The size (in bytes) of each buffer
- *
- * @api
- * @{
- */
-bool_t gfxBufferAlloc(unsigned num, size_t size);
-/** @} */
-
-/**
- * @name		BufferIsAvailable() Functions
- * @brief		Is there one or more buffers currently available on the free list
- * @return		TRUE if there are buffers in the free list
- *
- * @api
- * @{
- */
-bool_t gfxBufferIsAvailable(void);
-/** @} */
-
-/**
- * @name		BufferGet() Functions
- * @brief		Get a buffer from the free list
- * @return		A GDataBuffer pointer or NULL if the timeout is exceeded
- *
- * @param[in] ms	The maximum amount of time in milliseconds to wait for a buffer if one is not available.
- *
- * @api
- * @{
- */
-GDataBuffer *gfxBufferGet(delaytime_t ms);
-GDataBuffer *gfxBufferGetI(void);
-/** @} */
-
-/**
- * @name		BufferRelease) Functions
- * @brief		Release a buffer back to the free list
- *
- * @param[in] pd		The buffer to put (back) on the free-list.
- *
- * @note		This call should be used to return any buffers that were taken from
- * 				the free-list once they have been finished with. It can also be used
- * 				to put new buffers onto the free-list. Just make sure the "size" field
- * 				of the GDataBuffer structure has been filled in first.
- *
- * @api
- * @{
- */
-void gfxBufferRelease(GDataBuffer *pd);
-void gfxBufferReleaseI(GDataBuffer *pd);
-/** @} */
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GQUEUE */
-#endif /* _GQUEUE_H */
-/** @} */
diff --git a/src/gqueue/sys_make.mk b/src/gqueue/sys_make.mk
deleted file mode 100644
index f8a542c3..00000000
--- a/src/gqueue/sys_make.mk
+++ /dev/null
@@ -1 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gqueue/gqueue_gqueue.c
diff --git a/src/gqueue/sys_options.h b/src/gqueue/sys_options.h
deleted file mode 100644
index 169cf116..00000000
--- a/src/gqueue/sys_options.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gqueue/sys_options.h
- * @brief   GQUEUE - Queue options header file.
- *
- * @addtogroup GQUEUE
- * @{
- */
-
-#ifndef _GQUEUE_OPTIONS_H
-#define _GQUEUE_OPTIONS_H
-
-/**
- * @name    GQUEUE Functions to include.
- * @{
- */
-	/**
-	 * @brief   Enable Asynchronous Queues
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GQUEUE_NEED_ASYNC
-		#define GQUEUE_NEED_ASYNC		FALSE
-	#endif
-	/**
-	 * @brief   Enable Get-Synchronous Queues
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GQUEUE_NEED_GSYNC
-		#define GQUEUE_NEED_GSYNC		FALSE
-	#endif
-	/**
-	 * @brief   Enable Fully Synchronous Queues
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GQUEUE_NEED_FSYNC
-		#define GQUEUE_NEED_FSYNC		FALSE
-	#endif
-	/**
-	 * @brief	Enable Queue-able Data Buffers
-	 */
-	#ifndef GQUEUE_NEED_BUFFERS
-		#define GQUEUE_NEED_BUFFERS		FALSE
-	#endif
-/**
- * @}
- *
- * @name    GQUEUE Optional Sizing Parameters
- * @{
- */
-/** @} */
-
-#endif /* _GQUEUE_OPTIONS_H */
-/** @} */
diff --git a/src/gqueue/sys_rules.h b/src/gqueue/sys_rules.h
deleted file mode 100644
index 831952d8..00000000
--- a/src/gqueue/sys_rules.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gqueue/sys_rules.h
- * @brief   GQUEUE safety rules header file.
- *
- * @addtogroup GQUEUE
- * @{
- */
-
-#ifndef _GQUEUE_RULES_H
-#define _GQUEUE_RULES_H
-
-#if GFX_USE_GQUEUE
-	#if GQUEUE_NEED_BUFFERS && !GQUEUE_NEED_GSYNC
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GQUEUE: GQUEUE_NEED_GSYNC is required if GQUEUE_NEED_BUFFERS is TRUE. It has been turned on for you."
-		#endif
-		#undef GQUEUE_NEED_GSYNC
-		#define	GQUEUE_NEED_GSYNC		TRUE
-	#endif
-#endif
-
-#endif /* _GQUEUE_RULES_H */
-/** @} */
diff --git a/src/gtimer/gtimer.c b/src/gtimer/gtimer.c
new file mode 100644
index 00000000..f84cad22
--- /dev/null
+++ b/src/gtimer/gtimer.c
@@ -0,0 +1,229 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GTIMER || defined(__DOXYGEN__)
+
+#define GTIMER_FLG_PERIODIC		0x0001
+#define GTIMER_FLG_INFINITE		0x0002
+#define GTIMER_FLG_JABBED		0x0004
+#define GTIMER_FLG_SCHEDULED	0x0008
+
+/* Don't rework this macro to use a ternary operator - the gcc compiler stuffs it up */
+#define TimeIsWithin(x, start, end)	((end >= start && x >= start && x <= end) || (end < start && (x >= start || x <= end)))
+
+/* This mutex protects access to our tables */
+static gfxMutex			mutex;
+static gfxThreadHandle	hThread = 0;
+static GTimer			*pTimerHead = 0;
+static gfxSem			waitsem;
+static DECLARE_THREAD_STACK(waTimerThread, GTIMER_THREAD_WORKAREA_SIZE);
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+static DECLARE_THREAD_FUNCTION(GTimerThreadHandler, arg) {
+	(void)arg;
+	GTimer			*pt;
+	systemticks_t	tm;
+	systemticks_t	nxtTimeout;
+	systemticks_t	lastTime;
+	GTimerFunction	fn;
+	void			*param;
+
+	nxtTimeout = TIME_INFINITE;
+	lastTime = 0;
+	while(1) {
+		/* Wait for work to do. */
+		gfxYield();					// Give someone else a go no matter how busy we are
+		gfxSemWait(&waitsem, nxtTimeout);
+		
+	restartTimerChecks:
+	
+		// Our reference time
+		tm = gfxSystemTicks();
+		nxtTimeout = TIME_INFINITE;
+		
+		/* We need to obtain the mutex */
+		gfxMutexEnter(&mutex);
+
+		if (pTimerHead) {
+			pt = pTimerHead;
+			do {
+				// Do we have something to do for this timer?
+				if ((pt->flags & GTIMER_FLG_JABBED) || (!(pt->flags & GTIMER_FLG_INFINITE) && TimeIsWithin(pt->when, lastTime, tm))) {
+				
+					// Is this timer periodic?
+					if ((pt->flags & GTIMER_FLG_PERIODIC) && pt->period != TIME_IMMEDIATE) {
+						// Yes - Update ready for the next period
+						if (!(pt->flags & GTIMER_FLG_INFINITE)) {
+							// We may have skipped a period.
+							// We use this complicated formulae rather than a loop
+							//	because the gcc compiler stuffs up the loop so that it
+							//	either loops forever or doesn't get executed at all.
+							pt->when += ((tm + pt->period - pt->when) / pt->period) * pt->period;
+						}
+
+						// We are definitely no longer jabbed
+						pt->flags &= ~GTIMER_FLG_JABBED;
+						
+					} else {
+						// No - get us off the timers list
+						if (pt->next == pt->prev)
+							pTimerHead = 0;
+						else {
+							pt->next->prev = pt->prev;
+							pt->prev->next = pt->next;
+							if (pTimerHead == pt)
+								pTimerHead = pt->next;
+						}
+						pt->flags = 0;
+					}
+					
+					// Call the callback function
+					fn = pt->fn;
+					param = pt->param;
+					gfxMutexExit(&mutex);
+					fn(param);
+					
+					// We no longer hold the mutex, the callback function may have taken a while
+					// and our list may have been altered so start again!
+					goto restartTimerChecks;
+				}
+				
+				// Find when we next need to wake up
+				if (!(pt->flags & GTIMER_FLG_INFINITE) && pt->when - tm < nxtTimeout)
+					nxtTimeout = pt->when - tm;
+				pt = pt->next;
+			} while(pt != pTimerHead);
+		}
+
+		// Ready for the next loop
+		lastTime = tm;
+		gfxMutexExit(&mutex);
+	}
+	return 0;
+}
+
+void _gtimerInit(void)
+{
+	gfxSemInit(&waitsem, 0, 1);
+	gfxMutexInit(&mutex);
+}
+
+void _gtimerDeinit(void)
+{
+	gfxSemDestroy(&waitsem);
+	gfxMutexDestroy(&mutex);
+	// Need to destroy GTimer thread here
+}
+
+void gtimerInit(GTimer* pt)
+{
+	pt->flags = 0;
+}
+
+void gtimerDeinit(GTimer* pt)
+{
+	gtimerStop(pt);
+}
+
+void gtimerStart(GTimer *pt, GTimerFunction fn, void *param, bool_t periodic, delaytime_t millisec) {
+	gfxMutexEnter(&mutex);
+	
+	// Start our thread if not already going
+	if (!hThread) {
+		hThread = gfxThreadCreate(waTimerThread, sizeof(waTimerThread), GTIMER_THREAD_PRIORITY, GTimerThreadHandler, 0);
+		if (hThread) {gfxThreadClose(hThread);}		// We never really need the handle again
+	}
+
+	// Is this already scheduled?
+	if (pt->flags & GTIMER_FLG_SCHEDULED) {
+		// Cancel it!
+		if (pt->next == pt->prev)
+			pTimerHead = 0;
+		else {
+			pt->next->prev = pt->prev;
+			pt->prev->next = pt->next;
+			if (pTimerHead == pt)
+				pTimerHead = pt->next;
+		}
+	}
+	
+	// Set up the timer structure
+	pt->fn = fn;
+	pt->param = param;
+	pt->flags = GTIMER_FLG_SCHEDULED;
+	if (periodic)
+		pt->flags |= GTIMER_FLG_PERIODIC;
+	if (millisec == TIME_INFINITE) {
+		pt->flags |= GTIMER_FLG_INFINITE;
+		pt->period = TIME_INFINITE;
+	} else {
+		pt->period = gfxMillisecondsToTicks(millisec);
+		pt->when = gfxSystemTicks() + pt->period;
+	}
+
+	// Just pop it on the end of the queue
+	if (pTimerHead) {
+		pt->next = pTimerHead;
+		pt->prev = pTimerHead->prev;
+		pt->prev->next = pt;
+		pt->next->prev = pt;
+	} else
+		pt->next = pt->prev = pTimerHead = pt;
+
+	// Bump the thread
+	if (!(pt->flags & GTIMER_FLG_INFINITE))
+		gfxSemSignal(&waitsem);
+	gfxMutexExit(&mutex);
+}
+
+void gtimerStop(GTimer *pt) {
+	gfxMutexEnter(&mutex);
+	if (pt->flags & GTIMER_FLG_SCHEDULED) {
+		// Cancel it!
+		if (pt->next == pt)
+			pTimerHead = 0;
+		else {
+			pt->next->prev = pt->prev;
+			pt->prev->next = pt->next;
+			if (pTimerHead == pt)
+				pTimerHead = pt->next;
+		}
+		// Make sure we know the structure is dead!
+		pt->flags = 0;
+	}
+	gfxMutexExit(&mutex);
+}
+
+bool_t gtimerIsActive(GTimer *pt) {
+	return (pt->flags & GTIMER_FLG_SCHEDULED) ? TRUE : FALSE;
+}
+
+void gtimerJab(GTimer *pt) {
+	gfxMutexEnter(&mutex);
+	
+	// Jab it!
+	pt->flags |= GTIMER_FLG_JABBED;
+
+	// Bump the thread
+	gfxSemSignal(&waitsem);
+	gfxMutexExit(&mutex);
+}
+
+void gtimerJabI(GTimer *pt) {
+	// Jab it!
+	pt->flags |= GTIMER_FLG_JABBED;
+
+	// Bump the thread
+	gfxSemSignalI(&waitsem);
+}
+
+#endif /* GFX_USE_GTIMER */
diff --git a/src/gtimer/gtimer.h b/src/gtimer/gtimer.h
new file mode 100644
index 00000000..6803ac66
--- /dev/null
+++ b/src/gtimer/gtimer.h
@@ -0,0 +1,180 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gtimer/gtimer.h
+ *
+ * @addtogroup GTIMER
+ *
+ * @brief	Module which provides software based timers for user-space applications
+ *
+ * @details	The reason why ChibiOS/GFX has it's own timer abstraction is because
+ *			virtual timers provided by ChibiOS/RT are interrupt context only.
+ *			While great for what they are designed for, they make coding of the input
+ *			drivers much more complex.
+ *			For non-performance critical drivers like these input drivers,  it would also
+ *			hog an in-ordinate amount of critical (interrupt locked) system time.
+ *			This contrary to the goals of a real-time operating system. So a user-land
+ *			(thread based) timer mechanism is also required.
+ *
+ * @pre		GFX_USE_GTIMER must be set to TRUE in your gfxconf.h
+ *
+ * @{
+ */
+
+#ifndef _GTIMER_H
+#define _GTIMER_H
+
+#include "gfx.h"
+
+#if GFX_USE_GTIMER || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Type definitions                                                          */
+/*===========================================================================*/
+
+/* Data part of a static GTimer initialiser */
+#define _GTIMER_DATA() {0,0,0,0,0,0,0}
+
+/* Static GTimer initialiser */
+#define GTIMER_DECL(name) GTimer name = _GTIMER_DATA()
+
+/* A callback function (executed in a thread context) */
+typedef void (*GTimerFunction)(void *param);
+
+/**
+ * @brief	 A GTimer structure
+ */
+typedef struct GTimer_t {
+	GTimerFunction		fn;
+	void				*param;
+	systemticks_t		when;
+	systemticks_t		period;
+	uint16_t			flags;
+	struct GTimer_t		*next;
+	struct GTimer_t		*prev;
+} GTimer;
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Initialise a timer
+ *
+ * @param[in] pt 	Pointer to a GTimer structure
+ *
+ * @api
+ */
+void gtimerInit(GTimer* pt);
+
+/**
+ * @brief	Deinitialise a timer
+ *
+ * @param[in] pt	Pointer to a GTimer structure
+ *
+ * @api
+ */
+void gtimerDeinit(GTimer* pt);
+
+/**
+ * @brief   Set a timer going or alter its properties if it is already going.
+ *
+ * @param[in] pt	Pointer to a GTimer structure
+ * @param[in] fn		The callback function
+ * @param[in] param		The parameter to pass to the callback function
+ * @param[in] periodic	Is the timer a periodic timer? FALSE is a once-only timer.
+ * @param[in] millisec	The timer period. The following special values are allowed:
+ *							TIME_IMMEDIATE	causes the callback function to be called asap.
+ *											A periodic timer with this value will fire once only.
+ *							TIME_INFINITE	never timeout (unless triggered by gtimerJab or gtimerJabI)
+ *
+ * @note				If the timer is already active its properties are updated with the new parameters.
+ *						The current period will be immediately canceled (without the callback function being
+ *						called) and the timer will be restart with the new timer properties.
+ * @note				The callback function should be careful not to over-run the thread stack.
+ *						Define a new value for the macro GTIME_THREAD_STACK_SIZE if you want to
+ *						change the default size.
+ * @note				The callback function should return as quickly as possible as all
+ *						timer callbacks are performed by a single thread. If a callback function
+ *						takes too long it could affect the timer response for other timers.
+ * @note				A timer callback function is not a replacement for a dedicated thread if the
+ *						function wants to perform computationally expensive stuff.
+ * @note				As the callback function is called on GTIMER's thread, the function must make sure it uses
+ *						appropriate synchronisation controls such as semaphores or mutexes around any data
+ *						structures it shares with other threads such as the main application thread.
+ *
+ * @api
+ */
+void gtimerStart(GTimer *pt, GTimerFunction fn, void *param, bool_t periodic, delaytime_t millisec);
+
+/**
+ * @brief   Stop a timer (periodic or otherwise)
+ *
+ * @param[in] pt		Pointer to a GTimer structure
+ *
+ * @note				If the timer is not active this does nothing.
+ *
+ * @api
+ */
+void gtimerStop(GTimer *pt);
+
+/**
+ * @brief   Test if a timer is currently active
+ *
+ * @param[in] pt		Pointer to a GTimer structure
+ *
+ * @return	TRUE if active, FALSE otherwise
+ *
+ * @api
+ */
+bool_t gtimerIsActive(GTimer *pt);
+
+/**
+ * @brief   			Jab a timer causing the current period to immediate expire
+ * @details				The callback function will be called as soon as possible.
+ *
+ * @pre					Use from a normal thread context.
+ *
+ * @param[in] pt		Pointer to a GTimer structure
+ *
+ * @note				If the timer is not active this does nothing.
+ * @note				Repeated Jabs before the callback function actually happens are ignored.
+ *
+ * @api
+ */
+void gtimerJab(GTimer *pt);
+
+/**
+ * @brief   			Jab a timer causing the current period to immediate expire
+ * @details				The callback function will be called as soon as possible.
+ *
+ * @pre					Use from an interrupt routine context.
+ *
+ * @param[in] pt		Pointer to a GTimer structure
+ *
+ * @note				If the timer is not active this does nothing.
+ * @note				Repeated Jabs before the callback function actually happens are ignored.
+ *
+ * @iclass
+ * @api
+ */
+void gtimerJabI(GTimer *pt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_USE_GTIMER */
+
+#endif /* _GTIMER_H */
+/** @} */
+
diff --git a/src/gtimer/gtimer.mk b/src/gtimer/gtimer.mk
new file mode 100644
index 00000000..801c31a6
--- /dev/null
+++ b/src/gtimer/gtimer.mk
@@ -0,0 +1 @@
+GFXSRC +=   $(GFXLIB)/src/gtimer/gtimer.c
diff --git a/src/gtimer/gtimer_gtimer.c b/src/gtimer/gtimer_gtimer.c
deleted file mode 100644
index 38dceca5..00000000
--- a/src/gtimer/gtimer_gtimer.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gtimer/gtimer_gtimer.c
- * @brief   GTIMER sub-system code.
- *
- * @addtogroup GTIMER
- * @{
- */
-#include "gfx.h"
-
-#if GFX_USE_GTIMER || defined(__DOXYGEN__)
-
-#define GTIMER_FLG_PERIODIC		0x0001
-#define GTIMER_FLG_INFINITE		0x0002
-#define GTIMER_FLG_JABBED		0x0004
-#define GTIMER_FLG_SCHEDULED	0x0008
-
-/* Don't rework this macro to use a ternary operator - the gcc compiler stuffs it up */
-#define TimeIsWithin(x, start, end)	((end >= start && x >= start && x <= end) || (end < start && (x >= start || x <= end)))
-
-/* This mutex protects access to our tables */
-static gfxMutex			mutex;
-static gfxThreadHandle	hThread = 0;
-static GTimer			*pTimerHead = 0;
-static gfxSem			waitsem;
-static DECLARE_THREAD_STACK(waTimerThread, GTIMER_THREAD_WORKAREA_SIZE);
-
-/*===========================================================================*/
-/* Driver local functions.                                                   */
-/*===========================================================================*/
-
-static DECLARE_THREAD_FUNCTION(GTimerThreadHandler, arg) {
-	(void)arg;
-	GTimer			*pt;
-	systemticks_t	tm;
-	systemticks_t	nxtTimeout;
-	systemticks_t	lastTime;
-	GTimerFunction	fn;
-	void			*param;
-
-	nxtTimeout = TIME_INFINITE;
-	lastTime = 0;
-	while(1) {
-		/* Wait for work to do. */
-		gfxYield();					// Give someone else a go no matter how busy we are
-		gfxSemWait(&waitsem, nxtTimeout);
-		
-	restartTimerChecks:
-	
-		// Our reference time
-		tm = gfxSystemTicks();
-		nxtTimeout = TIME_INFINITE;
-		
-		/* We need to obtain the mutex */
-		gfxMutexEnter(&mutex);
-
-		if (pTimerHead) {
-			pt = pTimerHead;
-			do {
-				// Do we have something to do for this timer?
-				if ((pt->flags & GTIMER_FLG_JABBED) || (!(pt->flags & GTIMER_FLG_INFINITE) && TimeIsWithin(pt->when, lastTime, tm))) {
-				
-					// Is this timer periodic?
-					if ((pt->flags & GTIMER_FLG_PERIODIC) && pt->period != TIME_IMMEDIATE) {
-						// Yes - Update ready for the next period
-						if (!(pt->flags & GTIMER_FLG_INFINITE)) {
-							// We may have skipped a period.
-							// We use this complicated formulae rather than a loop
-							//	because the gcc compiler stuffs up the loop so that it
-							//	either loops forever or doesn't get executed at all.
-							pt->when += ((tm + pt->period - pt->when) / pt->period) * pt->period;
-						}
-
-						// We are definitely no longer jabbed
-						pt->flags &= ~GTIMER_FLG_JABBED;
-						
-					} else {
-						// No - get us off the timers list
-						if (pt->next == pt->prev)
-							pTimerHead = 0;
-						else {
-							pt->next->prev = pt->prev;
-							pt->prev->next = pt->next;
-							if (pTimerHead == pt)
-								pTimerHead = pt->next;
-						}
-						pt->flags = 0;
-					}
-					
-					// Call the callback function
-					fn = pt->fn;
-					param = pt->param;
-					gfxMutexExit(&mutex);
-					fn(param);
-					
-					// We no longer hold the mutex, the callback function may have taken a while
-					// and our list may have been altered so start again!
-					goto restartTimerChecks;
-				}
-				
-				// Find when we next need to wake up
-				if (!(pt->flags & GTIMER_FLG_INFINITE) && pt->when - tm < nxtTimeout)
-					nxtTimeout = pt->when - tm;
-				pt = pt->next;
-			} while(pt != pTimerHead);
-		}
-
-		// Ready for the next loop
-		lastTime = tm;
-		gfxMutexExit(&mutex);
-	}
-	return 0;
-}
-
-void _gtimerInit(void)
-{
-	gfxSemInit(&waitsem, 0, 1);
-	gfxMutexInit(&mutex);
-}
-
-void _gtimerDeinit(void)
-{
-	gfxSemDestroy(&waitsem);
-	gfxMutexDestroy(&mutex);
-	// Need to destroy GTimer thread here
-}
-
-void gtimerInit(GTimer* pt)
-{
-	pt->flags = 0;
-}
-
-void gtimerDeinit(GTimer* pt)
-{
-	gtimerStop(pt);
-}
-
-void gtimerStart(GTimer *pt, GTimerFunction fn, void *param, bool_t periodic, delaytime_t millisec) {
-	gfxMutexEnter(&mutex);
-	
-	// Start our thread if not already going
-	if (!hThread) {
-		hThread = gfxThreadCreate(waTimerThread, sizeof(waTimerThread), GTIMER_THREAD_PRIORITY, GTimerThreadHandler, 0);
-		if (hThread) {gfxThreadClose(hThread);}		// We never really need the handle again
-	}
-
-	// Is this already scheduled?
-	if (pt->flags & GTIMER_FLG_SCHEDULED) {
-		// Cancel it!
-		if (pt->next == pt->prev)
-			pTimerHead = 0;
-		else {
-			pt->next->prev = pt->prev;
-			pt->prev->next = pt->next;
-			if (pTimerHead == pt)
-				pTimerHead = pt->next;
-		}
-	}
-	
-	// Set up the timer structure
-	pt->fn = fn;
-	pt->param = param;
-	pt->flags = GTIMER_FLG_SCHEDULED;
-	if (periodic)
-		pt->flags |= GTIMER_FLG_PERIODIC;
-	if (millisec == TIME_INFINITE) {
-		pt->flags |= GTIMER_FLG_INFINITE;
-		pt->period = TIME_INFINITE;
-	} else {
-		pt->period = gfxMillisecondsToTicks(millisec);
-		pt->when = gfxSystemTicks() + pt->period;
-	}
-
-	// Just pop it on the end of the queue
-	if (pTimerHead) {
-		pt->next = pTimerHead;
-		pt->prev = pTimerHead->prev;
-		pt->prev->next = pt;
-		pt->next->prev = pt;
-	} else
-		pt->next = pt->prev = pTimerHead = pt;
-
-	// Bump the thread
-	if (!(pt->flags & GTIMER_FLG_INFINITE))
-		gfxSemSignal(&waitsem);
-	gfxMutexExit(&mutex);
-}
-
-void gtimerStop(GTimer *pt) {
-	gfxMutexEnter(&mutex);
-	if (pt->flags & GTIMER_FLG_SCHEDULED) {
-		// Cancel it!
-		if (pt->next == pt)
-			pTimerHead = 0;
-		else {
-			pt->next->prev = pt->prev;
-			pt->prev->next = pt->next;
-			if (pTimerHead == pt)
-				pTimerHead = pt->next;
-		}
-		// Make sure we know the structure is dead!
-		pt->flags = 0;
-	}
-	gfxMutexExit(&mutex);
-}
-
-bool_t gtimerIsActive(GTimer *pt) {
-	return (pt->flags & GTIMER_FLG_SCHEDULED) ? TRUE : FALSE;
-}
-
-void gtimerJab(GTimer *pt) {
-	gfxMutexEnter(&mutex);
-	
-	// Jab it!
-	pt->flags |= GTIMER_FLG_JABBED;
-
-	// Bump the thread
-	gfxSemSignal(&waitsem);
-	gfxMutexExit(&mutex);
-}
-
-void gtimerJabI(GTimer *pt) {
-	// Jab it!
-	pt->flags |= GTIMER_FLG_JABBED;
-
-	// Bump the thread
-	gfxSemSignalI(&waitsem);
-}
-
-#endif /* GFX_USE_GTIMER */
-/** @} */
-
diff --git a/src/gtimer/gtimer_options.h b/src/gtimer/gtimer_options.h
new file mode 100644
index 00000000..dc0c6141
--- /dev/null
+++ b/src/gtimer/gtimer_options.h
@@ -0,0 +1,46 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gtimer/gtimer_options.h
+ * @brief   GTIMER sub-system options header file.
+ *
+ * @addtogroup GTIMER
+ * @{
+ */
+
+#ifndef _GTIMER_OPTIONS_H
+#define _GTIMER_OPTIONS_H
+
+/**
+ * @name    GTIMER Functionality to be included
+ * @{
+ */
+/**
+ * @}
+ *
+ * @name    GTIMER Optional Sizing Parameters
+ * @{
+ */
+	/**
+	 * @brief	Defines the GTIMER thread priority
+	 * @details	Defaults to HIGH_PRIORITY
+	 */
+	#ifndef GTIMER_THREAD_PRIORITY
+		#define GTIMER_THREAD_PRIORITY			HIGH_PRIORITY
+	#endif
+	/**
+	 * @brief   Defines the size of the timer threads work area (stack+structures).
+	 * @details	Defaults to 2048 bytes
+	 */
+	#ifndef GTIMER_THREAD_WORKAREA_SIZE
+		#define GTIMER_THREAD_WORKAREA_SIZE		2048
+	#endif
+/** @} */
+
+#endif /* _GTIMER_OPTIONS_H */
+/** @} */
diff --git a/src/gtimer/gtimer_rules.h b/src/gtimer/gtimer_rules.h
new file mode 100644
index 00000000..ff966d38
--- /dev/null
+++ b/src/gtimer/gtimer_rules.h
@@ -0,0 +1,29 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gtimer/gtimer_rules.h
+ * @brief   GTIMER safety rules header file.
+ *
+ * @addtogroup GTIMER
+ * @{
+ */
+
+#ifndef _GTIMER_RULES_H
+#define _GTIMER_RULES_H
+
+#if GFX_USE_GTIMER
+	#if GFX_USE_GDISP && !GDISP_NEED_MULTITHREAD
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GTIMER: GDISP_NEED_MULTITHREAD has not been specified."
+			#warning "GTIMER: Make sure you are not performing any GDISP/GWIN drawing operations in the timer callback!"
+		#endif
+	#endif
+#endif
+
+#endif /* _GTIMER_RULES_H */
+/** @} */
diff --git a/src/gtimer/sys_defs.h b/src/gtimer/sys_defs.h
deleted file mode 100644
index 45b12162..00000000
--- a/src/gtimer/sys_defs.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gtimer/sys_defs.h
- *
- * @addtogroup GTIMER
- *
- * @brief	Module which provides software based timers for user-space applications
- *
- * @details	The reason why ChibiOS/GFX has it's own timer abstraction is because
- *			virtual timers provided by ChibiOS/RT are interrupt context only.
- *			While great for what they are designed for, they make coding of the input
- *			drivers much more complex.
- *			For non-performance critical drivers like these input drivers,  it would also
- *			hog an in-ordinate amount of critical (interrupt locked) system time.
- *			This contrary to the goals of a real-time operating system. So a user-land
- *			(thread based) timer mechanism is also required.
- *
- * @pre		GFX_USE_GTIMER must be set to TRUE in your gfxconf.h
- *
- * @{
- */
-
-#ifndef _GTIMER_H
-#define _GTIMER_H
-
-#include "gfx.h"
-
-#if GFX_USE_GTIMER || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Type definitions                                                          */
-/*===========================================================================*/
-
-/* Data part of a static GTimer initialiser */
-#define _GTIMER_DATA() {0,0,0,0,0,0,0}
-
-/* Static GTimer initialiser */
-#define GTIMER_DECL(name) GTimer name = _GTIMER_DATA()
-
-/* A callback function (executed in a thread context) */
-typedef void (*GTimerFunction)(void *param);
-
-/**
- * @brief	 A GTimer structure
- */
-typedef struct GTimer_t {
-	GTimerFunction		fn;
-	void				*param;
-	systemticks_t		when;
-	systemticks_t		period;
-	uint16_t			flags;
-	struct GTimer_t		*next;
-	struct GTimer_t		*prev;
-} GTimer;
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief   Initialise a timer
- *
- * @param[in] pt 	Pointer to a GTimer structure
- *
- * @api
- */
-void gtimerInit(GTimer* pt);
-
-/**
- * @brief	Deinitialise a timer
- *
- * @param[in] pt	Pointer to a GTimer structure
- *
- * @api
- */
-void gtimerDeinit(GTimer* pt);
-
-/**
- * @brief   Set a timer going or alter its properties if it is already going.
- *
- * @param[in] pt	Pointer to a GTimer structure
- * @param[in] fn		The callback function
- * @param[in] param		The parameter to pass to the callback function
- * @param[in] periodic	Is the timer a periodic timer? FALSE is a once-only timer.
- * @param[in] millisec	The timer period. The following special values are allowed:
- *							TIME_IMMEDIATE	causes the callback function to be called asap.
- *											A periodic timer with this value will fire once only.
- *							TIME_INFINITE	never timeout (unless triggered by gtimerJab or gtimerJabI)
- *
- * @note				If the timer is already active its properties are updated with the new parameters.
- *						The current period will be immediately canceled (without the callback function being
- *						called) and the timer will be restart with the new timer properties.
- * @note				The callback function should be careful not to over-run the thread stack.
- *						Define a new value for the macro GTIME_THREAD_STACK_SIZE if you want to
- *						change the default size.
- * @note				The callback function should return as quickly as possible as all
- *						timer callbacks are performed by a single thread. If a callback function
- *						takes too long it could affect the timer response for other timers.
- * @note				A timer callback function is not a replacement for a dedicated thread if the
- *						function wants to perform computationally expensive stuff.
- * @note				As the callback function is called on GTIMER's thread, the function must make sure it uses
- *						appropriate synchronisation controls such as semaphores or mutexes around any data
- *						structures it shares with other threads such as the main application thread.
- *
- * @api
- */
-void gtimerStart(GTimer *pt, GTimerFunction fn, void *param, bool_t periodic, delaytime_t millisec);
-
-/**
- * @brief   Stop a timer (periodic or otherwise)
- *
- * @param[in] pt		Pointer to a GTimer structure
- *
- * @note				If the timer is not active this does nothing.
- *
- * @api
- */
-void gtimerStop(GTimer *pt);
-
-/**
- * @brief   Test if a timer is currently active
- *
- * @param[in] pt		Pointer to a GTimer structure
- *
- * @return	TRUE if active, FALSE otherwise
- *
- * @api
- */
-bool_t gtimerIsActive(GTimer *pt);
-
-/**
- * @brief   			Jab a timer causing the current period to immediate expire
- * @details				The callback function will be called as soon as possible.
- *
- * @pre					Use from a normal thread context.
- *
- * @param[in] pt		Pointer to a GTimer structure
- *
- * @note				If the timer is not active this does nothing.
- * @note				Repeated Jabs before the callback function actually happens are ignored.
- *
- * @api
- */
-void gtimerJab(GTimer *pt);
-
-/**
- * @brief   			Jab a timer causing the current period to immediate expire
- * @details				The callback function will be called as soon as possible.
- *
- * @pre					Use from an interrupt routine context.
- *
- * @param[in] pt		Pointer to a GTimer structure
- *
- * @note				If the timer is not active this does nothing.
- * @note				Repeated Jabs before the callback function actually happens are ignored.
- *
- * @iclass
- * @api
- */
-void gtimerJabI(GTimer *pt);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GTIMER */
-
-#endif /* _GTIMER_H */
-/** @} */
-
diff --git a/src/gtimer/sys_make.mk b/src/gtimer/sys_make.mk
deleted file mode 100644
index e48dc9f5..00000000
--- a/src/gtimer/sys_make.mk
+++ /dev/null
@@ -1 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gtimer/gtimer_gtimer.c
diff --git a/src/gtimer/sys_options.h b/src/gtimer/sys_options.h
deleted file mode 100644
index 8dca0b82..00000000
--- a/src/gtimer/sys_options.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gtimer/sys_options.h
- * @brief   GTIMER sub-system options header file.
- *
- * @addtogroup GTIMER
- * @{
- */
-
-#ifndef _GTIMER_OPTIONS_H
-#define _GTIMER_OPTIONS_H
-
-/**
- * @name    GTIMER Functionality to be included
- * @{
- */
-/**
- * @}
- *
- * @name    GTIMER Optional Sizing Parameters
- * @{
- */
-	/**
-	 * @brief	Defines the GTIMER thread priority
-	 * @details	Defaults to HIGH_PRIORITY
-	 */
-	#ifndef GTIMER_THREAD_PRIORITY
-		#define GTIMER_THREAD_PRIORITY			HIGH_PRIORITY
-	#endif
-	/**
-	 * @brief   Defines the size of the timer threads work area (stack+structures).
-	 * @details	Defaults to 2048 bytes
-	 */
-	#ifndef GTIMER_THREAD_WORKAREA_SIZE
-		#define GTIMER_THREAD_WORKAREA_SIZE		2048
-	#endif
-/** @} */
-
-#endif /* _GTIMER_OPTIONS_H */
-/** @} */
diff --git a/src/gtimer/sys_rules.h b/src/gtimer/sys_rules.h
deleted file mode 100644
index 6f277965..00000000
--- a/src/gtimer/sys_rules.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gtimer/sys_rules.h
- * @brief   GTIMER safety rules header file.
- *
- * @addtogroup GTIMER
- * @{
- */
-
-#ifndef _GTIMER_RULES_H
-#define _GTIMER_RULES_H
-
-#if GFX_USE_GTIMER
-	#if GFX_USE_GDISP && !GDISP_NEED_MULTITHREAD
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GTIMER: GDISP_NEED_MULTITHREAD has not been specified."
-			#warning "GTIMER: Make sure you are not performing any GDISP/GWIN drawing operations in the timer callback!"
-		#endif
-	#endif
-#endif
-
-#endif /* _GTIMER_RULES_H */
-/** @} */
diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c
new file mode 100644
index 00000000..eb51b89a
--- /dev/null
+++ b/src/gwin/gwin.c
@@ -0,0 +1,400 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file	src/gwin/gwin_gwin.c
+ * @brief	GWIN sub-system code
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GWIN
+
+#include "gwin_class.h"
+
+#include <string.h>
+
+/*-----------------------------------------------
+ * Data
+ *-----------------------------------------------*/
+
+static const gwinVMT basegwinVMT = {
+		"GWIN",					// The classname
+		sizeof(GWindowObject),	// The object size
+		0,						// The destroy routine
+		0,						// The redraw routine
+		0,						// The after-clear routine
+};
+
+static color_t	defaultFgColor = White;
+static color_t	defaultBgColor = Black;
+#if GDISP_NEED_TEXT
+	static font_t	defaultFont;
+#endif
+
+/*-----------------------------------------------
+ * Helper Routines
+ *-----------------------------------------------*/
+
+/*-----------------------------------------------
+ * Class Routines
+ *-----------------------------------------------*/
+
+void _gwinInit(void)
+{
+	extern void _gwmInit(void);
+
+	_gwmInit();
+	#if GWIN_NEED_WIDGET
+		extern void _gwidgetInit(void);
+
+		_gwidgetInit();
+	#endif
+	#if GWIN_NEED_CONTAINERS
+		extern void _gcontainerInit(void);
+
+		_gcontainerInit();
+	#endif
+}
+
+void _gwinDeinit(void)
+{
+	extern void _gwmDeinit(void);
+
+	#if GWIN_NEED_CONTAINERS
+		extern void _gcontainerDeinit(void);
+
+		_gcontainerDeinit();
+	#endif
+	#if GWIN_NEED_WIDGET
+		extern void _gwidgetDeinit(void);
+
+		_gwidgetDeinit();
+	#endif
+
+	_gwmDeinit();
+}
+
+// Internal routine for use by GWIN components only
+// Initialise a window creating it dynamically if required.
+GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint32_t flags) {
+	// Allocate the structure if necessary
+	if (!pgw) {
+		if (!(pgw = gfxAlloc(vmt->size)))
+			return 0;
+		pgw->flags = flags|GWIN_FLG_DYNAMIC;
+	} else
+		pgw->flags = flags;
+	
+	// Initialise all basic fields
+	pgw->display = g;
+	pgw->vmt = vmt;
+	pgw->color = defaultFgColor;
+	pgw->bgcolor = defaultBgColor;
+	#if GDISP_NEED_TEXT
+		pgw->font = defaultFont;
+	#endif
+
+	// Make sure we don't create nasty problems for ourselves
+	if (vmt->size > sizeof(GWindowObject))
+		memset(pgw+1, 0, vmt->size - sizeof(GWindowObject));
+
+	if (!_gwinWMAdd(pgw, pInit)) {
+		if ((pgw->flags & GWIN_FLG_DYNAMIC))
+			gfxFree(pgw);
+		return 0;
+	}
+
+	return (GHandle)pgw;
+}
+
+// Internal routine for use by GWIN components only
+void _gwinDestroy(GHandle gh, GRedrawMethod how) {
+	if (!gh)
+		return;
+
+	// Make the window invisible
+	gwinSetVisible(gh, FALSE);
+
+	// Make sure it is flushed first - must be REDRAW_WAIT or REDRAW_INSESSION
+	_gwinFlushRedraws(how);
+
+	#if GWIN_NEED_CONTAINERS
+		// Notify the parent it is about to be deleted
+		if (gh->parent && ((gcontainerVMT *)gh->parent->vmt)->NotifyDelete)
+			((gcontainerVMT *)gh->parent->vmt)->NotifyDelete(gh->parent, gh);
+	#endif
+
+	// Remove from the window manager
+	#if GWIN_NEED_WINDOWMANAGER
+		_GWINwm->vmt->Delete(gh);
+	#endif
+
+	// Class destroy routine
+	if (gh->vmt->Destroy)
+		gh->vmt->Destroy(gh);
+
+	// Clean up the structure
+	if (gh->flags & GWIN_FLG_DYNAMIC) {
+		gh->flags = 0;							// To be sure, to be sure
+		gfxFree((void *)gh);
+	} else
+		gh->flags = 0;							// To be sure, to be sure
+}
+
+/*-----------------------------------------------
+ * Routines that affect all windows
+ *-----------------------------------------------*/
+
+void gwinClearInit(GWindowInit *pwi) {
+	char		*p;
+	unsigned	len;
+
+	for(p = (char *)pwi, len = sizeof(GWindowInit); len; len--)
+		*p++ = 0;
+}
+
+void gwinSetDefaultColor(color_t clr) {
+	defaultFgColor = clr;
+}
+
+color_t gwinGetDefaultColor(void) {
+	return defaultFgColor;
+}
+
+void gwinSetDefaultBgColor(color_t bgclr) {
+	defaultBgColor = bgclr;
+}
+
+color_t gwinGetDefaultBgColor(void) {
+	return defaultBgColor;
+}
+
+#if GDISP_NEED_TEXT
+	void gwinSetDefaultFont(font_t font) {
+		defaultFont = font;
+	}
+
+	font_t gwinGetDefaultFont(void) {
+		return defaultFont;
+	}
+#endif
+
+/*-----------------------------------------------
+ * The GWindow Routines
+ *-----------------------------------------------*/
+
+GHandle gwinGWindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit) {
+	if (!(pgw = _gwindowCreate(g, pgw, pInit, &basegwinVMT, 0)))
+		return 0;
+
+	gwinSetVisible(pgw, pInit->show);
+
+	return pgw;
+}
+
+void gwinDestroy(GHandle gh) {
+	_gwinDestroy(gh, REDRAW_WAIT);
+}
+
+const char *gwinGetClassName(GHandle gh) {
+	return gh->vmt->classname;
+}
+
+bool_t gwinGetVisible(GHandle gh) {
+	return (gh->flags & GWIN_FLG_SYSVISIBLE) ? TRUE : FALSE;
+}
+
+bool_t gwinGetEnabled(GHandle gh) {
+	return (gh->flags & GWIN_FLG_SYSENABLED) ? TRUE : FALSE;
+}
+
+#if GDISP_NEED_TEXT
+	void gwinSetFont(GHandle gh, font_t font) {
+		gh->font = font;
+	}
+#endif
+
+void gwinClear(GHandle gh) {
+	/*
+	 * Don't render anything when the window is not visible but 
+	 * still call the AfterClear() routine as some widgets will
+	 * need this to clear internal buffers or similar
+	 */
+	if (_gwinDrawStart(gh)) {
+		gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
+		_gwinDrawEnd(gh);
+	}
+	if (gh->vmt->AfterClear)
+		gh->vmt->AfterClear(gh);
+}
+
+void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {
+	if (!_gwinDrawStart(gh)) return;
+	gdispGDrawPixel(gh->display, gh->x+x, gh->y+y, gh->color);
+	_gwinDrawEnd(gh);
+}
+
+void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) {
+	if (!_gwinDrawStart(gh)) return;
+	gdispGDrawLine(gh->display, gh->x+x0, gh->y+y0, gh->x+x1, gh->y+y1, gh->color);
+	_gwinDrawEnd(gh);
+}
+
+void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
+	if (!_gwinDrawStart(gh)) return;
+	gdispGDrawBox(gh->display, gh->x+x, gh->y+y, cx, cy, gh->color);
+	_gwinDrawEnd(gh);
+}
+
+void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
+	if (!_gwinDrawStart(gh)) return;
+	gdispGFillArea(gh->display, gh->x+x, gh->y+y, cx, cy, gh->color);
+	_gwinDrawEnd(gh);
+}
+
+void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
+	if (!_gwinDrawStart(gh)) return;
+	gdispGBlitArea(gh->display, gh->x+x, gh->y+y, cx, cy, srcx, srcy, srccx, buffer);
+	_gwinDrawEnd(gh);
+}
+
+#if GDISP_NEED_CIRCLE
+	void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGDrawCircle(gh->display, gh->x+x, gh->y+y, radius, gh->color);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGFillCircle(gh->display, gh->x+x, gh->y+y, radius, gh->color);
+		_gwinDrawEnd(gh);
+	}
+#endif
+
+#if GDISP_NEED_ELLIPSE
+	void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGDrawEllipse(gh->display, gh->x+x, gh->y+y, a, b, gh->color);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGFillEllipse(gh->display, gh->x+x, gh->y+y, a, b, gh->color);
+		_gwinDrawEnd(gh);
+	}
+#endif
+
+#if GDISP_NEED_ARC
+	void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGDrawArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGFillArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color);
+		_gwinDrawEnd(gh);
+	}
+#endif
+
+#if GDISP_NEED_ARCSECTORS
+	void gwinDrawArcSectors(GHandle gh, coord_t x, coord_t y, coord_t radius, uint8_t sectors) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGDrawArcSectors(gh->display, gh->x+x, gh->y+y, radius, sectors, gh->color);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinFillArcSectors(GHandle gh, coord_t x, coord_t y, coord_t radius, uint8_t sectors) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGFillArcSectors(gh->display, gh->x+x, gh->y+y, radius, sectors, gh->color);
+		_gwinDrawEnd(gh);
+	}
+#endif
+
+#if GDISP_NEED_PIXELREAD
+	color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y) {
+		if (!_gwinDrawStart(gh)) return (color_t)0;
+		return gdispGGetPixelColor(gh->display, gh->x+x, gh->y+y);
+		_gwinDrawEnd(gh);
+	}
+#endif
+
+#if GDISP_NEED_TEXT
+	void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c) {
+		if (!gh->font || !_gwinDrawStart(gh)) return;
+		gdispGDrawChar(gh->display, gh->x+x, gh->y+y, c, gh->font, gh->color);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c) {
+		if (!gh->font || !_gwinDrawStart(gh)) return;
+		gdispGFillChar(gh->display, gh->x+x, gh->y+y, c, gh->font, gh->color, gh->bgcolor);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str) {
+		if (!gh->font || !_gwinDrawStart(gh)) return;
+		gdispGDrawString(gh->display, gh->x+x, gh->y+y, str, gh->font, gh->color);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str) {
+		if (!gh->font || !_gwinDrawStart(gh)) return;
+		gdispGFillString(gh->display, gh->x+x, gh->y+y, str, gh->font, gh->color, gh->bgcolor);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
+		if (!gh->font || !_gwinDrawStart(gh)) return;
+		gdispGDrawStringBox(gh->display, gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, justify);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
+		if (!gh->font || !_gwinDrawStart(gh)) return;
+		gdispGFillStringBox(gh->display, gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, gh->bgcolor, justify);
+		_gwinDrawEnd(gh);
+	}
+#endif
+
+#if GDISP_NEED_CONVEX_POLYGON
+	void gwinDrawPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGDrawPoly(gh->display, tx+gh->x, ty+gh->y, pntarray, cnt, gh->color);
+		_gwinDrawEnd(gh);
+	}
+
+	void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGFillConvexPoly(gh->display, tx+gh->x, ty+gh->y, pntarray, cnt, gh->color);
+		_gwinDrawEnd(gh);
+	}
+	void gwinDrawThickLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t width, bool_t round) {
+		if (!_gwinDrawStart(gh)) return;
+		gdispGDrawThickLine(gh->display, gh->x+x0, gh->y+y0, gh->x+x1, gh->y+y1, gh->color, width, round);
+		_gwinDrawEnd(gh);
+	}
+#endif
+
+#if GDISP_NEED_IMAGE
+	gdispImageError gwinDrawImage(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
+		gdispImageError		ret;
+
+		if (!_gwinDrawStart(gh)) return GDISP_IMAGE_ERR_OK;
+		ret = gdispGImageDraw(gh->display, img, gh->x+x, gh->y+y, cx, cy, sx, sy);
+		_gwinDrawEnd(gh);
+		return ret;
+	}
+#endif
+
+#endif /* GFX_USE_GWIN */
+/** @} */
+
diff --git a/src/gwin/gwin.h b/src/gwin/gwin.h
new file mode 100644
index 00000000..81bf38e5
--- /dev/null
+++ b/src/gwin/gwin.h
@@ -0,0 +1,1026 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gwin/gwin.h
+ *
+ * @defgroup Window Window
+ * @ingroup Windows
+ *
+ * @details		GWIN provides a basic window manager which allows it to easily
+ *				create and destroy different windows at runtime. Each window
+ *				will have it's own properties such as colors as well as
+ *				it's own drawing origin.
+ *
+ * @pre		GFX_USE_GWIN must be set to TRUE in your gfxconf.h
+ * @{
+ */
+
+#ifndef _GWIN_H
+#define _GWIN_H
+
+#include "gfx.h"
+
+#if GFX_USE_GWIN || defined(__DOXYGEN__)
+
+/* Forward declaration */
+typedef struct GWindowObject *GHandle;
+
+/**
+ * @brief	A window object structure
+ * @note	Do not access the members directly. Treat it as a black-box and use the method functions.
+ * @{
+ */
+typedef struct GWindowObject {
+	#if GWIN_NEED_WINDOWMANAGER
+		// This MUST be the first member of the structure
+		gfxQueueASyncItem	wmq;				// @< The next window (for the window manager)
+	#endif
+	const struct gwinVMT	*vmt;				// @< The VMT for this GWIN
+	GDisplay *				display;			// @< The display this window is on.
+	coord_t					x, y;				// @< Screen relative position
+	coord_t					width, height;		// @< Dimensions of this window
+	color_t					color, bgcolor;		// @< The current drawing colors
+	uint32_t				flags;				// @< Window flags (the meaning is private to the GWIN class)
+	#if GDISP_NEED_TEXT
+		font_t				font;				// @< The current font
+	#endif
+	#if GWIN_NEED_CONTAINERS
+		GHandle				parent;				// @< The parent window
+	#endif
+} GWindowObject, * GHandle;
+/** @} */
+
+/**
+ * @brief	The structure to initialise a GWIN.
+ *
+ * @note	Some gwin's will need extra parameters.
+ * @note	The dimensions and position may be changed to fit on the real screen.
+ * @note	If you create this structure on the stack, you should always memset
+ * 			it to all zero's first in case a future version of the software
+ * 			add's extra fields. Alternatively you can use @p gwinClearInit()
+ * 			to clear it.
+ *
+ * @{
+ */
+typedef struct GWindowInit {
+	coord_t			x, y;							// @< The initial position relative to its parent
+	coord_t			width, height;					// @< The initial dimension
+	bool_t			show;							// @< Should the window be visible initially
+	#if GWIN_NEED_CONTAINERS
+		GHandle		parent;							// @< The parent - must be a container or NULL
+	#endif
+} GWindowInit;
+/** @} */
+
+/**
+ * @brief	A window's minimized, maximized or normal size
+ */
+typedef enum { GWIN_NORMAL, GWIN_MAXIMIZE, GWIN_MINIMIZE } GWindowMinMax;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-------------------------------------------------
+ * Window Manager functions
+ *-------------------------------------------------*/
+
+#if GWIN_NEED_WINDOWMANAGER || defined(__DOXYGEN__)
+	// Forward definition
+	struct GWindowManager;
+
+	/**
+	 * @brief   Set the window manager for the GWIN system.
+	 *
+	 * @param[in] gwm		The window manager to use. Can be NULL to turn off the existing window manager.
+	 *
+	 * @note				A window manager is responsible for handling when window visibility is changed or
+	 * 						a window is resized for moved. Note that only saved window states will be redrawn. Each
+	 * 						window type can save different information (or none at all). See the documentation on each window
+	 * 						type to see which information it saves (and can therefore be automatically redrawn).
+	 * 						For window types that do not save any state information, the window manager determines what to do.
+	 * 						Generally it will just clear the window to its background color.
+	 *
+	 * @api
+	 */
+	void gwinSetWindowManager(struct GWindowManager *gwm);
+#endif
+
+/*-------------------------------------------------
+ * Functions that affect all windows
+ *-------------------------------------------------*/
+
+	/**
+	 * @brief	Clear a GWindowInit structure to all zero's
+	 * @note	This function is provided just to prevent problems
+	 * 			on operating systems where using memset() causes issues
+	 * 			in the users application.
+	 *
+	 * @param[in] pwi	The GWindowInit structure to clear
+	 *
+	 * @api
+	 */
+	void gwinClearInit(GWindowInit *pwi);
+
+	/**
+	 * @brief	Set the default foreground color for all new GWIN windows
+	 *
+	 * @param[in] clr	The color to be set
+	 *
+	 * @api
+	 */
+	void gwinSetDefaultColor(color_t clr);
+
+	/**
+	 * @brief	Get the default foreground color for all new GWIN windows
+	 *
+	 * @return	The current default color for all new GWIN windows
+	 *
+	 * @api
+	 */
+	color_t gwinGetDefaultColor(void);
+
+	/**
+	 * @brief	Set the default background color for all new GWIN windows
+	 *
+	 * @param[in] bgclr	The background color
+	 *
+	 * @api
+	 */
+	void gwinSetDefaultBgColor(color_t bgclr);
+
+	/**
+	 * @brief	Get the default background color for all new GWIN windows
+	 *
+	 * @return	The current default background color for all new GWIN windows
+	 *
+	 * @api
+	 */
+	color_t gwinGetDefaultBgColor(void);
+
+	#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
+		/**
+		 * @brief	Set the default font for all new GWIN windows
+		 *
+		 * @param[in] font	The new font to be set
+		 *
+		 * @api
+		 */
+		void gwinSetDefaultFont(font_t font);
+
+		/**
+		 * @brief	Get the current default font
+		 *
+		 * @return	The current default font
+		 *
+		 * @api
+		 */
+		font_t gwinGetDefaultFont(void);
+	#endif
+
+/*-------------------------------------------------
+ * Base functions
+ *-------------------------------------------------*/
+
+	/**
+	 * @brief   Create a basic window.
+	 * @return  NULL if there is no resultant drawing area, otherwise a window handle.
+	 *
+	 * @param[in] g			The GDisplay to display this window on
+	 * @param[in] pgw		The window structure to initialize. If this is NULL the structure is dynamically allocated.
+	 * @param[in] pInit		How to initialise the window
+	 *
+	 * @note				The drawing color and the background color get set to the current defaults. If you haven't called
+	 * 						@p gwinSetDefaultColor() or @p gwinSetDefaultBgColor() then these are White and Black respectively.
+	 * @note				The font gets set to the current default font. If you haven't called @p gwinSetDefaultFont() then there
+	 * 						is no default font and text drawing operations will no nothing.
+	 * @note				A basic window does not save the drawing state. It is not automatically redrawn if the window is moved or
+	 * 						its visibility state is changed.
+	 *
+	 * @api
+	 */
+	GHandle gwinGWindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit);
+	#define gwinWindowCreate(pgw, pInit)		gwinGWindowCreate(GDISP, pgw, pInit);
+
+	/**
+	 * @brief   Destroy a window (of any type). Releases any dynamically allocated memory.
+	 *
+	 * @param[in] gh		The window handle
+	 *
+	 * @api
+	 */
+	void gwinDestroy(GHandle gh);
+
+	/**
+	 * @brief	Get the real class name of the GHandle
+	 * @details	Returns a string describing the object class.
+	 *
+	 * @param[in] gh	The window
+	 *
+	 * @return	A string describing the object class.
+	 *
+	 * @api
+	 */
+	const char* gwinGetClassName(GHandle gh);
+
+	/**
+	 * @brief	Get an ID that uniquely describes the class of the GHandle
+	 *
+	 * @param[in] gh	The window
+	 *
+	 * @api
+	 */
+	#define gwinGetClassID(gh)		((void *)((gh)->vmt))
+
+	/**
+	 * @brief	Get the X coordinate of the window
+	 * @details	Returns the X coordinate of the origin of the window.
+	 *			The coordinate is relative to the physical screen zero point.
+	 *
+	 * @param[in] gh	The window
+	 *
+	 * @api
+	 */
+	#define gwinGetScreenX(gh)			((gh)->x)
+
+	/**
+	 * @brief	Get the Y coordinate of the window
+	 * @details	Returns the Y coordinate of the origin of the window.
+	 *			The coordinate is relative to the physical screen zero point.
+	 *
+	 * @param[in] gh	The window
+	 *
+	 * @api
+	 */
+	#define gwinGetScreenY(gh)			((gh)->y)
+
+	/**
+	 * @brief	Get the width of the window
+	 *
+	 * @param[in] gh	The window
+	 *
+	 * @api
+	 */
+	#define gwinGetWidth(gh)			((gh)->width)
+
+	/**
+	 * @brief	Get the height of the window
+	 *
+	 * @param[in] gh	The window
+	 *
+	 * @api
+	 */
+	#define gwinGetHeight(gh)			((gh)->height)
+
+	/**
+	 * @brief	Set foreground color
+	 * @details Set the color which will be used to draw
+	 *
+	 * @param[in] gh	The window
+	 * @param[in] clr	The color to be set
+	 *
+	 * @api
+	 */
+	#define gwinSetColor(gh, clr)		(gh)->color = (clr)
+
+	/**
+	 * @brief	Set background color
+	 * @details	Set the color which will be used as background
+	 * @note	gwinClear() must be called to set the background color
+	 *
+	 * @param[in] gh	The window
+	 * @param[in] bgclr	The background color
+	 *
+	 * @api
+	 */
+	#define gwinSetBgColor(gh, bgclr)	(gh)->bgcolor = (bgclr)
+
+	/**
+	 * @brief	Get the foreground color of a window
+	 *
+	 * @param[in] gh	The window
+	 *
+	 * @api
+	 */
+	#define gwinGetColor(gh)			(gh)->color
+
+	/**
+	 * @brief	Get the background color of a window
+	 *
+	 * @param[in] gh	The window
+	 *
+	 * @api
+	 */
+	#define gwinGetBgColor(gh)			(gh)->bgcolor
+
+	/**
+	 * @brief	Sets whether a window is visible or not
+	 *
+	 * @param[in] gh		The window
+	 * @param[in] visible	Whether the window should be visible or not
+	 *
+	 * @note	When a window is marked as not visible, drawing operations
+	 * 			on the window do nothing.
+	 * @note	When a window is marked as visible, it is not automatically
+	 * 			redrawn as many window types don't remember their drawing state.
+	 * 			Widgets such as Buttons, Sliders etc will be redrawn.
+	 * @note	If there is no window manager in use, when a window is marked
+	 * 			as not visible, nothing is done to remove the window from the screen.
+	 * 			When there is a window manager, it is up to the window manager to
+	 * 			handle what happens.
+	 * @note	Even when you mark a window as visible, it may still not be displayed
+	 * 			if it's parent is invisible. When the parent becomes visible this child
+	 * 			will automatically be shown because it is already marked as visible.
+	 *
+	 * @api
+	 */
+	void gwinSetVisible(GHandle gh, bool_t visible);
+
+	/**
+	 * @brief	Makes a widget become visible
+	 *
+	 * @param[in] gh		The window handle
+	 *
+	 * @api
+	 */
+	#define gwinShow(gh)		gwinSetVisible(gh, TRUE)
+
+	/**
+	 * @brief	Makes a widget become invisible
+	 *
+	 * @param[in] gh		The window handle
+	 *
+	 * @api
+	 */
+	#define gwinHide(gh)		gwinSetVisible(gh, FALSE)
+
+	/**
+	 * @brief	Gets the visibility of a window
+	 * @return	TRUE if visible
+	 *
+	 * @note	It is possible for a child to be marked as visible by @p gwinSetVisible()
+	 * 			but for this call to return FALSE if one of its parents are not visible.
+	 *
+	 * @param[in] gh		The window
+	 *
+	 * @api
+	 */
+	bool_t gwinGetVisible(GHandle gh);
+
+	/**
+	 * @brief	Enable or disable a window
+	 *
+	 * @param[in] gh		The window handle
+	 * @param[in] enabled	Enable or disable the window
+	 *
+	 * @note	The window is automatically redrawn if it supports self-redrawing.
+	 * @note	Even when you mark a window as enabled, it may still remain disabled
+	 * 			if it's parent is disabled. When the parent becomes enabled this child
+	 * 			will automatically be enabled because it is already marked as enabled.
+	 *
+	 * @api
+	 */
+	void gwinSetEnabled(GHandle gh, bool_t enabled);
+
+	/**
+	 * @brief	Enables a widget
+	 *
+	 * @param[in] gh		The window handle
+	 *
+	 * @api
+	 */
+	#define gwinEnable(gh)		gwinSetEnabled(gh, TRUE)
+
+	/**
+	 * @brief	Disables a widget
+	 *
+	 * @param[in] gh		The window handle
+	 *
+	 * @api
+	 */
+	#define gwinDisable(gh)		gwinSetEnabled(gh, FALSE)
+
+	/**
+	 * @brief	Gets the enabled state of a window
+	 * @return	TRUE if enabled
+	 *
+	 * @note	It is possible for a child to be marked as enabled by @p gwinSetEnabled()
+	 * 			but for this call to return FALSE if one of its parents are not enabled.
+	 *
+	 * @param[in] gh		The window
+	 *
+	 * @api
+	 */
+	bool_t gwinGetEnabled(GHandle gh);
+
+	/**
+	 * @brief	Move a window
+	 *
+	 * @param[in] gh		The window
+	 * @param[in] x, y		The new position (screen relative) for this window
+	 *
+	 * @note	The final window position may not be the requested position. Windows
+	 * 			are clipped to the screen area and the window manager may also affect the position.
+	 * @note	The window is redrawn if it is visible. See the comments in @p gwinSetVisible()
+	 * 			with regard to what can be redrawn and what can't.
+	 * @note	It is up to the window manager to determine what happens with the screen area
+	 * 			uncovered by moving the window. When there is no window manager, nothing
+	 * 			is done with the uncovered area.
+	 *
+	 * @api
+	 */
+	void gwinMove(GHandle gh, coord_t x, coord_t y);
+
+	/**
+	 * @brief	Resize a window
+	 *
+	 * @param[in] gh				The window
+	 * @param[in] width, height		The new size of the window
+	 *
+	 * @note	The final window size may not be the requested size. Windows
+	 * 			are clipped to the screen area and the window manager may also affect the size.
+	 * @note	The window is redrawn if it is visible. See the comments in @p gwinSetVisible()
+	 * 			with regard to what can be redrawn and what can't.
+	 * @note	It is up to the window manager to determine what happens with any screen area
+	 * 			uncovered by resizing the window. When there is no window manager, nothing
+	 * 			is done with the uncovered area.
+	 *
+	 * @api
+	 */
+	void gwinResize(GHandle gh, coord_t width, coord_t height);
+
+	/**
+	 * @brief	Redraw a window
+	 *
+	 * @param[in] gh				The window
+	 *
+	 * @note	This is normally never required as windows and widgets will redraw as required.
+	 * 			Note that some windows are incapable of redrawing themselves as they don't save
+	 * 			their drawing state.
+	 *
+	 * @api
+	 */
+	void gwinRedraw(GHandle gh);
+
+	#if GWIN_NEED_WINDOWMANAGER || defined (__DOXYGEN__)
+		/**
+		 * @brief	Redraw a window
+		 *
+		 * @param[in] g				The display to redraw. Passing NULL will redraw all displays.
+		 * @param[in] preserve		Should the redraw try to preserve existing screen data for those
+		 * 							windows that can't redraw themselves?
+		 *
+		 * @note	This is normally never required as windows and widgets will redraw as required.
+		 * @note	Some windows are incapable of redrawing themselves as they don't save
+		 * 			their drawing state.
+		 * @note	This does not clear the background - just redraws the gwin windows (where possible)
+		 *
+		 * @api
+		 */
+		void gwinRedrawDisplay(GDisplay *g, bool_t preserve);
+
+		/**
+		 * @brief	Minimize, Maximize or Restore a window
+		 * @pre		GWIN_NEED_WINDOWMANAGER must be TRUE
+		 *
+		 * @param[in] gh				The window
+		 * @param[in] minmax			The new minimized/maximized state
+		 *
+		 * @note	The final window state may not be the requested state. Window Managers
+		 * 			do not need to implement changing the minmax state. If there is no
+		 * 			window manager this call is ignored.
+		 * @note	The window is redrawn if it is changed. See the comments in @p gwinSetVisible()
+		 * 			with regard to what can be redrawn and what can't.
+		 * @note	It is up to the window manager to determine what happens with any screen area
+		 * 			uncovered by resizing the window.
+		 * @note	When a window is minimised it may be asked to draw the window or the window
+		 * 			manager may draw the minimised window.
+		 *
+		 * @api
+		 */
+		void gwinSetMinMax(GHandle gh, GWindowMinMax minmax);
+
+		/**
+		 * @brief	Get the Minimized/Maximized state of a window
+		 * @pre		GWIN_NEED_WINDOWMANAGER must be TRUE
+		 *
+		 * @param[in] gh				The window
+		 *
+		 * @return	GWIN_NORMAL, GWIN_MAXIMIZE or GWIN_MINIMIZE
+		 *
+		 * @api
+		 */
+		GWindowMinMax gwinGetMinMax(GHandle gh);
+
+		/**
+		 * @brief	Raise a window to the top of the z-order
+		 * @pre		GWIN_NEED_WINDOWMANAGER must be TRUE
+		 *
+		 * @param[in] gh				The window
+		 *
+		 * @note	The window z-order is only supported by some window managers. See the comments
+		 * 			in @p gwinSetVisible() with regard to what can be redrawn and what can't.
+		 *
+		 * @api
+		 */
+		void gwinRaise(GHandle gh);
+
+		/**
+		 * @brief	Get the next window in the z-order
+		 * @return	The next window or NULL if no more windows
+		 *
+		 * @param[in] gh		The previous window or NULL to get the first window
+		 *
+		 * @note	This returns the next window in the system from top to bottom.
+		 * @note	Where there are parent child relationships, this ignores them
+		 * 			and will list all windows in the system. There is no defined
+		 * 			order between children of siblings and they can in fact be mixed
+		 * 			in order. The only relationship honored is that parents will be
+		 * 			listed before their children.
+		 *
+		 * @api
+		 */
+		GHandle gwinGetNextWindow(GHandle gh);
+
+	#endif
+
+	#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
+		/**
+		 * @brief   Set the current font for this window.
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] font		The font to use for text functions
+		 *
+		 * @api
+		 */
+		void gwinSetFont(GHandle gh, font_t font);
+	#endif
+
+/*-------------------------------------------------
+ * Drawing functions
+ *-------------------------------------------------*/
+
+	/**
+	 * @brief   Clear the window
+	 * @note	Uses the current background color to clear the window
+	 *
+	 * @param[in] gh		The window handle
+	 *
+	 * @api
+	 */
+	void gwinClear(GHandle gh);
+
+	/**
+	 * @brief   Set a pixel in the window
+	 * @note	Uses the current foreground color to set the pixel
+	 * @note	May leave GDISP clipping to this window's dimensions
+	 *
+	 * @param[in] gh		The window handle
+	 * @param[in] x,y		The coordinates of the pixel
+	 *
+	 * @api
+	 */
+	void gwinDrawPixel(GHandle gh, coord_t x, coord_t y);
+
+	/**
+	 * @brief   Draw a line in the window
+	 * @note	Uses the current foreground color to draw the line
+	 * @note	May leave GDISP clipping to this window's dimensions
+	 *
+	 * @param[in] gh		The window handle
+	 * @param[in] x0,y0		The start position
+	 * @param[in] x1,y1 	The end position
+	 *
+	 * @api
+	 */
+	void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1);
+
+	/**
+	 * @brief   Draw a box in the window
+	 * @note	Uses the current foreground color to draw the box
+	 * @note	May leave GDISP clipping to this window's dimensions
+	 *
+	 * @param[in] gh		The window handle
+	 * @param[in] x,y		The start position
+	 * @param[in] cx,cy		The size of the box (outside dimensions)
+	 *
+	 * @api
+	 */
+	void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy);
+
+	/**
+	 * @brief   Fill an rectangular area in the window
+	 * @note	Uses the current foreground color to fill the box
+	 * @note	May leave GDISP clipping to this window's dimensions
+	 *
+	 * @param[in] gh		The window handle
+	 * @param[in] x,y		The start position
+	 * @param[in] cx,cy		The size of the box (outside dimensions)
+	 *
+	 * @api
+	 */
+	void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy);
+
+	/**
+	 * @brief   Fill an area in the window using the supplied bitmap.
+	 * @details The bitmap is in the pixel format specified by the low level driver
+	 * @note	If GDISP_NEED_ASYNC is defined then the buffer must be static
+	 * 			or at least retained until this call has finished the blit. You can
+	 * 			tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE.
+	 * @note	May leave GDISP clipping to this window's dimensions
+	 *
+	 * @param[in] gh		The window handle
+	 * @param[in] x, y		The start filled area
+	 * @param[in] cx, cy	The width and height to be filled
+	 * @param[in] srcx, srcy	The bitmap position to start the fill from
+	 * @param[in] srccx		The width of a line in the bitmap.
+	 * @param[in] buffer	The pixels to use to fill the area.
+	 *
+	 * @api
+	 */
+	void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer);
+
+/*-------------------------------------------------
+ * Circle, ellipse, arc and arc-sectors functions
+ *-------------------------------------------------*/
+
+	#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__)
+		/**
+		 * @brief   Draw a circle in the window.
+		 * @note	Uses the current foreground color to draw the circle
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x, y		The center of the circle
+		 * @param[in] radius	The radius of the circle
+		 *
+		 * @api
+		 */
+		void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius);
+
+		/**
+		 * @brief   Draw a filled circle in the window.
+		 * @note	Uses the current foreground color to draw the filled circle
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x, y		The center of the circle
+		 * @param[in] radius	The radius of the circle
+		 *
+		 * @api
+		 */
+		void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius);
+	#endif
+
+	#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__)
+		/**
+		 * @brief   Draw an ellipse.
+		 * @note	Uses the current foreground color to draw the ellipse
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The center of the ellipse
+		 * @param[in] a,b		The dimensions of the ellipse
+		 *
+		 * @api
+		 */
+		void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b);
+
+		/**
+		 * @brief   Draw an filled ellipse.
+		 * @note	Uses the current foreground color to draw the filled ellipse
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The center of the ellipse
+		 * @param[in] a,b		The dimensions of the ellipse
+		 *
+		 * @api
+		 */
+		void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b);
+	#endif
+
+	#if GDISP_NEED_ARC || defined(__DOXYGEN__)
+		/*
+		 * @brief	Draw an arc in the window.
+		 * @note	Uses the current foreground color to draw the arc
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The center point
+		 * @param[in] radius	The radius of the arc
+		 * @param[in] start		The start angle (0 to 360)
+		 * @param[in] end		The end angle (0 to 360)
+		 *
+		 * @api
+		 */
+		void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle);
+
+		/*
+		 * @brief	Draw a filled arc in the window.
+		 * @note	Uses the current foreground color to draw the filled arc
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The center point
+		 * @param[in] radius	The radius of the arc
+		 * @param[in] start		The start angle (0 to 360)
+		 * @param[in] end		The end angle (0 to 360)
+		 *
+		 * @api
+		 */
+		void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle);
+	#endif
+
+	#if GDISP_NEED_ARCSECTORS || defined(__DOXYGEN__)
+		/*
+		 * @brief	Draw a selection of 45 degree arcs of a circle in the window.
+		 * @note	Uses the current foreground color to draw the arc sector
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The center of the circle
+		 * @param[in] radius	The radius of the circle
+		 * @param[in] sectors	Bits determine which sectors are drawn.
+		 * 						Bits go anti-clockwise from the 0 degree mark (y = 0, x is positive), as follows:
+		 *  						bit 0 - upper right right		  -----
+		 *  						bit 1 - upper upper right		 /2   1\
+		 *  						bit 2 - upper upper left		/3     0\
+		 *  						bit 3 - upper left  left		\4     7/
+		 *  						bit 4 - lower left  left		 \5   6/
+		 *  						bit 5 - lower lower left		  -----
+		 *  						bit 6 - lower lower right
+		 *  						bit 7 - lower left  left
+		 *
+		 * @api
+		 */
+		void gwinDrawArcSectors(GHandle gh, coord_t x, coord_t y, coord_t radius, uint8_t sectors);
+
+		/*
+		 * @brief	Draw a filled selection of 45 degree arcs of a circle in the window.
+		 * @note	Uses the current foreground color to draw the arc sector
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The center of the circle
+		 * @param[in] radius	The radius of the circle
+		 * @param[in] sectors	Bits determine which sectors are drawn.
+		 * 						Bits go anti-clockwise from the 0 degree mark (y = 0, x is positive), as follows:
+		 *  						bit 0 - upper right right		  -----
+		 *  						bit 1 - upper upper right		 /2   1\
+		 *  						bit 2 - upper upper left		/3     0\
+		 *  						bit 3 - upper left  left		\4     7/
+		 *  						bit 4 - lower left  left		 \5   6/
+		 *  						bit 5 - lower lower left		  -----
+		 *  						bit 6 - lower lower right
+		 *  						bit 7 - lower left  left
+		 *
+		 * @api
+		 */
+		void gwinFillArcSectors(GHandle gh, coord_t x, coord_t y, coord_t radius, uint8_t sectors);
+	#endif
+
+/*-------------------------------------------------
+ * Pixel read-back functions
+ *-------------------------------------------------*/
+
+	#if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__)
+		/**
+		 * @brief   Get the color of a pixel in the window.
+		 * @return  The color of the pixel.
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The position in the window
+		 *
+		 * @api
+		 */
+		color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y);
+	#endif
+
+/*-------------------------------------------------
+ * Text functions
+ *-------------------------------------------------*/
+
+	#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
+		/**
+		 * @brief   Draw a text character at the specified position in the window.
+		 * @pre		The font must have been set.
+		 * @note	Uses the current foreground color to draw the character
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The position for the text
+		 * @param[in] c			The character to draw
+		 *
+		 * @api
+		 */
+		void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c);
+
+		/**
+		 * @brief   Draw a text character with a filled background at the specified position in the window.
+		 * @pre		The font must have been set.
+		 * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The position for the text
+		 * @param[in] c			The character to draw
+		 *
+		 * @api
+		 */
+		void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c);
+
+		/**
+		 * @brief   Draw a text string in the window
+		 * @pre		The font must have been set.
+		 * @note	Uses the current foreground color to draw the character
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The position for the text
+		 * @param[in] str		The string to draw
+		 *
+		 * @api
+		 */
+		void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str);
+
+		/**
+		 * @brief   Draw a text string with a filled background in the window
+		 * @pre		The font must have been set.
+		 * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The position for the text
+		 * @param[in] str		The string to draw
+		 *
+		 * @api
+		 */
+		void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str);
+
+		/**
+		 * @brief   Draw a text string verticly centered within the specified box.
+		 * @pre		The font must have been set.
+		 * @note	Uses the current foreground color to draw the character.
+		 * @note    The specified box does not need to align with the window box
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
+		 * @param[in] cx,cy		The width and height of the box
+		 * @param[in] str		The string to draw
+		 * @param[in] justify	Justify the text left, center or right within the box
+		 *
+		 * @api
+		 */
+		void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify);
+
+		/**
+		 * @brief   Draw a text string verticly centered within the specified filled box.
+		 * @pre		The font must have been set.
+		 * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
+		 * @note    The entire box is filled. Note this box does not need to align with the window box
+		 * @note	May leave GDISP clipping to this window's dimensions
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
+		 * @param[in] cx,cy		The width and height of the box
+		 * @param[in] str		The string to draw
+		 * @param[in] justify	Justify the text left, center or right within the box
+		 *
+		 * @api
+		 */
+		void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify);
+	#endif
+
+/*-------------------------------------------------
+ * Polygon functions
+ *-------------------------------------------------*/
+
+	#if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__)
+		/**
+		 * @brief   Draw an enclosed polygon (convex, non-convex or complex).
+		 *
+		 * @note	Uses the current foreground color.
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] tx, ty	Transform all points in pntarray by tx, ty
+		 * @param[in] pntarray	An array of points
+		 * @param[in] cnt		The number of points in the array
+		 *
+		 * @api
+		 */
+		void gwinDrawPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt);
+
+		/**
+		 * @brief   Fill a convex polygon
+		 * @details Doesn't handle non-convex or complex polygons.
+		 *
+		 * @note	Uses the current foreground color.
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] tx, ty	Transform all points in pntarray by tx, ty
+		 * @param[in] pntarray	An array of points
+		 * @param[in] cnt		The number of points in the array
+		 *
+		 * @note	Convex polygons are those that have no internal angles. That is;
+		 * 			you can draw a line from any point on the polygon to any other point
+		 * 			on the polygon without it going outside the polygon. In our case we generalise
+		 * 			this a little by saying that an infinite horizontal line (at any y value) will cross
+		 * 			no more than two edges on the polygon. Some non-convex polygons do fit this criteria
+		 * 			and can therefore be drawn.
+		 * @note	This routine is designed to be very efficient with even simple display hardware.
+		 *
+		 * @api
+		 */
+		void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt);
+	
+		/**
+		 * @brief	Draw a thick line in the window
+		 * @details	The line thickness is specified in pixels. The line ends can
+		 *		be selected to be either flat or round.
+		 * @note	Uses gdispGFillConvexPoly() internally to perform the drawing.
+		 * @note	Uses the current foreground color to draw the line
+		 * 
+		 * @param[in] gh		The window handle
+		 * @param[in] x0,y0		The start position
+		 * @param[in] x1,y1		The end position
+		 * @param[in] width		The width of the line
+		 * @param[in] round		Use round ends for the line
+		 * 
+		 * @api
+		 */
+		void gwinDrawThickLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t width, bool_t round);
+	#endif
+
+/*-------------------------------------------------
+ * Image functions
+ *-------------------------------------------------*/
+
+	#if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
+		/**
+		 * @brief	Draw the image
+		 * @return	GDISP_IMAGE_ERR_OK (0) on success or an error code.
+		 *
+		 * @param[in] gh		The window handle
+		 * @param[in] img   	The image structure
+		 * @param[in] x,y		The window location to draw the image
+		 * @param[in] cx,cy		The area on the screen to draw
+		 * @param[in] sx,sy		The image position to start drawing at
+		 *
+		 * @pre		gdispImageOpen() must have returned successfully.
+		 *
+		 * @note	If sx,sy + cx,cy is outside the image boundaries the area outside the image
+		 * 			is simply not drawn.
+		 * @note	If @p gdispImageCache() has been called first for this frame, this routine will draw using a
+		 * 			fast blit from the cached frame. If not, it reads the input and decodes it as it
+		 * 			is drawing. This may be significantly slower than if the image has been cached (but
+		 * 			uses a lot less RAM)
+		 *
+		 * @api
+		 */
+		gdispImageError gwinDrawImage(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
+	#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/*-------------------------------------------------
+ * Additional functionality
+ *-------------------------------------------------*/
+
+	/* Include widgets */
+	#if GWIN_NEED_WIDGET || defined(__DOXYGEN__)
+		#include "gwin_widget.h"
+	#endif
+
+	/* Include containers */
+	#if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__)
+		#include "gwin_container.h"
+	#endif
+
+	/* Include vanilla window objects */
+	#if GWIN_NEED_CONSOLE || defined(__DOXYGEN__)
+		#include "gwin_console.h"
+	#endif
+	#if GWIN_NEED_GRAPH || defined(__DOXYGEN__)
+		#include "gwin_graph.h"
+	#endif
+	#if GWIN_NEED_IMAGE || defined(__DOXYGEN__)
+		#include "gwin_image.h"
+	#endif
+	#if GWIN_NEED_GL3D || defined(__DOXYGEN__)
+		#include "gwin_gl3d.h"
+	#endif
+
+#endif /* GFX_USE_GWIN */
+
+#endif /* _GWIN_H */
+/** @} */
diff --git a/src/gwin/gwin.mk b/src/gwin/gwin.mk
new file mode 100644
index 00000000..23993346
--- /dev/null
+++ b/src/gwin/gwin.mk
@@ -0,0 +1,19 @@
+GFXSRC +=   $(GFXLIB)/src/gwin/gwin.c \
+			$(GFXLIB)/src/gwin/gwin_widget.c \
+			$(GFXLIB)/src/gwin/gwin_wm.c \
+			$(GFXLIB)/src/gwin/gwin_console.c \
+			$(GFXLIB)/src/gwin/gwin_graph.c \
+			$(GFXLIB)/src/gwin/gwin_button.c \
+			$(GFXLIB)/src/gwin/gwin_slider.c \
+			$(GFXLIB)/src/gwin/gwin_checkbox.c \
+			$(GFXLIB)/src/gwin/gwin_image.c \
+			$(GFXLIB)/src/gwin/gwin_label.c \
+			$(GFXLIB)/src/gwin/gwin_radio.c \
+			$(GFXLIB)/src/gwin/gwin_list.c \
+			$(GFXLIB)/src/gwin/gwin_progressbar.c \
+			$(GFXLIB)/src/gwin/gwin_container.c \
+			$(GFXLIB)/src/gwin/gwin_frame.c \
+			$(GFXLIB)/src/gwin/gwin_tabset.c \
+			$(GFXLIB)/src/gwin/gwin_gl3d.c \
+
+GFXINC +=	$(GFXLIB)/3rdparty/tinygl-0.4-ugfx/include	
diff --git a/src/gwin/gwin_console.h b/src/gwin/gwin_console.h
index 77e623eb..a21642aa 100644
--- a/src/gwin/gwin_console.h
+++ b/src/gwin/gwin_console.h
@@ -24,7 +24,7 @@
 #ifndef _GWIN_CONSOLE_H
 #define _GWIN_CONSOLE_H
 
-/* This file is included within "src/gwin/sys_defs.h" */
+/* This file is included within "src/gwin/gwin.h" */
 
 // A console window. Supports wrapped text writing and a cursor.
 typedef struct GConsoleObject {
diff --git a/src/gwin/gwin_container.h b/src/gwin/gwin_container.h
index 19562a7d..c40683db 100644
--- a/src/gwin/gwin_container.h
+++ b/src/gwin/gwin_container.h
@@ -21,7 +21,7 @@
 #ifndef _GCONTAINER_H
 #define _GCONTAINER_H
 
-/* This file is included within "src/gwin/sys_defs.h" */
+/* This file is included within "src/gwin/gwin.h" */
 
 // Forward definition
 struct GContainerObject;
diff --git a/src/gwin/gwin_gl3d.h b/src/gwin/gwin_gl3d.h
index 644f45bf..84ead5d9 100644
--- a/src/gwin/gwin_gl3d.h
+++ b/src/gwin/gwin_gl3d.h
@@ -22,7 +22,7 @@
 #ifndef _GWIN_GL3D_H
 #define _GWIN_GL3D_H
 
-/* This file is included within "src/gwin/sys_defs.h" */
+/* This file is included within "src/gwin/gwin.h" */
 
 
 // A gl3d window
diff --git a/src/gwin/gwin_graph.h b/src/gwin/gwin_graph.h
index eea80679..8355f494 100644
--- a/src/gwin/gwin_graph.h
+++ b/src/gwin/gwin_graph.h
@@ -22,7 +22,7 @@
 #ifndef _GWIN_GRAPH_H
 #define _GWIN_GRAPH_H
 
-/* This file is included within "src/gwin/sys_defs.h" */
+/* This file is included within "src/gwin/gwin.h" */
 
 typedef enum GGraphPointType_e {
 	GGRAPH_POINT_NONE, GGRAPH_POINT_DOT, GGRAPH_POINT_SQUARE, GGRAPH_POINT_CIRCLE
diff --git a/src/gwin/gwin_gwin.c b/src/gwin/gwin_gwin.c
deleted file mode 100644
index eb51b89a..00000000
--- a/src/gwin/gwin_gwin.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file	src/gwin/gwin_gwin.c
- * @brief	GWIN sub-system code
- */
-
-#include "gfx.h"
-
-#if GFX_USE_GWIN
-
-#include "gwin_class.h"
-
-#include <string.h>
-
-/*-----------------------------------------------
- * Data
- *-----------------------------------------------*/
-
-static const gwinVMT basegwinVMT = {
-		"GWIN",					// The classname
-		sizeof(GWindowObject),	// The object size
-		0,						// The destroy routine
-		0,						// The redraw routine
-		0,						// The after-clear routine
-};
-
-static color_t	defaultFgColor = White;
-static color_t	defaultBgColor = Black;
-#if GDISP_NEED_TEXT
-	static font_t	defaultFont;
-#endif
-
-/*-----------------------------------------------
- * Helper Routines
- *-----------------------------------------------*/
-
-/*-----------------------------------------------
- * Class Routines
- *-----------------------------------------------*/
-
-void _gwinInit(void)
-{
-	extern void _gwmInit(void);
-
-	_gwmInit();
-	#if GWIN_NEED_WIDGET
-		extern void _gwidgetInit(void);
-
-		_gwidgetInit();
-	#endif
-	#if GWIN_NEED_CONTAINERS
-		extern void _gcontainerInit(void);
-
-		_gcontainerInit();
-	#endif
-}
-
-void _gwinDeinit(void)
-{
-	extern void _gwmDeinit(void);
-
-	#if GWIN_NEED_CONTAINERS
-		extern void _gcontainerDeinit(void);
-
-		_gcontainerDeinit();
-	#endif
-	#if GWIN_NEED_WIDGET
-		extern void _gwidgetDeinit(void);
-
-		_gwidgetDeinit();
-	#endif
-
-	_gwmDeinit();
-}
-
-// Internal routine for use by GWIN components only
-// Initialise a window creating it dynamically if required.
-GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint32_t flags) {
-	// Allocate the structure if necessary
-	if (!pgw) {
-		if (!(pgw = gfxAlloc(vmt->size)))
-			return 0;
-		pgw->flags = flags|GWIN_FLG_DYNAMIC;
-	} else
-		pgw->flags = flags;
-	
-	// Initialise all basic fields
-	pgw->display = g;
-	pgw->vmt = vmt;
-	pgw->color = defaultFgColor;
-	pgw->bgcolor = defaultBgColor;
-	#if GDISP_NEED_TEXT
-		pgw->font = defaultFont;
-	#endif
-
-	// Make sure we don't create nasty problems for ourselves
-	if (vmt->size > sizeof(GWindowObject))
-		memset(pgw+1, 0, vmt->size - sizeof(GWindowObject));
-
-	if (!_gwinWMAdd(pgw, pInit)) {
-		if ((pgw->flags & GWIN_FLG_DYNAMIC))
-			gfxFree(pgw);
-		return 0;
-	}
-
-	return (GHandle)pgw;
-}
-
-// Internal routine for use by GWIN components only
-void _gwinDestroy(GHandle gh, GRedrawMethod how) {
-	if (!gh)
-		return;
-
-	// Make the window invisible
-	gwinSetVisible(gh, FALSE);
-
-	// Make sure it is flushed first - must be REDRAW_WAIT or REDRAW_INSESSION
-	_gwinFlushRedraws(how);
-
-	#if GWIN_NEED_CONTAINERS
-		// Notify the parent it is about to be deleted
-		if (gh->parent && ((gcontainerVMT *)gh->parent->vmt)->NotifyDelete)
-			((gcontainerVMT *)gh->parent->vmt)->NotifyDelete(gh->parent, gh);
-	#endif
-
-	// Remove from the window manager
-	#if GWIN_NEED_WINDOWMANAGER
-		_GWINwm->vmt->Delete(gh);
-	#endif
-
-	// Class destroy routine
-	if (gh->vmt->Destroy)
-		gh->vmt->Destroy(gh);
-
-	// Clean up the structure
-	if (gh->flags & GWIN_FLG_DYNAMIC) {
-		gh->flags = 0;							// To be sure, to be sure
-		gfxFree((void *)gh);
-	} else
-		gh->flags = 0;							// To be sure, to be sure
-}
-
-/*-----------------------------------------------
- * Routines that affect all windows
- *-----------------------------------------------*/
-
-void gwinClearInit(GWindowInit *pwi) {
-	char		*p;
-	unsigned	len;
-
-	for(p = (char *)pwi, len = sizeof(GWindowInit); len; len--)
-		*p++ = 0;
-}
-
-void gwinSetDefaultColor(color_t clr) {
-	defaultFgColor = clr;
-}
-
-color_t gwinGetDefaultColor(void) {
-	return defaultFgColor;
-}
-
-void gwinSetDefaultBgColor(color_t bgclr) {
-	defaultBgColor = bgclr;
-}
-
-color_t gwinGetDefaultBgColor(void) {
-	return defaultBgColor;
-}
-
-#if GDISP_NEED_TEXT
-	void gwinSetDefaultFont(font_t font) {
-		defaultFont = font;
-	}
-
-	font_t gwinGetDefaultFont(void) {
-		return defaultFont;
-	}
-#endif
-
-/*-----------------------------------------------
- * The GWindow Routines
- *-----------------------------------------------*/
-
-GHandle gwinGWindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit) {
-	if (!(pgw = _gwindowCreate(g, pgw, pInit, &basegwinVMT, 0)))
-		return 0;
-
-	gwinSetVisible(pgw, pInit->show);
-
-	return pgw;
-}
-
-void gwinDestroy(GHandle gh) {
-	_gwinDestroy(gh, REDRAW_WAIT);
-}
-
-const char *gwinGetClassName(GHandle gh) {
-	return gh->vmt->classname;
-}
-
-bool_t gwinGetVisible(GHandle gh) {
-	return (gh->flags & GWIN_FLG_SYSVISIBLE) ? TRUE : FALSE;
-}
-
-bool_t gwinGetEnabled(GHandle gh) {
-	return (gh->flags & GWIN_FLG_SYSENABLED) ? TRUE : FALSE;
-}
-
-#if GDISP_NEED_TEXT
-	void gwinSetFont(GHandle gh, font_t font) {
-		gh->font = font;
-	}
-#endif
-
-void gwinClear(GHandle gh) {
-	/*
-	 * Don't render anything when the window is not visible but 
-	 * still call the AfterClear() routine as some widgets will
-	 * need this to clear internal buffers or similar
-	 */
-	if (_gwinDrawStart(gh)) {
-		gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
-		_gwinDrawEnd(gh);
-	}
-	if (gh->vmt->AfterClear)
-		gh->vmt->AfterClear(gh);
-}
-
-void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {
-	if (!_gwinDrawStart(gh)) return;
-	gdispGDrawPixel(gh->display, gh->x+x, gh->y+y, gh->color);
-	_gwinDrawEnd(gh);
-}
-
-void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) {
-	if (!_gwinDrawStart(gh)) return;
-	gdispGDrawLine(gh->display, gh->x+x0, gh->y+y0, gh->x+x1, gh->y+y1, gh->color);
-	_gwinDrawEnd(gh);
-}
-
-void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
-	if (!_gwinDrawStart(gh)) return;
-	gdispGDrawBox(gh->display, gh->x+x, gh->y+y, cx, cy, gh->color);
-	_gwinDrawEnd(gh);
-}
-
-void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
-	if (!_gwinDrawStart(gh)) return;
-	gdispGFillArea(gh->display, gh->x+x, gh->y+y, cx, cy, gh->color);
-	_gwinDrawEnd(gh);
-}
-
-void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
-	if (!_gwinDrawStart(gh)) return;
-	gdispGBlitArea(gh->display, gh->x+x, gh->y+y, cx, cy, srcx, srcy, srccx, buffer);
-	_gwinDrawEnd(gh);
-}
-
-#if GDISP_NEED_CIRCLE
-	void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGDrawCircle(gh->display, gh->x+x, gh->y+y, radius, gh->color);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGFillCircle(gh->display, gh->x+x, gh->y+y, radius, gh->color);
-		_gwinDrawEnd(gh);
-	}
-#endif
-
-#if GDISP_NEED_ELLIPSE
-	void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGDrawEllipse(gh->display, gh->x+x, gh->y+y, a, b, gh->color);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGFillEllipse(gh->display, gh->x+x, gh->y+y, a, b, gh->color);
-		_gwinDrawEnd(gh);
-	}
-#endif
-
-#if GDISP_NEED_ARC
-	void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGDrawArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGFillArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color);
-		_gwinDrawEnd(gh);
-	}
-#endif
-
-#if GDISP_NEED_ARCSECTORS
-	void gwinDrawArcSectors(GHandle gh, coord_t x, coord_t y, coord_t radius, uint8_t sectors) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGDrawArcSectors(gh->display, gh->x+x, gh->y+y, radius, sectors, gh->color);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinFillArcSectors(GHandle gh, coord_t x, coord_t y, coord_t radius, uint8_t sectors) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGFillArcSectors(gh->display, gh->x+x, gh->y+y, radius, sectors, gh->color);
-		_gwinDrawEnd(gh);
-	}
-#endif
-
-#if GDISP_NEED_PIXELREAD
-	color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y) {
-		if (!_gwinDrawStart(gh)) return (color_t)0;
-		return gdispGGetPixelColor(gh->display, gh->x+x, gh->y+y);
-		_gwinDrawEnd(gh);
-	}
-#endif
-
-#if GDISP_NEED_TEXT
-	void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c) {
-		if (!gh->font || !_gwinDrawStart(gh)) return;
-		gdispGDrawChar(gh->display, gh->x+x, gh->y+y, c, gh->font, gh->color);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c) {
-		if (!gh->font || !_gwinDrawStart(gh)) return;
-		gdispGFillChar(gh->display, gh->x+x, gh->y+y, c, gh->font, gh->color, gh->bgcolor);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str) {
-		if (!gh->font || !_gwinDrawStart(gh)) return;
-		gdispGDrawString(gh->display, gh->x+x, gh->y+y, str, gh->font, gh->color);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str) {
-		if (!gh->font || !_gwinDrawStart(gh)) return;
-		gdispGFillString(gh->display, gh->x+x, gh->y+y, str, gh->font, gh->color, gh->bgcolor);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
-		if (!gh->font || !_gwinDrawStart(gh)) return;
-		gdispGDrawStringBox(gh->display, gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, justify);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
-		if (!gh->font || !_gwinDrawStart(gh)) return;
-		gdispGFillStringBox(gh->display, gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, gh->bgcolor, justify);
-		_gwinDrawEnd(gh);
-	}
-#endif
-
-#if GDISP_NEED_CONVEX_POLYGON
-	void gwinDrawPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGDrawPoly(gh->display, tx+gh->x, ty+gh->y, pntarray, cnt, gh->color);
-		_gwinDrawEnd(gh);
-	}
-
-	void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGFillConvexPoly(gh->display, tx+gh->x, ty+gh->y, pntarray, cnt, gh->color);
-		_gwinDrawEnd(gh);
-	}
-	void gwinDrawThickLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t width, bool_t round) {
-		if (!_gwinDrawStart(gh)) return;
-		gdispGDrawThickLine(gh->display, gh->x+x0, gh->y+y0, gh->x+x1, gh->y+y1, gh->color, width, round);
-		_gwinDrawEnd(gh);
-	}
-#endif
-
-#if GDISP_NEED_IMAGE
-	gdispImageError gwinDrawImage(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
-		gdispImageError		ret;
-
-		if (!_gwinDrawStart(gh)) return GDISP_IMAGE_ERR_OK;
-		ret = gdispGImageDraw(gh->display, img, gh->x+x, gh->y+y, cx, cy, sx, sy);
-		_gwinDrawEnd(gh);
-		return ret;
-	}
-#endif
-
-#endif /* GFX_USE_GWIN */
-/** @} */
-
diff --git a/src/gwin/gwin_image.h b/src/gwin/gwin_image.h
index 2e0a3218..5def4037 100644
--- a/src/gwin/gwin_image.h
+++ b/src/gwin/gwin_image.h
@@ -27,7 +27,7 @@
 #ifndef _GWIN_IMAGE_H
 #define _GWIN_IMAGE_H
 
-// This file is included within "src/gwin/sys_defs.h"
+// This file is included within "src/gwin/gwin.h"
 
 // An image window
 typedef struct GImageObject {
diff --git a/src/gwin/gwin_options.h b/src/gwin/gwin_options.h
new file mode 100644
index 00000000..9252e67a
--- /dev/null
+++ b/src/gwin/gwin_options.h
@@ -0,0 +1,334 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gwin/gwin_options.h
+ * @brief   GWIN sub-system options header file.
+ *
+ * @addtogroup GWIN
+ * @brief	The GWIN module uses all the other modules (GDISP, GINPUT, GTIMER...) to
+ *			form a complete GUI toolkit.
+ * 
+ * @{
+ */
+
+#ifndef _GWIN_OPTIONS_H
+#define _GWIN_OPTIONS_H
+
+/**
+ * @name    GWIN Functionality to be included
+ * @{
+ */
+	/**
+	 * @brief   Should window manager support be included
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_WINDOWMANAGER
+		#define GWIN_NEED_WIDGET	FALSE
+	#endif
+	/**
+	 * @brief	Should the widget hierarchy be included. This provides parent-child features.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_CONTAINERS
+		#define GWIN_NEED_CONTAINERS	FALSE
+	#endif
+	/**
+	 * @brief   Should widget functions be included. Needed for any widget (eg Buttons, Sliders etc)
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_WIDGET
+		#define GWIN_NEED_WIDGET	FALSE
+	#endif
+	/**
+	 * @brief	Should the simple container be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_CONTAINER
+		#define GWIN_NEED_CONTAINER		FALSE
+	#endif
+	/**
+	 * @brief	Should the frame widget be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_FRAME
+		#define GWIN_NEED_FRAME		FALSE
+	#endif
+	/**
+	 * @brief   Should console functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_CONSOLE
+		#define GWIN_NEED_CONSOLE	FALSE
+	#endif
+	/**
+	 * @brief   Should graph functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_GRAPH
+		#define GWIN_NEED_GRAPH		FALSE
+	#endif
+	/**
+	 * @brief   Should gl3d functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_GL3D
+		#define GWIN_NEED_GL3D		FALSE
+	#endif
+	/**
+	 * @brief   Should button functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_BUTTON
+		#define GWIN_NEED_BUTTON	FALSE
+	#endif
+	/**
+	 * @brief   Should progressbar functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_PROGRESSBAR
+		#define GWIN_NEED_PROGRESSBAR	FALSE
+	#endif
+	/**
+	 * @brief   Should slider functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_SLIDER
+		#define GWIN_NEED_SLIDER	FALSE
+	#endif
+	/**
+	 * @brief   Should checkbox functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_CHECKBOX
+		#define GWIN_NEED_CHECKBOX	FALSE
+	#endif
+	/**
+	 * @brief   Should image functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_IMAGE
+		#define GWIN_NEED_IMAGE		FALSE
+	#endif
+	/**
+	 * @brief   Should label functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_LABEL
+		#define GWIN_NEED_LABEL		FALSE
+	#endif
+	/**
+	 * @brief   Should radio button functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_RADIO
+		#define GWIN_NEED_RADIO		FALSE
+	#endif
+	/**
+	 * @brief   Should tabset functions be included.
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_TABSET
+		#define GWIN_NEED_TABSET	FALSE
+	#endif
+/**
+ * @}
+ *
+ * @name    GWIN Optional Parameters
+ * @{
+ */
+	/**
+	 * @brief   Add a tag to each widget
+	 * @details	Defaults to FALSE
+	 * @note	Adds a tag member to each widget. Any events created include this tag.
+	 * 			The enables switch based application logic to detect the event source.
+	 */
+	#ifndef GWIN_WIDGET_TAGS
+		#define GWIN_WIDGET_TAGS		FALSE
+	#endif
+	/**
+	 * @brief   Use flat styling for controls rather than a 3D look
+	 * @details	Defaults to FALSE
+	 * @note	This may appear better on color-restricted displays
+	 * @note	Flat styling is less graphics and cpu intensive (marginally) than the default 3D look.
+	 */
+	#ifndef GWIN_FLAT_STYLING
+		#define GWIN_FLAT_STYLING		FALSE
+	#endif
+	/**
+	 * @brief	Don't use a timer for redrawing windows
+	 * @details	Defaults to FALSE
+	 * @note	Normally windows and widgets are redrawn on a timer. Setting this
+	 * 			option causes them to be redrawn immediately. Note that this can
+	 * 			cause extended blocking times on events and saves little code.
+	 * @note	If GWIN_NEED_WINDOWMANAGER is FALSE then this setting is ignored
+	 * 			as redrawing always occurs immediately.
+	 */
+	#ifndef GWIN_REDRAW_IMMEDIATE
+		#define GWIN_REDRAW_IMMEDIATE	FALSE
+	#endif
+	/**
+	 * @brief	Redraw all windows in a single operation
+	 * @details	Defaults to FALSE
+	 * @note	Windows are normally redraw one per gtimer cycle.
+	 * 			Setting this option causes all windows to be redrawn in
+	 * 			a single gtimer cycle. Note that this can
+	 * 			cause extended blocking times on the timer thread but may
+	 * 			speed up redraw slightly.
+	 * @note	This is only relevant if GWIN_REDRAW_IMMEDIATE is FALSE.
+	 * 			Everything always gets redrawn in a single operation if
+	 * 			GWIN_REDRAW_IMMEDIATE is TRUE.
+	 */
+	#ifndef GWIN_REDRAW_SINGLEOP
+		#define GWIN_REDRAW_SINGLEOP	FALSE
+	#endif
+	/**
+	 * @brief   Buttons should not insist the mouse is over the button on mouse release
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_BUTTON_LAZY_RELEASE
+		#define GWIN_BUTTON_LAZY_RELEASE		FALSE
+	#endif
+	/**
+	 * @brief	Should the content of the console be saved for redrawing.
+	 * @details	Defaults to FALSE
+	 * @details	If this feature is enabled, the contents of the console will be saved
+	 * 			as it is written. If a redraw is required it will be redrawn from the
+	 * 			history. Scrolling will also use the history buffer if it is turned on.
+	 * @note	Using this option allocates the amount of memory to store the
+	 * 			history based on the minimum character width in the current font
+	 * 			at the time the history is turned on. Using a fixed width font is a good
+	 * 			idea to minimize memory usage.
+	 * @note	If you change the size of the window or you change the font being displayed
+	 * 			you should turn off the history and then turn it back on in order to get
+	 * 			a new buffer of the correct size for the window/font combination. Strange
+	 * 			redrawing and scrolling effects can occur if the buffer is too small to
+	 * 			save a complete screen of data. Note the system tries to optimize storage
+	 * 			so this may only be evident in very limited situations eg with a console
+	 * 			with many characters in it.
+	 * @note	@p gwinConsoleSetBuffer() can be used to turn the history buffer off and on.
+	 */
+	#ifndef GWIN_CONSOLE_USE_HISTORY
+		#define GWIN_CONSOLE_USE_HISTORY		FALSE
+	#endif
+	/**
+	 * @brief	Use font width averaging for the history buffer allocation.
+	 * @details	Defaults to FALSE
+	 * @details	If this feature is enabled, the width one third of the way between
+	 * 			the font's character width minimum and maximum will be used instead
+	 * 			of the font's minimum width.
+	 * @note	This option reduces the memory allocation for a variable width font's
+	 * 			history buffer. Note that strange
+	 * 			redrawing and scrolling effects can occur if the buffer is too small to
+	 * 			save a complete screen of data. The system tries to optimize storage
+	 * 			so this may only be evident in very limited situations eg with a console
+	 * 			with many characters in it.
+	 */
+	#ifndef GWIN_CONSOLE_HISTORY_AVERAGING
+		#define GWIN_CONSOLE_HISTORY_AVERAGING	FALSE
+	#endif
+	/**
+	 * @brief	Should the history be turned on for all console windows when they are first created.
+	 * @details	Defaults to FALSE
+	 * @note	@p gwinConsoleSetBuffer() can be used to turn the history buffer off and on at
+	 * 			any time.
+	 */
+	#ifndef GWIN_CONSOLE_HISTORY_ATCREATE
+		#define GWIN_CONSOLE_HISTORY_ATCREATE	FALSE
+	#endif
+	/**
+	 * @brief   Console Windows need floating point support in @p gwinPrintf
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_CONSOLE_USE_FLOAT
+		#define GWIN_CONSOLE_USE_FLOAT			FALSE
+	#endif
+	/**
+	 * @brief   Console windows support escape sequences to control display
+	 * @details	Defaults to FALSE
+	 *
+	 * @note
+	 * 		Currently supported:
+	 * 			ESC color		Change subsequent text color
+	 * 							color:	"0" = black, "1" = red, "2" = green, "3" = yellow, "4" = blue,
+	 * 									"5" = magenta, "6" = cyan, "7" = white
+	 * 			ESC C			Revert subsequent text color to the window default
+	 * 			ESC u			Turn on underline
+	 * 			ESC U			Turn off underline
+	 * 			ESC b			Turn on bold
+	 * 			ESC B			Turn off bold
+	 * 			ESC J			Clear the window
+	 */
+	#ifndef GWIN_CONSOLE_ESCSEQ
+		#define GWIN_CONSOLE_ESCSEQ				FALSE
+	#endif
+	/**
+	 * @brief   Console Windows need BaseStreamSequential support (ChibiOS only)
+	 * @details	Defaults to FALSE
+	 * @note	To use the ChibiOS basestream functions such as chprintf()
+	 * 			for printing in a console window you need to set this option to
+	 * 			TRUE in your gfxconf.h and include in your application source file...
+	 * 			\#include "chprintf.h"
+	 * 			In your makefile, as part of your list of C source files, include
+	 * 			${CHIBIOS}/os/various/chprintf.c
+	 */
+	#ifndef GWIN_CONSOLE_USE_BASESTREAM
+		#define GWIN_CONSOLE_USE_BASESTREAM		FALSE
+	#endif
+	/**
+	 * @brief   Image windows can optionally support animated images
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_NEED_IMAGE_ANIMATION
+		#define GWIN_NEED_IMAGE_ANIMATION		FALSE
+	#endif
+	/**
+	 * @brief	Enable the API to automatically increment the progressbar over time
+	 * @details	Defaults to FALSE
+	 */
+	#ifndef GWIN_PROGRESSBAR_AUTO
+	 	#define GWIN_PROGRESSBAR_AUTO			FALSE
+	#endif
+	/**
+	 * @brief	Should the slider avoid snapping to a fixed position when the mouse is released
+	 * @details	Defaults to FALSE
+	 * @note	If FALSE the slider will snap to the closest set-able position when the
+	 * 			mouse is released. If TRUE it will maintain the position the
+	 * 			mouse was released at, except when at the minimum and maximum slider values.
+	 */
+	#ifndef GWIN_SLIDER_NOSNAP
+	 	#define GWIN_SLIDER_NOSNAP				FALSE
+	#endif
+	/**
+	 * @brief	The number of pixels of dead-band at each end of the slider
+	 * @details	Defaults to 5
+	 * @note	A dead-band is required because fingers can often cannot
+	 * 			accurately control the slider peg at the edges of the slider
+	 */
+	#ifndef GWIN_SLIDER_DEAD_BAND
+		#define GWIN_SLIDER_DEAD_BAND			5
+	#endif
+	/**
+	 * @brief	How many toggles it takes to go from minimum to maximum value on a slider
+	 * @details	Defaults to 20
+	 * @note	When the slider is being operated by a toggle device this setting describes
+	 * 			how many toggles are required to go from end to end.
+	 */
+	#ifndef GWIN_SLIDER_TOGGLE_INC
+		#define GWIN_SLIDER_TOGGLE_INC			20
+	#endif
+	/**
+	 * @brief	The height in pixels of a row of tabs in a tabset
+	 * @details	Defaults to 18
+	 */
+	#ifndef GWIN_TABSET_TABHEIGHT
+		#define GWIN_TABSET_TABHEIGHT			18
+	#endif
+/** @} */
+
+#endif /* _GWIN_OPTIONS_H */
+/** @} */
diff --git a/src/gwin/gwin_rules.h b/src/gwin/gwin_rules.h
new file mode 100644
index 00000000..8d8ef2cc
--- /dev/null
+++ b/src/gwin/gwin_rules.h
@@ -0,0 +1,129 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ *              http://ugfx.org/license.html
+ */
+
+/**
+ * @file    src/gwin/gwin_rules.h
+ * @brief   GWIN safety rules header file.
+ *
+ * @addtogroup GWIN
+ * @{
+ */
+
+#ifndef _GWIN_RULES_H
+#define _GWIN_RULES_H
+
+#if GFX_USE_GWIN
+	// Sub-system rules
+	#if !GFX_USE_GDISP
+		#error "GWIN: GFX_USE_GDISP must be TRUE when using GWIN"
+	#endif
+	#if !GDISP_NEED_CLIP
+		#if GFX_DISPLAY_RULE_WARNINGS
+			#warning "GWIN: Drawing can occur outside the defined windows as GDISP_NEED_CLIP is FALSE"
+		#endif
+	#endif
+
+	// Objects require their super-class
+	#if GWIN_NEED_TABSET || GWIN_NEED_FRAME || GWIN_NEED_CONTAINER
+		#if !GWIN_NEED_CONTAINERS
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GWIN: GWIN_NEED_CONTAINERS is required when a container is enabled. It has been turned on for you."
+			#endif
+			#undef GWIN_NEED_CONTAINERS
+			#define GWIN_NEED_CONTAINERS	TRUE
+		#endif
+	#endif
+	#if GWIN_NEED_BUTTON || GWIN_NEED_SLIDER || GWIN_NEED_CHECKBOX || GWIN_NEED_LABEL || GWIN_NEED_RADIO || GWIN_NEED_LIST || \
+		GWIN_NEED_IMAGE || GWIN_NEED_CHECKBOX || GWIN_NEED_PROGRESSBAR 
+		#if !GWIN_NEED_WIDGET
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GWIN: GWIN_NEED_WIDGET is required when a widget is used. It has been turned on for you."
+			#endif
+			#undef GWIN_NEED_WIDGET
+			#define GWIN_NEED_WIDGET	TRUE
+		#endif
+	#endif
+
+	// Rules for the super-classes
+	#if GWIN_NEED_CONTAINERS
+		#if !GWIN_NEED_WIDGET
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GWIN: GWIN_NEED_WIDGET is required when GWIN_NEED_CONTAINERS is enabled. It has been turned on for you."
+			#endif
+			#undef GWIN_NEED_WIDGET
+			#define GWIN_NEED_WIDGET	TRUE
+		#endif
+	#endif
+	#if GWIN_NEED_WIDGET
+		#if !GDISP_NEED_TEXT
+			#error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_WIDGET is TRUE."
+		#endif
+		#if !GFX_USE_GINPUT
+			// This test also ensures that GFX_USE_GEVENT is set
+			#error "GWIN: GFX_USE_GINPUT (and one or more input sources) is required if GWIN_NEED_WIDGET is TRUE"
+		#endif
+		#if !GWIN_NEED_WINDOWMANAGER
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GWIN: GWIN_NEED_WINDOWMANAGER is required if GWIN_NEED_WIDGET is TRUE. It has been turned on for you."
+			#endif
+			#undef GWIN_NEED_WINDOWMANAGER
+			#define GWIN_NEED_WINDOWMANAGER	TRUE
+		#endif
+		#if !GDISP_NEED_MULTITHREAD
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GWIN: GDISP_NEED_MULTITHREAD is required if GWIN_NEED_WIDGET is TRUE. It has been turned on for you"
+			#endif
+			#undef GDISP_NEED_MULTITHREAD
+			#define GDISP_NEED_MULTITHREAD	TRUE
+		#endif
+	#endif
+	#if GWIN_NEED_WINDOWMANAGER
+		#if !GFX_USE_GQUEUE || !GQUEUE_NEED_ASYNC
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GWIN: GFX_USE_GQUEUE and GQUEUE_NEED_ASYNC is required if GWIN_NEED_WINDOWMANAGER is TRUE. It has been turned on for you."
+			#endif
+			#undef GFX_USE_GQUEUE
+			#undef GQUEUE_NEED_ASYNC
+			#define GFX_USE_GQUEUE		TRUE
+			#define GQUEUE_NEED_ASYNC	TRUE
+		#endif
+		#if !GFX_USE_GTIMER
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GWIN: GFX_USE_GTIMER is required if GWIN_NEED_WINDOWMANAGER is TRUE. It has been turned on for you."
+			#endif
+			#undef GFX_USE_GTIMER
+			#define GFX_USE_GTIMER		TRUE
+		#endif
+	#endif
+
+	// Rules for individual objects
+	#if GWIN_NEED_LIST
+		#if !GDISP_NEED_TEXT
+			#error "GWIN: GDISP_NEED_TEXT is required when GWIN_NEED_LIST is TRUE."
+		#endif
+	#endif
+	#if GWIN_NEED_RADIO
+		#if !GDISP_NEED_CIRCLE
+			#if GFX_DISPLAY_RULE_WARNINGS
+				#warning "GWIN: GDISP_NEED_CIRCLE should be set to TRUE for much nicer radio button widgets."
+			#endif
+		#endif
+	#endif
+	#if GWIN_NEED_IMAGE
+		#if !GDISP_NEED_IMAGE
+			#error "GWIN: GDISP_NEED_IMAGE is required when GWIN_NEED_IMAGE is TRUE."
+		#endif
+	#endif
+	#if GWIN_NEED_CONSOLE
+		#if !GDISP_NEED_TEXT
+			#error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_CONSOLE is TRUE."
+		#endif
+	#endif
+#endif
+
+#endif /* _GWIN_RULES_H */
+/** @} */
diff --git a/src/gwin/gwin_widget.h b/src/gwin/gwin_widget.h
index c6bc6d4c..63d73e77 100644
--- a/src/gwin/gwin_widget.h
+++ b/src/gwin/gwin_widget.h
@@ -23,7 +23,7 @@
 #ifndef _GWIDGET_H
 #define _GWIDGET_H
 
-/* This file is included within "src/gwin/sys_defs.h" */
+/* This file is included within "src/gwin/gwin.h" */
 
 // Forward definition
 struct GWidgetObject;
diff --git a/src/gwin/sys_defs.h b/src/gwin/sys_defs.h
deleted file mode 100644
index afab138c..00000000
--- a/src/gwin/sys_defs.h
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gwin/sys_defs.h
- *
- * @defgroup Window Window
- * @ingroup Windows
- *
- * @details		GWIN provides a basic window manager which allows it to easily
- *				create and destroy different windows at runtime. Each window
- *				will have it's own properties such as colors as well as
- *				it's own drawing origin.
- *
- * @pre		GFX_USE_GWIN must be set to TRUE in your gfxconf.h
- * @{
- */
-
-#ifndef _GWIN_H
-#define _GWIN_H
-
-#include "gfx.h"
-
-#if GFX_USE_GWIN || defined(__DOXYGEN__)
-
-/* Forward declaration */
-typedef struct GWindowObject *GHandle;
-
-/**
- * @brief	A window object structure
- * @note	Do not access the members directly. Treat it as a black-box and use the method functions.
- * @{
- */
-typedef struct GWindowObject {
-	#if GWIN_NEED_WINDOWMANAGER
-		// This MUST be the first member of the structure
-		gfxQueueASyncItem	wmq;				// @< The next window (for the window manager)
-	#endif
-	const struct gwinVMT	*vmt;				// @< The VMT for this GWIN
-	GDisplay *				display;			// @< The display this window is on.
-	coord_t					x, y;				// @< Screen relative position
-	coord_t					width, height;		// @< Dimensions of this window
-	color_t					color, bgcolor;		// @< The current drawing colors
-	uint32_t				flags;				// @< Window flags (the meaning is private to the GWIN class)
-	#if GDISP_NEED_TEXT
-		font_t				font;				// @< The current font
-	#endif
-	#if GWIN_NEED_CONTAINERS
-		GHandle				parent;				// @< The parent window
-	#endif
-} GWindowObject, * GHandle;
-/** @} */
-
-/**
- * @brief	The structure to initialise a GWIN.
- *
- * @note	Some gwin's will need extra parameters.
- * @note	The dimensions and position may be changed to fit on the real screen.
- * @note	If you create this structure on the stack, you should always memset
- * 			it to all zero's first in case a future version of the software
- * 			add's extra fields. Alternatively you can use @p gwinClearInit()
- * 			to clear it.
- *
- * @{
- */
-typedef struct GWindowInit {
-	coord_t			x, y;							// @< The initial position relative to its parent
-	coord_t			width, height;					// @< The initial dimension
-	bool_t			show;							// @< Should the window be visible initially
-	#if GWIN_NEED_CONTAINERS
-		GHandle		parent;							// @< The parent - must be a container or NULL
-	#endif
-} GWindowInit;
-/** @} */
-
-/**
- * @brief	A window's minimized, maximized or normal size
- */
-typedef enum { GWIN_NORMAL, GWIN_MAXIMIZE, GWIN_MINIMIZE } GWindowMinMax;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*-------------------------------------------------
- * Window Manager functions
- *-------------------------------------------------*/
-
-#if GWIN_NEED_WINDOWMANAGER || defined(__DOXYGEN__)
-	// Forward definition
-	struct GWindowManager;
-
-	/**
-	 * @brief   Set the window manager for the GWIN system.
-	 *
-	 * @param[in] gwm		The window manager to use. Can be NULL to turn off the existing window manager.
-	 *
-	 * @note				A window manager is responsible for handling when window visibility is changed or
-	 * 						a window is resized for moved. Note that only saved window states will be redrawn. Each
-	 * 						window type can save different information (or none at all). See the documentation on each window
-	 * 						type to see which information it saves (and can therefore be automatically redrawn).
-	 * 						For window types that do not save any state information, the window manager determines what to do.
-	 * 						Generally it will just clear the window to its background color.
-	 *
-	 * @api
-	 */
-	void gwinSetWindowManager(struct GWindowManager *gwm);
-#endif
-
-/*-------------------------------------------------
- * Functions that affect all windows
- *-------------------------------------------------*/
-
-	/**
-	 * @brief	Clear a GWindowInit structure to all zero's
-	 * @note	This function is provided just to prevent problems
-	 * 			on operating systems where using memset() causes issues
-	 * 			in the users application.
-	 *
-	 * @param[in] pwi	The GWindowInit structure to clear
-	 *
-	 * @api
-	 */
-	void gwinClearInit(GWindowInit *pwi);
-
-	/**
-	 * @brief	Set the default foreground color for all new GWIN windows
-	 *
-	 * @param[in] clr	The color to be set
-	 *
-	 * @api
-	 */
-	void gwinSetDefaultColor(color_t clr);
-
-	/**
-	 * @brief	Get the default foreground color for all new GWIN windows
-	 *
-	 * @return	The current default color for all new GWIN windows
-	 *
-	 * @api
-	 */
-	color_t gwinGetDefaultColor(void);
-
-	/**
-	 * @brief	Set the default background color for all new GWIN windows
-	 *
-	 * @param[in] bgclr	The background color
-	 *
-	 * @api
-	 */
-	void gwinSetDefaultBgColor(color_t bgclr);
-
-	/**
-	 * @brief	Get the default background color for all new GWIN windows
-	 *
-	 * @return	The current default background color for all new GWIN windows
-	 *
-	 * @api
-	 */
-	color_t gwinGetDefaultBgColor(void);
-
-	#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
-		/**
-		 * @brief	Set the default font for all new GWIN windows
-		 *
-		 * @param[in] font	The new font to be set
-		 *
-		 * @api
-		 */
-		void gwinSetDefaultFont(font_t font);
-
-		/**
-		 * @brief	Get the current default font
-		 *
-		 * @return	The current default font
-		 *
-		 * @api
-		 */
-		font_t gwinGetDefaultFont(void);
-	#endif
-
-/*-------------------------------------------------
- * Base functions
- *-------------------------------------------------*/
-
-	/**
-	 * @brief   Create a basic window.
-	 * @return  NULL if there is no resultant drawing area, otherwise a window handle.
-	 *
-	 * @param[in] g			The GDisplay to display this window on
-	 * @param[in] pgw		The window structure to initialize. If this is NULL the structure is dynamically allocated.
-	 * @param[in] pInit		How to initialise the window
-	 *
-	 * @note				The drawing color and the background color get set to the current defaults. If you haven't called
-	 * 						@p gwinSetDefaultColor() or @p gwinSetDefaultBgColor() then these are White and Black respectively.
-	 * @note				The font gets set to the current default font. If you haven't called @p gwinSetDefaultFont() then there
-	 * 						is no default font and text drawing operations will no nothing.
-	 * @note				A basic window does not save the drawing state. It is not automatically redrawn if the window is moved or
-	 * 						its visibility state is changed.
-	 *
-	 * @api
-	 */
-	GHandle gwinGWindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit);
-	#define gwinWindowCreate(pgw, pInit)		gwinGWindowCreate(GDISP, pgw, pInit);
-
-	/**
-	 * @brief   Destroy a window (of any type). Releases any dynamically allocated memory.
-	 *
-	 * @param[in] gh		The window handle
-	 *
-	 * @api
-	 */
-	void gwinDestroy(GHandle gh);
-
-	/**
-	 * @brief	Get the real class name of the GHandle
-	 * @details	Returns a string describing the object class.
-	 *
-	 * @param[in] gh	The window
-	 *
-	 * @return	A string describing the object class.
-	 *
-	 * @api
-	 */
-	const char* gwinGetClassName(GHandle gh);
-
-	/**
-	 * @brief	Get an ID that uniquely describes the class of the GHandle
-	 *
-	 * @param[in] gh	The window
-	 *
-	 * @api
-	 */
-	#define gwinGetClassID(gh)		((void *)((gh)->vmt))
-
-	/**
-	 * @brief	Get the X coordinate of the window
-	 * @details	Returns the X coordinate of the origin of the window.
-	 *			The coordinate is relative to the physical screen zero point.
-	 *
-	 * @param[in] gh	The window
-	 *
-	 * @api
-	 */
-	#define gwinGetScreenX(gh)			((gh)->x)
-
-	/**
-	 * @brief	Get the Y coordinate of the window
-	 * @details	Returns the Y coordinate of the origin of the window.
-	 *			The coordinate is relative to the physical screen zero point.
-	 *
-	 * @param[in] gh	The window
-	 *
-	 * @api
-	 */
-	#define gwinGetScreenY(gh)			((gh)->y)
-
-	/**
-	 * @brief	Get the width of the window
-	 *
-	 * @param[in] gh	The window
-	 *
-	 * @api
-	 */
-	#define gwinGetWidth(gh)			((gh)->width)
-
-	/**
-	 * @brief	Get the height of the window
-	 *
-	 * @param[in] gh	The window
-	 *
-	 * @api
-	 */
-	#define gwinGetHeight(gh)			((gh)->height)
-
-	/**
-	 * @brief	Set foreground color
-	 * @details Set the color which will be used to draw
-	 *
-	 * @param[in] gh	The window
-	 * @param[in] clr	The color to be set
-	 *
-	 * @api
-	 */
-	#define gwinSetColor(gh, clr)		(gh)->color = (clr)
-
-	/**
-	 * @brief	Set background color
-	 * @details	Set the color which will be used as background
-	 * @note	gwinClear() must be called to set the background color
-	 *
-	 * @param[in] gh	The window
-	 * @param[in] bgclr	The background color
-	 *
-	 * @api
-	 */
-	#define gwinSetBgColor(gh, bgclr)	(gh)->bgcolor = (bgclr)
-
-	/**
-	 * @brief	Get the foreground color of a window
-	 *
-	 * @param[in] gh	The window
-	 *
-	 * @api
-	 */
-	#define gwinGetColor(gh)			(gh)->color
-
-	/**
-	 * @brief	Get the background color of a window
-	 *
-	 * @param[in] gh	The window
-	 *
-	 * @api
-	 */
-	#define gwinGetBgColor(gh)			(gh)->bgcolor
-
-	/**
-	 * @brief	Sets whether a window is visible or not
-	 *
-	 * @param[in] gh		The window
-	 * @param[in] visible	Whether the window should be visible or not
-	 *
-	 * @note	When a window is marked as not visible, drawing operations
-	 * 			on the window do nothing.
-	 * @note	When a window is marked as visible, it is not automatically
-	 * 			redrawn as many window types don't remember their drawing state.
-	 * 			Widgets such as Buttons, Sliders etc will be redrawn.
-	 * @note	If there is no window manager in use, when a window is marked
-	 * 			as not visible, nothing is done to remove the window from the screen.
-	 * 			When there is a window manager, it is up to the window manager to
-	 * 			handle what happens.
-	 * @note	Even when you mark a window as visible, it may still not be displayed
-	 * 			if it's parent is invisible. When the parent becomes visible this child
-	 * 			will automatically be shown because it is already marked as visible.
-	 *
-	 * @api
-	 */
-	void gwinSetVisible(GHandle gh, bool_t visible);
-
-	/**
-	 * @brief	Makes a widget become visible
-	 *
-	 * @param[in] gh		The window handle
-	 *
-	 * @api
-	 */
-	#define gwinShow(gh)		gwinSetVisible(gh, TRUE)
-
-	/**
-	 * @brief	Makes a widget become invisible
-	 *
-	 * @param[in] gh		The window handle
-	 *
-	 * @api
-	 */
-	#define gwinHide(gh)		gwinSetVisible(gh, FALSE)
-
-	/**
-	 * @brief	Gets the visibility of a window
-	 * @return	TRUE if visible
-	 *
-	 * @note	It is possible for a child to be marked as visible by @p gwinSetVisible()
-	 * 			but for this call to return FALSE if one of its parents are not visible.
-	 *
-	 * @param[in] gh		The window
-	 *
-	 * @api
-	 */
-	bool_t gwinGetVisible(GHandle gh);
-
-	/**
-	 * @brief	Enable or disable a window
-	 *
-	 * @param[in] gh		The window handle
-	 * @param[in] enabled	Enable or disable the window
-	 *
-	 * @note	The window is automatically redrawn if it supports self-redrawing.
-	 * @note	Even when you mark a window as enabled, it may still remain disabled
-	 * 			if it's parent is disabled. When the parent becomes enabled this child
-	 * 			will automatically be enabled because it is already marked as enabled.
-	 *
-	 * @api
-	 */
-	void gwinSetEnabled(GHandle gh, bool_t enabled);
-
-	/**
-	 * @brief	Enables a widget
-	 *
-	 * @param[in] gh		The window handle
-	 *
-	 * @api
-	 */
-	#define gwinEnable(gh)		gwinSetEnabled(gh, TRUE)
-
-	/**
-	 * @brief	Disables a widget
-	 *
-	 * @param[in] gh		The window handle
-	 *
-	 * @api
-	 */
-	#define gwinDisable(gh)		gwinSetEnabled(gh, FALSE)
-
-	/**
-	 * @brief	Gets the enabled state of a window
-	 * @return	TRUE if enabled
-	 *
-	 * @note	It is possible for a child to be marked as enabled by @p gwinSetEnabled()
-	 * 			but for this call to return FALSE if one of its parents are not enabled.
-	 *
-	 * @param[in] gh		The window
-	 *
-	 * @api
-	 */
-	bool_t gwinGetEnabled(GHandle gh);
-
-	/**
-	 * @brief	Move a window
-	 *
-	 * @param[in] gh		The window
-	 * @param[in] x, y		The new position (screen relative) for this window
-	 *
-	 * @note	The final window position may not be the requested position. Windows
-	 * 			are clipped to the screen area and the window manager may also affect the position.
-	 * @note	The window is redrawn if it is visible. See the comments in @p gwinSetVisible()
-	 * 			with regard to what can be redrawn and what can't.
-	 * @note	It is up to the window manager to determine what happens with the screen area
-	 * 			uncovered by moving the window. When there is no window manager, nothing
-	 * 			is done with the uncovered area.
-	 *
-	 * @api
-	 */
-	void gwinMove(GHandle gh, coord_t x, coord_t y);
-
-	/**
-	 * @brief	Resize a window
-	 *
-	 * @param[in] gh				The window
-	 * @param[in] width, height		The new size of the window
-	 *
-	 * @note	The final window size may not be the requested size. Windows
-	 * 			are clipped to the screen area and the window manager may also affect the size.
-	 * @note	The window is redrawn if it is visible. See the comments in @p gwinSetVisible()
-	 * 			with regard to what can be redrawn and what can't.
-	 * @note	It is up to the window manager to determine what happens with any screen area
-	 * 			uncovered by resizing the window. When there is no window manager, nothing
-	 * 			is done with the uncovered area.
-	 *
-	 * @api
-	 */
-	void gwinResize(GHandle gh, coord_t width, coord_t height);
-
-	/**
-	 * @brief	Redraw a window
-	 *
-	 * @param[in] gh				The window
-	 *
-	 * @note	This is normally never required as windows and widgets will redraw as required.
-	 * 			Note that some windows are incapable of redrawing themselves as they don't save
-	 * 			their drawing state.
-	 *
-	 * @api
-	 */
-	void gwinRedraw(GHandle gh);
-
-	#if GWIN_NEED_WINDOWMANAGER || defined (__DOXYGEN__)
-		/**
-		 * @brief	Redraw a window
-		 *
-		 * @param[in] g				The display to redraw. Passing NULL will redraw all displays.
-		 * @param[in] preserve		Should the redraw try to preserve existing screen data for those
-		 * 							windows that can't redraw themselves?
-		 *
-		 * @note	This is normally never required as windows and widgets will redraw as required.
-		 * @note	Some windows are incapable of redrawing themselves as they don't save
-		 * 			their drawing state.
-		 * @note	This does not clear the background - just redraws the gwin windows (where possible)
-		 *
-		 * @api
-		 */
-		void gwinRedrawDisplay(GDisplay *g, bool_t preserve);
-
-		/**
-		 * @brief	Minimize, Maximize or Restore a window
-		 * @pre		GWIN_NEED_WINDOWMANAGER must be TRUE
-		 *
-		 * @param[in] gh				The window
-		 * @param[in] minmax			The new minimized/maximized state
-		 *
-		 * @note	The final window state may not be the requested state. Window Managers
-		 * 			do not need to implement changing the minmax state. If there is no
-		 * 			window manager this call is ignored.
-		 * @note	The window is redrawn if it is changed. See the comments in @p gwinSetVisible()
-		 * 			with regard to what can be redrawn and what can't.
-		 * @note	It is up to the window manager to determine what happens with any screen area
-		 * 			uncovered by resizing the window.
-		 * @note	When a window is minimised it may be asked to draw the window or the window
-		 * 			manager may draw the minimised window.
-		 *
-		 * @api
-		 */
-		void gwinSetMinMax(GHandle gh, GWindowMinMax minmax);
-
-		/**
-		 * @brief	Get the Minimized/Maximized state of a window
-		 * @pre		GWIN_NEED_WINDOWMANAGER must be TRUE
-		 *
-		 * @param[in] gh				The window
-		 *
-		 * @return	GWIN_NORMAL, GWIN_MAXIMIZE or GWIN_MINIMIZE
-		 *
-		 * @api
-		 */
-		GWindowMinMax gwinGetMinMax(GHandle gh);
-
-		/**
-		 * @brief	Raise a window to the top of the z-order
-		 * @pre		GWIN_NEED_WINDOWMANAGER must be TRUE
-		 *
-		 * @param[in] gh				The window
-		 *
-		 * @note	The window z-order is only supported by some window managers. See the comments
-		 * 			in @p gwinSetVisible() with regard to what can be redrawn and what can't.
-		 *
-		 * @api
-		 */
-		void gwinRaise(GHandle gh);
-
-		/**
-		 * @brief	Get the next window in the z-order
-		 * @return	The next window or NULL if no more windows
-		 *
-		 * @param[in] gh		The previous window or NULL to get the first window
-		 *
-		 * @note	This returns the next window in the system from top to bottom.
-		 * @note	Where there are parent child relationships, this ignores them
-		 * 			and will list all windows in the system. There is no defined
-		 * 			order between children of siblings and they can in fact be mixed
-		 * 			in order. The only relationship honored is that parents will be
-		 * 			listed before their children.
-		 *
-		 * @api
-		 */
-		GHandle gwinGetNextWindow(GHandle gh);
-
-	#endif
-
-	#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
-		/**
-		 * @brief   Set the current font for this window.
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] font		The font to use for text functions
-		 *
-		 * @api
-		 */
-		void gwinSetFont(GHandle gh, font_t font);
-	#endif
-
-/*-------------------------------------------------
- * Drawing functions
- *-------------------------------------------------*/
-
-	/**
-	 * @brief   Clear the window
-	 * @note	Uses the current background color to clear the window
-	 *
-	 * @param[in] gh		The window handle
-	 *
-	 * @api
-	 */
-	void gwinClear(GHandle gh);
-
-	/**
-	 * @brief   Set a pixel in the window
-	 * @note	Uses the current foreground color to set the pixel
-	 * @note	May leave GDISP clipping to this window's dimensions
-	 *
-	 * @param[in] gh		The window handle
-	 * @param[in] x,y		The coordinates of the pixel
-	 *
-	 * @api
-	 */
-	void gwinDrawPixel(GHandle gh, coord_t x, coord_t y);
-
-	/**
-	 * @brief   Draw a line in the window
-	 * @note	Uses the current foreground color to draw the line
-	 * @note	May leave GDISP clipping to this window's dimensions
-	 *
-	 * @param[in] gh		The window handle
-	 * @param[in] x0,y0		The start position
-	 * @param[in] x1,y1 	The end position
-	 *
-	 * @api
-	 */
-	void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1);
-
-	/**
-	 * @brief   Draw a box in the window
-	 * @note	Uses the current foreground color to draw the box
-	 * @note	May leave GDISP clipping to this window's dimensions
-	 *
-	 * @param[in] gh		The window handle
-	 * @param[in] x,y		The start position
-	 * @param[in] cx,cy		The size of the box (outside dimensions)
-	 *
-	 * @api
-	 */
-	void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy);
-
-	/**
-	 * @brief   Fill an rectangular area in the window
-	 * @note	Uses the current foreground color to fill the box
-	 * @note	May leave GDISP clipping to this window's dimensions
-	 *
-	 * @param[in] gh		The window handle
-	 * @param[in] x,y		The start position
-	 * @param[in] cx,cy		The size of the box (outside dimensions)
-	 *
-	 * @api
-	 */
-	void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy);
-
-	/**
-	 * @brief   Fill an area in the window using the supplied bitmap.
-	 * @details The bitmap is in the pixel format specified by the low level driver
-	 * @note	If GDISP_NEED_ASYNC is defined then the buffer must be static
-	 * 			or at least retained until this call has finished the blit. You can
-	 * 			tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE.
-	 * @note	May leave GDISP clipping to this window's dimensions
-	 *
-	 * @param[in] gh		The window handle
-	 * @param[in] x, y		The start filled area
-	 * @param[in] cx, cy	The width and height to be filled
-	 * @param[in] srcx, srcy	The bitmap position to start the fill from
-	 * @param[in] srccx		The width of a line in the bitmap.
-	 * @param[in] buffer	The pixels to use to fill the area.
-	 *
-	 * @api
-	 */
-	void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer);
-
-/*-------------------------------------------------
- * Circle, ellipse, arc and arc-sectors functions
- *-------------------------------------------------*/
-
-	#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__)
-		/**
-		 * @brief   Draw a circle in the window.
-		 * @note	Uses the current foreground color to draw the circle
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x, y		The center of the circle
-		 * @param[in] radius	The radius of the circle
-		 *
-		 * @api
-		 */
-		void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius);
-
-		/**
-		 * @brief   Draw a filled circle in the window.
-		 * @note	Uses the current foreground color to draw the filled circle
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x, y		The center of the circle
-		 * @param[in] radius	The radius of the circle
-		 *
-		 * @api
-		 */
-		void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius);
-	#endif
-
-	#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__)
-		/**
-		 * @brief   Draw an ellipse.
-		 * @note	Uses the current foreground color to draw the ellipse
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The center of the ellipse
-		 * @param[in] a,b		The dimensions of the ellipse
-		 *
-		 * @api
-		 */
-		void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b);
-
-		/**
-		 * @brief   Draw an filled ellipse.
-		 * @note	Uses the current foreground color to draw the filled ellipse
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The center of the ellipse
-		 * @param[in] a,b		The dimensions of the ellipse
-		 *
-		 * @api
-		 */
-		void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b);
-	#endif
-
-	#if GDISP_NEED_ARC || defined(__DOXYGEN__)
-		/*
-		 * @brief	Draw an arc in the window.
-		 * @note	Uses the current foreground color to draw the arc
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The center point
-		 * @param[in] radius	The radius of the arc
-		 * @param[in] start		The start angle (0 to 360)
-		 * @param[in] end		The end angle (0 to 360)
-		 *
-		 * @api
-		 */
-		void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle);
-
-		/*
-		 * @brief	Draw a filled arc in the window.
-		 * @note	Uses the current foreground color to draw the filled arc
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The center point
-		 * @param[in] radius	The radius of the arc
-		 * @param[in] start		The start angle (0 to 360)
-		 * @param[in] end		The end angle (0 to 360)
-		 *
-		 * @api
-		 */
-		void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle);
-	#endif
-
-	#if GDISP_NEED_ARCSECTORS || defined(__DOXYGEN__)
-		/*
-		 * @brief	Draw a selection of 45 degree arcs of a circle in the window.
-		 * @note	Uses the current foreground color to draw the arc sector
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The center of the circle
-		 * @param[in] radius	The radius of the circle
-		 * @param[in] sectors	Bits determine which sectors are drawn.
-		 * 						Bits go anti-clockwise from the 0 degree mark (y = 0, x is positive), as follows:
-		 *  						bit 0 - upper right right		  -----
-		 *  						bit 1 - upper upper right		 /2   1\
-		 *  						bit 2 - upper upper left		/3     0\
-		 *  						bit 3 - upper left  left		\4     7/
-		 *  						bit 4 - lower left  left		 \5   6/
-		 *  						bit 5 - lower lower left		  -----
-		 *  						bit 6 - lower lower right
-		 *  						bit 7 - lower left  left
-		 *
-		 * @api
-		 */
-		void gwinDrawArcSectors(GHandle gh, coord_t x, coord_t y, coord_t radius, uint8_t sectors);
-
-		/*
-		 * @brief	Draw a filled selection of 45 degree arcs of a circle in the window.
-		 * @note	Uses the current foreground color to draw the arc sector
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The center of the circle
-		 * @param[in] radius	The radius of the circle
-		 * @param[in] sectors	Bits determine which sectors are drawn.
-		 * 						Bits go anti-clockwise from the 0 degree mark (y = 0, x is positive), as follows:
-		 *  						bit 0 - upper right right		  -----
-		 *  						bit 1 - upper upper right		 /2   1\
-		 *  						bit 2 - upper upper left		/3     0\
-		 *  						bit 3 - upper left  left		\4     7/
-		 *  						bit 4 - lower left  left		 \5   6/
-		 *  						bit 5 - lower lower left		  -----
-		 *  						bit 6 - lower lower right
-		 *  						bit 7 - lower left  left
-		 *
-		 * @api
-		 */
-		void gwinFillArcSectors(GHandle gh, coord_t x, coord_t y, coord_t radius, uint8_t sectors);
-	#endif
-
-/*-------------------------------------------------
- * Pixel read-back functions
- *-------------------------------------------------*/
-
-	#if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__)
-		/**
-		 * @brief   Get the color of a pixel in the window.
-		 * @return  The color of the pixel.
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The position in the window
-		 *
-		 * @api
-		 */
-		color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y);
-	#endif
-
-/*-------------------------------------------------
- * Text functions
- *-------------------------------------------------*/
-
-	#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
-		/**
-		 * @brief   Draw a text character at the specified position in the window.
-		 * @pre		The font must have been set.
-		 * @note	Uses the current foreground color to draw the character
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The position for the text
-		 * @param[in] c			The character to draw
-		 *
-		 * @api
-		 */
-		void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c);
-
-		/**
-		 * @brief   Draw a text character with a filled background at the specified position in the window.
-		 * @pre		The font must have been set.
-		 * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The position for the text
-		 * @param[in] c			The character to draw
-		 *
-		 * @api
-		 */
-		void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c);
-
-		/**
-		 * @brief   Draw a text string in the window
-		 * @pre		The font must have been set.
-		 * @note	Uses the current foreground color to draw the character
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The position for the text
-		 * @param[in] str		The string to draw
-		 *
-		 * @api
-		 */
-		void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str);
-
-		/**
-		 * @brief   Draw a text string with a filled background in the window
-		 * @pre		The font must have been set.
-		 * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The position for the text
-		 * @param[in] str		The string to draw
-		 *
-		 * @api
-		 */
-		void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str);
-
-		/**
-		 * @brief   Draw a text string verticly centered within the specified box.
-		 * @pre		The font must have been set.
-		 * @note	Uses the current foreground color to draw the character.
-		 * @note    The specified box does not need to align with the window box
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
-		 * @param[in] cx,cy		The width and height of the box
-		 * @param[in] str		The string to draw
-		 * @param[in] justify	Justify the text left, center or right within the box
-		 *
-		 * @api
-		 */
-		void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify);
-
-		/**
-		 * @brief   Draw a text string verticly centered within the specified filled box.
-		 * @pre		The font must have been set.
-		 * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
-		 * @note    The entire box is filled. Note this box does not need to align with the window box
-		 * @note	May leave GDISP clipping to this window's dimensions
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
-		 * @param[in] cx,cy		The width and height of the box
-		 * @param[in] str		The string to draw
-		 * @param[in] justify	Justify the text left, center or right within the box
-		 *
-		 * @api
-		 */
-		void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify);
-	#endif
-
-/*-------------------------------------------------
- * Polygon functions
- *-------------------------------------------------*/
-
-	#if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__)
-		/**
-		 * @brief   Draw an enclosed polygon (convex, non-convex or complex).
-		 *
-		 * @note	Uses the current foreground color.
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] tx, ty	Transform all points in pntarray by tx, ty
-		 * @param[in] pntarray	An array of points
-		 * @param[in] cnt		The number of points in the array
-		 *
-		 * @api
-		 */
-		void gwinDrawPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt);
-
-		/**
-		 * @brief   Fill a convex polygon
-		 * @details Doesn't handle non-convex or complex polygons.
-		 *
-		 * @note	Uses the current foreground color.
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] tx, ty	Transform all points in pntarray by tx, ty
-		 * @param[in] pntarray	An array of points
-		 * @param[in] cnt		The number of points in the array
-		 *
-		 * @note	Convex polygons are those that have no internal angles. That is;
-		 * 			you can draw a line from any point on the polygon to any other point
-		 * 			on the polygon without it going outside the polygon. In our case we generalise
-		 * 			this a little by saying that an infinite horizontal line (at any y value) will cross
-		 * 			no more than two edges on the polygon. Some non-convex polygons do fit this criteria
-		 * 			and can therefore be drawn.
-		 * @note	This routine is designed to be very efficient with even simple display hardware.
-		 *
-		 * @api
-		 */
-		void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt);
-	
-		/**
-		 * @brief	Draw a thick line in the window
-		 * @details	The line thickness is specified in pixels. The line ends can
-		 *		be selected to be either flat or round.
-		 * @note	Uses gdispGFillConvexPoly() internally to perform the drawing.
-		 * @note	Uses the current foreground color to draw the line
-		 * 
-		 * @param[in] gh		The window handle
-		 * @param[in] x0,y0		The start position
-		 * @param[in] x1,y1		The end position
-		 * @param[in] width		The width of the line
-		 * @param[in] round		Use round ends for the line
-		 * 
-		 * @api
-		 */
-		void gwinDrawThickLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t width, bool_t round);
-	#endif
-
-/*-------------------------------------------------
- * Image functions
- *-------------------------------------------------*/
-
-	#if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
-		/**
-		 * @brief	Draw the image
-		 * @return	GDISP_IMAGE_ERR_OK (0) on success or an error code.
-		 *
-		 * @param[in] gh		The window handle
-		 * @param[in] img   	The image structure
-		 * @param[in] x,y		The window location to draw the image
-		 * @param[in] cx,cy		The area on the screen to draw
-		 * @param[in] sx,sy		The image position to start drawing at
-		 *
-		 * @pre		gdispImageOpen() must have returned successfully.
-		 *
-		 * @note	If sx,sy + cx,cy is outside the image boundaries the area outside the image
-		 * 			is simply not drawn.
-		 * @note	If @p gdispImageCache() has been called first for this frame, this routine will draw using a
-		 * 			fast blit from the cached frame. If not, it reads the input and decodes it as it
-		 * 			is drawing. This may be significantly slower than if the image has been cached (but
-		 * 			uses a lot less RAM)
-		 *
-		 * @api
-		 */
-		gdispImageError gwinDrawImage(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy);
-	#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-/*-------------------------------------------------
- * Additional functionality
- *-------------------------------------------------*/
-
-	/* Include widgets */
-	#if GWIN_NEED_WIDGET || defined(__DOXYGEN__)
-		#include "gwin_widget.h"
-	#endif
-
-	/* Include containers */
-	#if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__)
-		#include "gwin_container.h"
-	#endif
-
-	/* Include vanilla window objects */
-	#if GWIN_NEED_CONSOLE || defined(__DOXYGEN__)
-		#include "gwin_console.h"
-	#endif
-	#if GWIN_NEED_GRAPH || defined(__DOXYGEN__)
-		#include "gwin_graph.h"
-	#endif
-	#if GWIN_NEED_IMAGE || defined(__DOXYGEN__)
-		#include "gwin_image.h"
-	#endif
-	#if GWIN_NEED_GL3D || defined(__DOXYGEN__)
-		#include "gwin_gl3d.h"
-	#endif
-
-#endif /* GFX_USE_GWIN */
-
-#endif /* _GWIN_H */
-/** @} */
diff --git a/src/gwin/sys_make.mk b/src/gwin/sys_make.mk
deleted file mode 100644
index c619466e..00000000
--- a/src/gwin/sys_make.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-GFXSRC +=   $(GFXLIB)/src/gwin/gwin_gwin.c \
-			$(GFXLIB)/src/gwin/gwin_widget.c \
-			$(GFXLIB)/src/gwin/gwin_wm.c \
-			$(GFXLIB)/src/gwin/gwin_console.c \
-			$(GFXLIB)/src/gwin/gwin_graph.c \
-			$(GFXLIB)/src/gwin/gwin_button.c \
-			$(GFXLIB)/src/gwin/gwin_slider.c \
-			$(GFXLIB)/src/gwin/gwin_checkbox.c \
-			$(GFXLIB)/src/gwin/gwin_image.c \
-			$(GFXLIB)/src/gwin/gwin_label.c \
-			$(GFXLIB)/src/gwin/gwin_radio.c \
-			$(GFXLIB)/src/gwin/gwin_list.c \
-			$(GFXLIB)/src/gwin/gwin_progressbar.c \
-			$(GFXLIB)/src/gwin/gwin_container.c \
-			$(GFXLIB)/src/gwin/gwin_frame.c \
-			$(GFXLIB)/src/gwin/gwin_tabset.c \
-			$(GFXLIB)/src/gwin/gwin_gl3d.c \
-
-GFXINC +=	$(GFXLIB)/3rdparty/tinygl-0.4-ugfx/include	
diff --git a/src/gwin/sys_options.h b/src/gwin/sys_options.h
deleted file mode 100644
index df8f497e..00000000
--- a/src/gwin/sys_options.h
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gwin/sys_options.h
- * @brief   GWIN sub-system options header file.
- *
- * @addtogroup GWIN
- * @brief	The GWIN module uses all the other modules (GDISP, GINPUT, GTIMER...) to
- *			form a complete GUI toolkit.
- * 
- * @{
- */
-
-#ifndef _GWIN_OPTIONS_H
-#define _GWIN_OPTIONS_H
-
-/**
- * @name    GWIN Functionality to be included
- * @{
- */
-	/**
-	 * @brief   Should window manager support be included
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_WINDOWMANAGER
-		#define GWIN_NEED_WIDGET	FALSE
-	#endif
-	/**
-	 * @brief	Should the widget hierarchy be included. This provides parent-child features.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_CONTAINERS
-		#define GWIN_NEED_CONTAINERS	FALSE
-	#endif
-	/**
-	 * @brief   Should widget functions be included. Needed for any widget (eg Buttons, Sliders etc)
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_WIDGET
-		#define GWIN_NEED_WIDGET	FALSE
-	#endif
-	/**
-	 * @brief	Should the simple container be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_CONTAINER
-		#define GWIN_NEED_CONTAINER		FALSE
-	#endif
-	/**
-	 * @brief	Should the frame widget be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_FRAME
-		#define GWIN_NEED_FRAME		FALSE
-	#endif
-	/**
-	 * @brief   Should console functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_CONSOLE
-		#define GWIN_NEED_CONSOLE	FALSE
-	#endif
-	/**
-	 * @brief   Should graph functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_GRAPH
-		#define GWIN_NEED_GRAPH		FALSE
-	#endif
-	/**
-	 * @brief   Should gl3d functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_GL3D
-		#define GWIN_NEED_GL3D		FALSE
-	#endif
-	/**
-	 * @brief   Should button functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_BUTTON
-		#define GWIN_NEED_BUTTON	FALSE
-	#endif
-	/**
-	 * @brief   Should progressbar functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_PROGRESSBAR
-		#define GWIN_NEED_PROGRESSBAR	FALSE
-	#endif
-	/**
-	 * @brief   Should slider functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_SLIDER
-		#define GWIN_NEED_SLIDER	FALSE
-	#endif
-	/**
-	 * @brief   Should checkbox functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_CHECKBOX
-		#define GWIN_NEED_CHECKBOX	FALSE
-	#endif
-	/**
-	 * @brief   Should image functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_IMAGE
-		#define GWIN_NEED_IMAGE		FALSE
-	#endif
-	/**
-	 * @brief   Should label functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_LABEL
-		#define GWIN_NEED_LABEL		FALSE
-	#endif
-	/**
-	 * @brief   Should radio button functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_RADIO
-		#define GWIN_NEED_RADIO		FALSE
-	#endif
-	/**
-	 * @brief   Should tabset functions be included.
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_TABSET
-		#define GWIN_NEED_TABSET	FALSE
-	#endif
-/**
- * @}
- *
- * @name    GWIN Optional Parameters
- * @{
- */
-	/**
-	 * @brief   Add a tag to each widget
-	 * @details	Defaults to FALSE
-	 * @note	Adds a tag member to each widget. Any events created include this tag.
-	 * 			The enables switch based application logic to detect the event source.
-	 */
-	#ifndef GWIN_WIDGET_TAGS
-		#define GWIN_WIDGET_TAGS		FALSE
-	#endif
-	/**
-	 * @brief   Use flat styling for controls rather than a 3D look
-	 * @details	Defaults to FALSE
-	 * @note	This may appear better on color-restricted displays
-	 * @note	Flat styling is less graphics and cpu intensive (marginally) than the default 3D look.
-	 */
-	#ifndef GWIN_FLAT_STYLING
-		#define GWIN_FLAT_STYLING		FALSE
-	#endif
-	/**
-	 * @brief	Don't use a timer for redrawing windows
-	 * @details	Defaults to FALSE
-	 * @note	Normally windows and widgets are redrawn on a timer. Setting this
-	 * 			option causes them to be redrawn immediately. Note that this can
-	 * 			cause extended blocking times on events and saves little code.
-	 * @note	If GWIN_NEED_WINDOWMANAGER is FALSE then this setting is ignored
-	 * 			as redrawing always occurs immediately.
-	 */
-	#ifndef GWIN_REDRAW_IMMEDIATE
-		#define GWIN_REDRAW_IMMEDIATE	FALSE
-	#endif
-	/**
-	 * @brief	Redraw all windows in a single operation
-	 * @details	Defaults to FALSE
-	 * @note	Windows are normally redraw one per gtimer cycle.
-	 * 			Setting this option causes all windows to be redrawn in
-	 * 			a single gtimer cycle. Note that this can
-	 * 			cause extended blocking times on the timer thread but may
-	 * 			speed up redraw slightly.
-	 * @note	This is only relevant if GWIN_REDRAW_IMMEDIATE is FALSE.
-	 * 			Everything always gets redrawn in a single operation if
-	 * 			GWIN_REDRAW_IMMEDIATE is TRUE.
-	 */
-	#ifndef GWIN_REDRAW_SINGLEOP
-		#define GWIN_REDRAW_SINGLEOP	FALSE
-	#endif
-	/**
-	 * @brief   Buttons should not insist the mouse is over the button on mouse release
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_BUTTON_LAZY_RELEASE
-		#define GWIN_BUTTON_LAZY_RELEASE		FALSE
-	#endif
-	/**
-	 * @brief	Should the content of the console be saved for redrawing.
-	 * @details	Defaults to FALSE
-	 * @details	If this feature is enabled, the contents of the console will be saved
-	 * 			as it is written. If a redraw is required it will be redrawn from the
-	 * 			history. Scrolling will also use the history buffer if it is turned on.
-	 * @note	Using this option allocates the amount of memory to store the
-	 * 			history based on the minimum character width in the current font
-	 * 			at the time the history is turned on. Using a fixed width font is a good
-	 * 			idea to minimize memory usage.
-	 * @note	If you change the size of the window or you change the font being displayed
-	 * 			you should turn off the history and then turn it back on in order to get
-	 * 			a new buffer of the correct size for the window/font combination. Strange
-	 * 			redrawing and scrolling effects can occur if the buffer is too small to
-	 * 			save a complete screen of data. Note the system tries to optimize storage
-	 * 			so this may only be evident in very limited situations eg with a console
-	 * 			with many characters in it.
-	 * @note	@p gwinConsoleSetBuffer() can be used to turn the history buffer off and on.
-	 */
-	#ifndef GWIN_CONSOLE_USE_HISTORY
-		#define GWIN_CONSOLE_USE_HISTORY		FALSE
-	#endif
-	/**
-	 * @brief	Use font width averaging for the history buffer allocation.
-	 * @details	Defaults to FALSE
-	 * @details	If this feature is enabled, the width one third of the way between
-	 * 			the font's character width minimum and maximum will be used instead
-	 * 			of the font's minimum width.
-	 * @note	This option reduces the memory allocation for a variable width font's
-	 * 			history buffer. Note that strange
-	 * 			redrawing and scrolling effects can occur if the buffer is too small to
-	 * 			save a complete screen of data. The system tries to optimize storage
-	 * 			so this may only be evident in very limited situations eg with a console
-	 * 			with many characters in it.
-	 */
-	#ifndef GWIN_CONSOLE_HISTORY_AVERAGING
-		#define GWIN_CONSOLE_HISTORY_AVERAGING	FALSE
-	#endif
-	/**
-	 * @brief	Should the history be turned on for all console windows when they are first created.
-	 * @details	Defaults to FALSE
-	 * @note	@p gwinConsoleSetBuffer() can be used to turn the history buffer off and on at
-	 * 			any time.
-	 */
-	#ifndef GWIN_CONSOLE_HISTORY_ATCREATE
-		#define GWIN_CONSOLE_HISTORY_ATCREATE	FALSE
-	#endif
-	/**
-	 * @brief   Console Windows need floating point support in @p gwinPrintf
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_CONSOLE_USE_FLOAT
-		#define GWIN_CONSOLE_USE_FLOAT			FALSE
-	#endif
-	/**
-	 * @brief   Console windows support escape sequences to control display
-	 * @details	Defaults to FALSE
-	 *
-	 * @note
-	 * 		Currently supported:
-	 * 			ESC color		Change subsequent text color
-	 * 							color:	"0" = black, "1" = red, "2" = green, "3" = yellow, "4" = blue,
-	 * 									"5" = magenta, "6" = cyan, "7" = white
-	 * 			ESC C			Revert subsequent text color to the window default
-	 * 			ESC u			Turn on underline
-	 * 			ESC U			Turn off underline
-	 * 			ESC b			Turn on bold
-	 * 			ESC B			Turn off bold
-	 * 			ESC J			Clear the window
-	 */
-	#ifndef GWIN_CONSOLE_ESCSEQ
-		#define GWIN_CONSOLE_ESCSEQ				FALSE
-	#endif
-	/**
-	 * @brief   Console Windows need BaseStreamSequential support (ChibiOS only)
-	 * @details	Defaults to FALSE
-	 * @note	To use the ChibiOS basestream functions such as chprintf()
-	 * 			for printing in a console window you need to set this option to
-	 * 			TRUE in your gfxconf.h and include in your application source file...
-	 * 			\#include "chprintf.h"
-	 * 			In your makefile, as part of your list of C source files, include
-	 * 			${CHIBIOS}/os/various/chprintf.c
-	 */
-	#ifndef GWIN_CONSOLE_USE_BASESTREAM
-		#define GWIN_CONSOLE_USE_BASESTREAM		FALSE
-	#endif
-	/**
-	 * @brief   Image windows can optionally support animated images
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_NEED_IMAGE_ANIMATION
-		#define GWIN_NEED_IMAGE_ANIMATION		FALSE
-	#endif
-	/**
-	 * @brief	Enable the API to automatically increment the progressbar over time
-	 * @details	Defaults to FALSE
-	 */
-	#ifndef GWIN_PROGRESSBAR_AUTO
-	 	#define GWIN_PROGRESSBAR_AUTO			FALSE
-	#endif
-	/**
-	 * @brief	Should the slider avoid snapping to a fixed position when the mouse is released
-	 * @details	Defaults to FALSE
-	 * @note	If FALSE the slider will snap to the closest set-able position when the
-	 * 			mouse is released. If TRUE it will maintain the position the
-	 * 			mouse was released at, except when at the minimum and maximum slider values.
-	 */
-	#ifndef GWIN_SLIDER_NOSNAP
-	 	#define GWIN_SLIDER_NOSNAP				FALSE
-	#endif
-	/**
-	 * @brief	The number of pixels of dead-band at each end of the slider
-	 * @details	Defaults to 5
-	 * @note	A dead-band is required because fingers can often cannot
-	 * 			accurately control the slider peg at the edges of the slider
-	 */
-	#ifndef GWIN_SLIDER_DEAD_BAND
-		#define GWIN_SLIDER_DEAD_BAND			5
-	#endif
-	/**
-	 * @brief	How many toggles it takes to go from minimum to maximum value on a slider
-	 * @details	Defaults to 20
-	 * @note	When the slider is being operated by a toggle device this setting describes
-	 * 			how many toggles are required to go from end to end.
-	 */
-	#ifndef GWIN_SLIDER_TOGGLE_INC
-		#define GWIN_SLIDER_TOGGLE_INC			20
-	#endif
-	/**
-	 * @brief	The height in pixels of a row of tabs in a tabset
-	 * @details	Defaults to 18
-	 */
-	#ifndef GWIN_TABSET_TABHEIGHT
-		#define GWIN_TABSET_TABHEIGHT			18
-	#endif
-/** @} */
-
-#endif /* _GWIN_OPTIONS_H */
-/** @} */
diff --git a/src/gwin/sys_rules.h b/src/gwin/sys_rules.h
deleted file mode 100644
index 39864901..00000000
--- a/src/gwin/sys_rules.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- *              http://ugfx.org/license.html
- */
-
-/**
- * @file    src/gwin/sys_rules.h
- * @brief   GWIN safety rules header file.
- *
- * @addtogroup GWIN
- * @{
- */
-
-#ifndef _GWIN_RULES_H
-#define _GWIN_RULES_H
-
-#if GFX_USE_GWIN
-	// Sub-system rules
-	#if !GFX_USE_GDISP
-		#error "GWIN: GFX_USE_GDISP must be TRUE when using GWIN"
-	#endif
-	#if !GDISP_NEED_CLIP
-		#if GFX_DISPLAY_RULE_WARNINGS
-			#warning "GWIN: Drawing can occur outside the defined windows as GDISP_NEED_CLIP is FALSE"
-		#endif
-	#endif
-
-	// Objects require their super-class
-	#if GWIN_NEED_TABSET || GWIN_NEED_FRAME || GWIN_NEED_CONTAINER
-		#if !GWIN_NEED_CONTAINERS
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GWIN: GWIN_NEED_CONTAINERS is required when a container is enabled. It has been turned on for you."
-			#endif
-			#undef GWIN_NEED_CONTAINERS
-			#define GWIN_NEED_CONTAINERS	TRUE
-		#endif
-	#endif
-	#if GWIN_NEED_BUTTON || GWIN_NEED_SLIDER || GWIN_NEED_CHECKBOX || GWIN_NEED_LABEL || GWIN_NEED_RADIO || GWIN_NEED_LIST || \
-		GWIN_NEED_IMAGE || GWIN_NEED_CHECKBOX || GWIN_NEED_PROGRESSBAR 
-		#if !GWIN_NEED_WIDGET
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GWIN: GWIN_NEED_WIDGET is required when a widget is used. It has been turned on for you."
-			#endif
-			#undef GWIN_NEED_WIDGET
-			#define GWIN_NEED_WIDGET	TRUE
-		#endif
-	#endif
-
-	// Rules for the super-classes
-	#if GWIN_NEED_CONTAINERS
-		#if !GWIN_NEED_WIDGET
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GWIN: GWIN_NEED_WIDGET is required when GWIN_NEED_CONTAINERS is enabled. It has been turned on for you."
-			#endif
-			#undef GWIN_NEED_WIDGET
-			#define GWIN_NEED_WIDGET	TRUE
-		#endif
-	#endif
-	#if GWIN_NEED_WIDGET
-		#if !GDISP_NEED_TEXT
-			#error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_WIDGET is TRUE."
-		#endif
-		#if !GFX_USE_GINPUT
-			// This test also ensures that GFX_USE_GEVENT is set
-			#error "GWIN: GFX_USE_GINPUT (and one or more input sources) is required if GWIN_NEED_WIDGET is TRUE"
-		#endif
-		#if !GWIN_NEED_WINDOWMANAGER
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GWIN: GWIN_NEED_WINDOWMANAGER is required if GWIN_NEED_WIDGET is TRUE. It has been turned on for you."
-			#endif
-			#undef GWIN_NEED_WINDOWMANAGER
-			#define GWIN_NEED_WINDOWMANAGER	TRUE
-		#endif
-		#if !GDISP_NEED_MULTITHREAD
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GWIN: GDISP_NEED_MULTITHREAD is required if GWIN_NEED_WIDGET is TRUE. It has been turned on for you"
-			#endif
-			#undef GDISP_NEED_MULTITHREAD
-			#define GDISP_NEED_MULTITHREAD	TRUE
-		#endif
-	#endif
-	#if GWIN_NEED_WINDOWMANAGER
-		#if !GFX_USE_GQUEUE || !GQUEUE_NEED_ASYNC
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GWIN: GFX_USE_GQUEUE and GQUEUE_NEED_ASYNC is required if GWIN_NEED_WINDOWMANAGER is TRUE. It has been turned on for you."
-			#endif
-			#undef GFX_USE_GQUEUE
-			#undef GQUEUE_NEED_ASYNC
-			#define GFX_USE_GQUEUE		TRUE
-			#define GQUEUE_NEED_ASYNC	TRUE
-		#endif
-		#if !GFX_USE_GTIMER
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GWIN: GFX_USE_GTIMER is required if GWIN_NEED_WINDOWMANAGER is TRUE. It has been turned on for you."
-			#endif
-			#undef GFX_USE_GTIMER
-			#define GFX_USE_GTIMER		TRUE
-		#endif
-	#endif
-
-	// Rules for individual objects
-	#if GWIN_NEED_LIST
-		#if !GDISP_NEED_TEXT
-			#error "GWIN: GDISP_NEED_TEXT is required when GWIN_NEED_LIST is TRUE."
-		#endif
-	#endif
-	#if GWIN_NEED_RADIO
-		#if !GDISP_NEED_CIRCLE
-			#if GFX_DISPLAY_RULE_WARNINGS
-				#warning "GWIN: GDISP_NEED_CIRCLE should be set to TRUE for much nicer radio button widgets."
-			#endif
-		#endif
-	#endif
-	#if GWIN_NEED_IMAGE
-		#if !GDISP_NEED_IMAGE
-			#error "GWIN: GDISP_NEED_IMAGE is required when GWIN_NEED_IMAGE is TRUE."
-		#endif
-	#endif
-	#if GWIN_NEED_CONSOLE
-		#if !GDISP_NEED_TEXT
-			#error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_CONSOLE is TRUE."
-		#endif
-	#endif
-#endif
-
-#endif /* _GWIN_RULES_H */
-/** @} */
-- 
cgit v1.2.3