void _gmousePostInitDriver(GDriver *g) {
    #define     m   ((GMouse *)g)

	#if !GINPUT_TOUCH_STARTRAW
		m->flags |= GMOUSE_FLG_CLIP;
	#endif

    #if !GINPUT_TOUCH_NOCALIBRATE && !GINPUT_TOUCH_STARTRAW
        if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CALIBRATE)) {
            #if GINPUT_TOUCH_USER_CALIBRATION_LOAD
                if (LoadMouseCalibration(gdriverGetDriverInstanceNumber((GDriver *)m), &m->caldata, sizeof(GMouseCalibration)))
                    m->flags |= GMOUSE_FLG_CALIBRATE;
                else
            #endif
            if (gmvmt(m)->calload && gmvmt(m)->calload(m, &m->caldata, sizeof(GMouseCalibration)))
                m->flags |= GMOUSE_FLG_CALIBRATE;
			#if !GINPUT_TOUCH_NOCALIBRATE_GUI
				else
					while (CalibrateMouse(m));
			#endif
        }
    #endif

    // Get the first reading
    GetMouseReading(m);

    #undef m
}
void _gmousePostInitDriver(GDriver *g) {
    #define     m   ((GMouse *)g)

	#if !GINPUT_TOUCH_STARTRAW
		m->flags |= GMOUSE_FLG_CLIP;
	#endif

    #if !GINPUT_TOUCH_NOCALIBRATE && !GINPUT_TOUCH_STARTRAW
        if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CALIBRATE)) {
            GMouseCalibration		*pc;

            #if GINPUT_TOUCH_USER_CALIBRATION_LOAD
                if ((pc = (GMouseCalibration *)LoadMouseCalibration(gdriverGetDriverInstanceNumber((GDriver *)m), sizeof(GMouseCalibration)))) {
                    memcpy(&m->caldata, pc, sizeof(GMouseCalibration));
                    #if GINPUT_TOUCH_USER_CALIBRATION_FREE
                        gfxFree(pc);
                    #endif
                    m->flags |= GMOUSE_FLG_CALIBRATE;
                } else
            #endif
            if (gmvmt(m)->calload && (pc = (GMouseCalibration *)gmvmt(m)->calload(m, sizeof(GMouseCalibration)))) {
                memcpy(&m->caldata, pc, sizeof(GMouseCalibration));
                if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_LOADFREE))
                    gfxFree(pc);
                m->flags |= GMOUSE_FLG_CALIBRATE;
            }
			#if !GINPUT_TOUCH_NOCALIBRATE_GUI
				else
					while (CalibrateMouse(m));
			#endif
        }
    #endif

    // Get the first reading
    GetMouseReading(m);

    #undef m
}
	static uint32_t CalibrateMouse(GMouse *m) {
		coord_t		w, h;
		point		cross[4];		// The locations of the test points on the display
		point		points[4];		// The x, y readings obtained from the mouse for each test point
		uint32_t	err;
		#if GDISP_NEED_TEXT
			font_t		font1, font2;
		#endif

		#if GDISP_NEED_TEXT
			font1 = gdispOpenFont(CALIBRATION_FONT);
			if (!font1) font1 = gdispOpenFont("*");
			font2 = gdispOpenFont(CALIBRATION_FONT2);
			if (!font2) font2 = gdispOpenFont("*");
		#endif
		err = 0;
		w  =  gdispGGetWidth(m->display);
		h  =  gdispGGetHeight(m->display);
		#if GDISP_NEED_CLIP
			gdispGSetClip(m->display, 0, 0, w, h);
		#endif

		// Ensure we get minimaly processed readings for the calibration
		m->flags |= GMOUSE_FLG_IN_CAL;

		// Set up our calibration locations
        if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_EXTREMES)) {
            cross[0].x = 0;		cross[0].y = 0;
            cross[1].x = w-1;	cross[1].y = 0;
            cross[2].x = w-1;	cross[2].y = h-1;
            cross[3].x = w/2;	cross[3].y = h/2;
        } else {
            cross[0].x = w/4;	cross[0].y = h/4;
            cross[1].x = w-w/4;	cross[1].y = h/4;
            cross[2].x = w-w/4;	cross[2].y = h-h/4;
            cross[3].x = w/2;	cross[3].y = h/2;
        }

		// Set up the calibration display
		gdispGClear(m->display, Blue);
		#if GDISP_NEED_TEXT
			gdispGFillStringBox(m->display,
								0, CALIBRATION_TITLE_Y, w, CALIBRATION_TITLE_HEIGHT,
								CALIBRATION_TITLE, font1,  CALIBRATION_TITLE_COLOR, CALIBRATION_TITLE_BACKGROUND,
								justifyCenter);
		#endif

		// Calculate the calibration
		{
			unsigned	i, maxpoints;

			maxpoints = (gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_TEST) ? 4 : 3;

			// Loop through the calibration points
			for(i = 0; i < maxpoints; i++) {
				int32_t		px, py;
				unsigned	j;

				// Draw the current calibration point
				CalibrationCrossDraw(m, &cross[i]);

				// Get a valid "point pressed" average reading
				do {
					// Wait for the mouse to be pressed
					while(!(m->r.buttons & GINPUT_MOUSE_BTN_LEFT))
						gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD);

					// Sum samples taken every CALIBRATION_POLL_PERIOD milliseconds while the mouse is down
					px = py = j = 0;
					while((m->r.buttons & GINPUT_MOUSE_BTN_LEFT)) {
						// Limit sampling period to prevent overflow
						if (j < CALIBRATION_MAXPRESS_PERIOD/CALIBRATION_POLL_PERIOD) {
							px += m->r.x;
							py += m->r.y;
							j++;
						}
						gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD);
					}

					// Ignore presses less than CALIBRATION_MAXPRESS_PERIOD milliseconds
				} while(j < CALIBRATION_MINPRESS_PERIOD/CALIBRATION_POLL_PERIOD);
				points[i].x = px / j;
				points[i].y = py / j;

				// Clear the current calibration point
				CalibrationCrossClear(m, &cross[i]);
			}
		}

		// Apply 3 point calibration algorithm
		CalibrationCalculate(m, cross, points);

		 /* Verification of correctness of calibration (optional) :
		 *  See if the 4th point (Middle of the screen) coincides with the calibrated
		 *  result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration
		 *  Else return the error.
		 */
		if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_TEST)) {
			const GMouseJitter	*pj;

			// Are we in pen or finger mode
			pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter;

			// Transform the co-ordinates
			CalibrationTransform((GMouseReading *)&points[3], &m->caldata);

			// Do we need to rotate the reading to match the display
			#if GDISP_NEED_CONTROL
				if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) {
					coord_t		t;

					switch(gdispGGetOrientation(m->display)) {
						case GDISP_ROTATE_0:
							break;
						case GDISP_ROTATE_90:
							t = points[3].x;
							points[3].x = w - 1 - points[3].y;
							points[3].y = t;
							break;
						case GDISP_ROTATE_180:
							points[3].x = w - 1 - points[3].x;
							points[3].y = h - 1 - points[3].y;
							break;
						case GDISP_ROTATE_270:
							t = points[3].y;
							points[3].y = h - 1 - points[3].x;
							points[3].x = t;
							break;
						default:
							break;
					}
				}
			#endif

			// Is this accurate enough?
			err = (points[3].x - cross[3].x) * (points[3].x - cross[3].x) + (points[3].y - cross[3].y) * (points[3].y - cross[3].y);
			if (err > (uint32_t)pj->calibrate * (uint32_t)pj->calibrate) {
				#if GDISP_NEED_TEXT
					// No - Display error and return
					gdispGFillStringBox(m->display,
											0, CALIBRATION_ERROR_Y, w, CALIBRATION_ERROR_HEIGHT,
											CALIBRATION_ERROR_TEXT, font2,  CALIBRATION_ERROR_COLOR, CALIBRATION_ERROR_BACKGROUND,
											justifyCenter);
					gfxSleepMilliseconds(CALIBRATION_ERROR_DELAY);
				#endif
			} else
				err = 0;
		}

		// We are done calibrating
		#if GDISP_NEED_TEXT
			gdispCloseFont(font1);
			gdispCloseFont(font2);
		#endif
		m->flags &= ~GMOUSE_FLG_IN_CAL;
		m->flags |= GMOUSE_FLG_CLIP;

		// Save the calibration data (if possible)
		if (!err) {
			m->flags |= GMOUSE_FLG_CALIBRATE;

			#if GINPUT_TOUCH_USER_CALIBRATION_SAVE
				SaveMouseCalibration(gdriverGetDriverInstanceNumber((GDriver *)m), &m->caldata, sizeof(GMouseCalibration));
			#endif
			if (gmvmt(m)->calsave)
				gmvmt(m)->calsave(m, &m->caldata, sizeof(GMouseCalibration));
		}

		// Force an initial reading
		m->r.buttons = 0;
		GetMouseReading(m);

		// Clear the screen using the GWIN default background color
		#if GFX_USE_GWIN
			gdispGClear(m->display, gwinGetDefaultBgColor());
		#else
			gdispGClear(m->display, GDISP_STARTUP_COLOR);
		#endif

		return err;
	}