Merge branch 'master' into rosh_for_hpa
[profile/ivi/syslinux.git] / memdisk / dskprobe.c
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2009 Shao Miller - All Rights Reserved
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8  *   Boston MA 02111-1307, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12
13 /*
14  * dskprobe.c
15  *
16  * Routines for probing BIOS disk drives
17  */
18
19 /*
20  * Uncomment for debugging
21  *
22  * #define DBG_DSKPROBE 1
23  */
24
25 #include <stdint.h>
26 #include "memdisk.h"
27 #include "bda.h"
28 #include "conio.h"
29
30 /*
31  * We will probe a BIOS drive numer using INT 13h, AH=probe
32  * and will pass along that call's success or failure
33  */
34 int probe_int13_ah(uint8_t drive, uint8_t probe)
35 {
36     int err;
37     com32sys_t regs;
38
39     memset(&regs, 0, sizeof regs);
40
41     regs.eax.b[1] = probe;      /* AH = probe                 */
42     regs.edx.b[0] = drive;      /* DL = drive number to probe */
43     intcall(0x13, &regs, &regs);
44
45     err = !(regs.eflags.l & 1);
46 #ifdef DBG_DSKPROBE
47     printf("probe_int13_ah(0x%02x, 0x%02x) == %d\n", drive, probe, err);
48 #endif
49     return err;
50 }
51
52 /*
53  * We will probe the BIOS Data Area and count the drives found there.
54  * This heuristic then assumes that all drives of 'drive's type are
55  * found in a contiguous range, and returns 1 if the probed drive
56  * is less than or equal to the BDA count.
57  * This particular function's code is derived from code in setup.c by
58  * H. Peter Anvin.  Please respect that file's copyright for this function
59  */
60 int probe_bda_drive(uint8_t drive)
61 {
62     int bios_drives;
63     int err;
64
65     if (drive & 0x80) {
66         bios_drives = rdz_8(BIOS_HD_COUNT);     /* HDD count */
67     } else {
68         uint8_t equip = rdz_8(BIOS_EQUIP);
69         if (equip & 1)
70             bios_drives = (equip >> 6) + 1;     /* Floppy count */
71         else
72             bios_drives = 0;
73     }
74     err = (drive - (drive & 0x80)) >= bios_drives ? 0 : 1;
75 #ifdef DBG_DSKPROBE
76     printf("probe_bda_drive(0x%02x) == %d, count: %d\n",
77            drive, err, bios_drives);
78 #endif
79     return err;
80 }
81
82 /*
83  * We will probe a drive with a few different methods, returning
84  * the count of succesful probes
85  */
86 int probe_drive(uint8_t drive)
87 {
88     int c = 0;
89     /* Only probe the BDA for floppies */
90     if (drive & 0x80) {
91         c += probe_int13_ah(drive, 0x08);
92         c += probe_int13_ah(drive, 0x15);
93         c += probe_int13_ah(drive, 0x41);
94     }
95     c += probe_bda_drive(drive);
96     return c;
97 }
98
99 /*
100  * We will probe a contiguous range of BIOS drive, starting with drive
101  * number 'start'.  We probe with a few different methods, and return
102  * the first drive which doesn't respond to any of the probes.
103  */
104 uint8_t probe_drive_range(uint8_t start)
105 {
106     uint8_t drive = start;
107     while (probe_drive(drive)) {
108         drive++;
109         /* Check for passing the floppy/HDD boundary */
110         if ((drive & 0x7F) == 0)
111             break;
112     }
113     return drive;
114 }