176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* ----------------------------------------------------------------------- *
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2009 Shao Miller - All Rights Reserved
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   This program is free software; you can redistribute it and/or modify
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   it under the terms of the GNU General Public License as published by
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Boston MA 02111-1307, USA; either version 2 of the License, or
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   (at your option) any later version; incorporated herein by reference.
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ----------------------------------------------------------------------- */
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * dskprobe.c
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Routines for probing BIOS disk drives
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Change to 1 for debugging */
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define DBG_DSKPROBE 0
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h>
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "memdisk.h"
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "bda.h"
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "conio.h"
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function type for printf() */
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantypedef int (f_printf) (const char *, ...);
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Dummy printf() that does nothing */
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic f_printf no_printf;
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic f_printf *dskprobe_printfs[] = { no_printf, printf };
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define dskprobe_printf (dskprobe_printfs[DBG_DSKPROBE])
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void dskprobe_pause(com32sys_t *);
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Probe routine function type */
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantypedef int (f_probe) (uint8_t, com32sys_t *);
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic f_probe probe_int13h_08h, probe_int13h_15h, probe_int13h_41h;
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* We will probe a BIOS drive number using INT 0x13, AH == func */
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void probe_any(uint8_t func, uint8_t drive, com32sys_t * regs)
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    regs->eax.b[1] = func;	/* AH == sub-function for probe */
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    regs->edx.b[0] = drive;	/* DL == drive number to probe */
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    intcall(0x13, regs, regs);
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Determine if the return from probe_int13h_01h indicates a failure; a
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return of zero indicates no known failure.
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_01h_fail(int istatus)
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int status = 0;
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (istatus >= 256)
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	status = istatus;
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (istatus) {
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case 1: status = istatus;
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return status;
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 0x13, AH == 0x01: Get status of last command.
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_01h(uint8_t drive)
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int status;
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    com32sys_t regs;
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(&regs, 0, sizeof regs);
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    probe_any(0x01, drive, &regs);
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = (regs.eflags.l & 1) * 256 + regs.eax.b[1];
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("  AH01: CF%d AH%02x", regs.eflags.l & 1, regs.eax.b[1]);
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return status;
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 0x13, AH == 0x08: Get drive parameters.
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_08h(uint8_t drive, com32sys_t * regs)
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int present;
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int status;
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(regs, 0, sizeof *regs);
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    probe_any(0x08, drive, regs);
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("  AH08: CF%d AH%02x AL%02x BL%02x DL%02x    ",
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    regs->eflags.l & 1, regs->eax.b[1], regs->eax.b[0],
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    regs->ebx.b[0], regs->edx.b[0]);
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    present = !(regs->eflags.l & 1) && !regs->eax.b[1];
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = probe_int13h_01h(drive);
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    present = present && !(probe_int13h_01h_fail(status));
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("  P%d\n",  present);
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return present;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 0x13, AH == 0x15: Get disk type.
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_15h(uint8_t drive, com32sys_t * regs)
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int present;
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int status;
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(regs, 0, sizeof *regs);
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    probe_any(0x15, drive, regs);
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("  AH15: CF%d AH%02x AL%02x CX%04x DX%04x",
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    regs->eflags.l & 1, regs->eax.b[1], regs->eax.b[0],
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    regs->ecx.w[0], regs->edx.w[0]);
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    present = !(regs->eflags.l & 1) && regs->eax.b[1];
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = probe_int13h_01h(drive);
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    present = present && !(probe_int13h_01h_fail(status));
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("  P%d\n",  present);
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return present;
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INT 0x13, AH == 0x41: INT 0x13 extensions installation check.
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int probe_int13h_41h(uint8_t drive, com32sys_t * regs)
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int present;
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int status;
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(regs, 0, sizeof *regs);
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    regs->ebx.w[0] = 0x55AA;	/* BX == 0x55AA */
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    probe_any(0x41, drive, regs);
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("  AH41: CF%d AH%02x BX%04x CX%04x DH%02x",
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    regs->eflags.l & 1, regs->eax.b[1], regs->ebx.w[0],
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    regs->ecx.w[0], regs->edx.b[1]);
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    present = !(regs->eflags.l & 1) && (regs->ebx.w[0] == 0xAA55);
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = probe_int13h_01h(drive);
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    present = present && !(probe_int13h_01h_fail(status));
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("  P%d\n",  present);
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return present;
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We will probe the BIOS Data Area and count the drives found there.
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This heuristic then assumes that all drives of 'drive's type are
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * found in a contiguous range, and returns 1 if the probed drive
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is less than or equal to the BDA count.
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This particular function's code is derived from code in setup.c by
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * H. Peter Anvin.  Please respect that file's copyright for this function
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint probe_bda_drive(uint8_t drive)
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int bios_drives;
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int err;
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (drive & 0x80) {
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	bios_drives = rdz_8(BIOS_HD_COUNT);	/* HDD count */
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t equip = rdz_8(BIOS_EQUIP);
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (equip & 1)
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    bios_drives = (equip >> 6) + 1;	/* Floppy count */
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    bios_drives = 0;
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    err = (drive - (drive & 0x80)) >= bios_drives ? 0 : 1;
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("BDA drive %02x? %d, total count: %d\n", drive, err,
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    bios_drives);
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return err;
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We will probe a drive with a few different methods, returning
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the count of succesful probes
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint multi_probe_drive(uint8_t drive)
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int c = 0;
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    com32sys_t regs;
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("INT 13 DL%02x:\n", drive);
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Only probe the BDA for floppies */
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (drive & 0x80) {
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	c += probe_int13h_08h(drive, &regs);
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	c += probe_int13h_15h(drive, &regs);
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	c += probe_int13h_41h(drive, &regs);
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    c += probe_bda_drive(drive);
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_pause(&regs);
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return c;
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * We will probe a contiguous range of BIOS drive, starting with drive
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * number 'start'.  We probe with a few different methods, and return
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the first drive which doesn't respond to any of the probes.
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanuint8_t probe_drive_range(uint8_t start)
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint8_t drive = start;
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (multi_probe_drive(drive)) {
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	drive++;
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Check for passing the floppy/HDD boundary */
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((drive & 0x7F) == 0)
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return drive;
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Dummy printf() that does nothing */
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int no_printf(const char *ignored, ...)
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (void)ignored;
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Pause if we are in debug-mode */
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void dskprobe_pause(com32sys_t * regs)
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!DBG_DSKPROBE)
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return;
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dskprobe_printf("Press a key to continue...\n");
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(regs, 0, sizeof *regs);
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    regs->eax.w[0] = 0;
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    intcall(0x16, regs, NULL);
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
229