blob: eb68e87983c0faff547b94f523669cebc1d447b6 [file] [log] [blame]
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05001// 16bit code to access hard drives.
2//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2002 MandrakeSoft S.A.
5//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05006// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05007
8#include "disk.h" // floppy_13
Kevin O'Connor9521e262008-07-04 13:04:29 -04009#include "biosvar.h" // SET_BDA
Kevin O'Connor3491e8b2008-02-29 00:22:27 -050010#include "config.h" // CONFIG_*
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050011#include "util.h" // debug_enter
Kevin O'Connorf54c1502008-06-14 15:56:16 -040012#include "pic.h" // eoi_pic2
Kevin O'Connor9521e262008-07-04 13:04:29 -040013#include "bregs.h" // struct bregs
Kevin O'Connor53236cc2008-08-31 11:16:33 -040014#include "pci.h" // pci_bdf_to_bus
Kevin O'Connorc892b132009-08-11 21:59:37 -040015#include "ata.h" // ATA_CB_DC
Kevin O'Connor3491e8b2008-02-29 00:22:27 -050016
Kevin O'Connorb74102d2008-03-03 21:57:30 -050017
18/****************************************************************
19 * Helper functions
20 ****************************************************************/
21
Kevin O'Connor567e4e32008-04-05 11:37:51 -040022void
Kevin O'Connor05600342009-01-02 13:10:58 -050023__disk_ret(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connor567e4e32008-04-05 11:37:51 -040024{
Kevin O'Connor05600342009-01-02 13:10:58 -050025 u8 code = linecode;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -040026 if (regs->dl < EXTSTART_HD)
Kevin O'Connor48410fd2009-08-16 14:13:36 -040027 SET_BDA(floppy_last_status, code);
28 else
29 SET_BDA(disk_last_status, code);
Kevin O'Connor567e4e32008-04-05 11:37:51 -040030 if (code)
Kevin O'Connordfefeb52009-12-13 13:04:17 -050031 __set_code_invalid(regs, linecode, fname);
Kevin O'Connor567e4e32008-04-05 11:37:51 -040032 else
33 set_code_success(regs);
34}
35
Kevin O'Connordfefeb52009-12-13 13:04:17 -050036void
37__disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
38{
39 u8 code = linecode;
40 if (regs->dl < EXTSTART_HD)
41 SET_BDA(floppy_last_status, code);
42 else
43 SET_BDA(disk_last_status, code);
44 __set_code_unimplemented(regs, linecode, fname);
45}
46
Kevin O'Connor567e4e32008-04-05 11:37:51 -040047static void
Kevin O'Connor05600342009-01-02 13:10:58 -050048__disk_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor567e4e32008-04-05 11:37:51 -040049{
Kevin O'Connordfefeb52009-12-13 13:04:17 -050050 __warn_unimplemented(regs, lineno, fname);
Kevin O'Connor05600342009-01-02 13:10:58 -050051 __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
Kevin O'Connor567e4e32008-04-05 11:37:51 -040052}
53
Kevin O'Connor05600342009-01-02 13:10:58 -050054#define DISK_STUB(regs) \
55 __disk_stub((regs), __LINE__, __func__)
Kevin O'Connore43df9e2008-03-01 22:16:32 -050056
Kevin O'Connor5c99b6c2009-12-30 12:36:22 -050057// Get the cylinders/heads/sectors for the given drive.
Kevin O'Connor36c93a52009-09-12 19:35:04 -040058static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -040059fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt)
Kevin O'Connore43df9e2008-03-01 22:16:32 -050060{
Kevin O'Connor77d227b2009-10-22 21:48:39 -040061 if (CONFIG_CDROM_EMU && drive_g == GET_GLOBAL(cdemu_drive)) {
Kevin O'Connor36c93a52009-09-12 19:35:04 -040062 // Emulated drive - get info from ebda. (It's not possible to
63 // populate the geometry directly in the driveid because the
64 // geometry is only known after the bios segment is made
65 // read-only).
66 u16 ebda_seg = get_ebda_seg();
67 *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
68 *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
69 *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
70 return;
Kevin O'Connor0cdac0e2008-03-29 12:45:53 -040071 }
Kevin O'Connor77d227b2009-10-22 21:48:39 -040072 *nlc = GET_GLOBAL(drive_g->lchs.cylinders);
73 *nlh = GET_GLOBAL(drive_g->lchs.heads);
74 *nlspt = GET_GLOBAL(drive_g->lchs.spt);
Kevin O'Connor1625a752009-08-09 13:08:21 -040075}
76
77// Perform read/write/verify using old-style chs accesses
78static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -040079basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
Kevin O'Connor1625a752009-08-09 13:08:21 -040080{
81 struct disk_op_s dop;
Kevin O'Connor77d227b2009-10-22 21:48:39 -040082 dop.drive_g = drive_g;
Kevin O'Connor1625a752009-08-09 13:08:21 -040083 dop.command = command;
Kevin O'Connor36c93a52009-09-12 19:35:04 -040084
85 u8 count = regs->al;
86 u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
87 u16 sector = regs->cl & 0x3f;
88 u16 head = regs->dh;
89
90 if (count > 128 || count == 0 || sector == 0) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -050091 warn_invalid(regs);
Kevin O'Connor36c93a52009-09-12 19:35:04 -040092 disk_ret(regs, DISK_RET_EPARAM);
Kevin O'Connor1625a752009-08-09 13:08:21 -040093 return;
Kevin O'Connor36c93a52009-09-12 19:35:04 -040094 }
95 dop.count = count;
96
97 u16 nlc, nlh, nlspt;
Kevin O'Connor77d227b2009-10-22 21:48:39 -040098 fillLCHS(drive_g, &nlc, &nlh, &nlspt);
Kevin O'Connor36c93a52009-09-12 19:35:04 -040099
100 // sanity check on cyl heads, sec
101 if (cylinder >= nlc || head >= nlh || sector > nlspt) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500102 warn_invalid(regs);
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400103 disk_ret(regs, DISK_RET_EPARAM);
104 return;
105 }
106
107 // translate lchs to lba
108 dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
109 + (u32)sector - 1);
110
Kevin O'Connorb68ac712009-08-09 17:25:19 -0400111 dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400112
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500113 int status = send_disk_op(&dop);
Kevin O'Connor74799df2008-03-12 20:49:07 -0400114
Kevin O'Connor1625a752009-08-09 13:08:21 -0400115 regs->al = dop.count;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500116
Kevin O'Connor126eac62009-08-16 13:32:24 -0400117 disk_ret(regs, status);
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500118}
119
Kevin O'Connor1625a752009-08-09 13:08:21 -0400120// Perform read/write/verify using new-style "int13ext" accesses.
Kevin O'Connored128492008-03-11 11:14:59 -0400121static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400122extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500123{
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500124 struct disk_op_s dop;
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400125 // Get lba and check.
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500126 dop.lba = GET_INT13EXT(regs, lba);
127 dop.command = command;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400128 dop.drive_g = drive_g;
129 if (dop.lba >= GET_GLOBAL(drive_g->sectors)) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500130 warn_invalid(regs);
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400131 disk_ret(regs, DISK_RET_EPARAM);
132 return;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500133 }
134
Kevin O'Connor9f985422009-09-09 11:34:39 -0400135 dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data));
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500136 dop.count = GET_INT13EXT(regs, count);
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400137
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500138 int status = send_disk_op(&dop);
Kevin O'Connor74799df2008-03-12 20:49:07 -0400139
Kevin O'Connor1625a752009-08-09 13:08:21 -0400140 SET_INT13EXT(regs, count, dop.count);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500141
Kevin O'Connor126eac62009-08-16 13:32:24 -0400142 disk_ret(regs, status);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500143}
144
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500145
146/****************************************************************
147 * Hard Drive functions
148 ****************************************************************/
149
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500150// disk controller reset
151static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400152disk_1300(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500153{
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400154 struct disk_op_s dop;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400155 dop.drive_g = drive_g;
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400156 dop.command = CMD_RESET;
Kevin O'Connor126eac62009-08-16 13:32:24 -0400157 int status = send_disk_op(&dop);
158 disk_ret(regs, status);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500159}
160
161// read disk status
162static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400163disk_1301(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500164{
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400165 u8 v;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400166 if (regs->dl < EXTSTART_HD)
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400167 // Floppy
168 v = GET_BDA(floppy_last_status);
169 else
170 v = GET_BDA(disk_last_status);
Kevin O'Connorfad2da82008-03-22 20:37:44 -0400171 regs->ah = v;
172 set_cf(regs, v);
173 // XXX - clear disk_last_status?
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500174}
175
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500176// read disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500177static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400178disk_1302(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500179{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400180 basic_access(regs, drive_g, CMD_READ);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500181}
182
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500183// write disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500184static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400185disk_1303(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500186{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400187 basic_access(regs, drive_g, CMD_WRITE);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500188}
189
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500190// verify disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500191static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400192disk_1304(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500193{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400194 basic_access(regs, drive_g, CMD_VERIFY);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500195}
196
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500197// format disk track
198static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400199disk_1305(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500200{
Kevin O'Connor4d9d4002009-11-25 19:35:01 -0500201 debug_stub(regs);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400202
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400203 u16 nlc, nlh, nlspt;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400204 fillLCHS(drive_g, &nlc, &nlh, &nlspt);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400205
206 u8 num_sectors = regs->al;
207 u8 head = regs->dh;
208
209 if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) {
210 disk_ret(regs, DISK_RET_EPARAM);
211 return;
212 }
213
214 struct disk_op_s dop;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400215 dop.drive_g = drive_g;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400216 dop.command = CMD_FORMAT;
217 dop.lba = head;
218 dop.count = num_sectors;
219 dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
220 int status = send_disk_op(&dop);
221 disk_ret(regs, status);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500222}
223
224// read disk drive parameters
225static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400226disk_1308(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500227{
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400228 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500229 // Get logical geometry from table
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400230 u16 nlc, nlh, nlspt;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400231 fillLCHS(drive_g, &nlc, &nlh, &nlspt);
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400232 nlc--;
233 nlh--;
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400234 u8 count;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400235 if (regs->dl < EXTSTART_HD) {
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400236 // Floppy
237 count = GET_GLOBAL(Drives.floppycount);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500238
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400239 if (CONFIG_CDROM_EMU && drive_g == GET_GLOBAL(cdemu_drive))
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400240 regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
241 else
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400242 regs->bx = GET_GLOBAL(drive_g->floppy_type);
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400243
244 // set es & di to point to 11 byte diskette param table in ROM
245 regs->es = SEG_BIOS;
246 regs->di = (u32)&diskette_param_table2;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400247 } else if (regs->dl < EXTSTART_CD) {
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400248 // Hard drive
249 count = GET_BDA(hdcount);
250 nlc--; // last sector reserved
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400251 } else {
252 // Not supported on CDROM
253 disk_ret(regs, DISK_RET_EPARAM);
254 return;
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400255 }
256
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400257 if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) {
258 u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
259 if (((emudrive ^ regs->dl) & 0x80) == 0)
260 // Note extra drive due to emulation.
261 count++;
262 if (regs->dl < EXTSTART_HD && count > 2)
263 // Max of two floppy drives.
264 count = 2;
265 }
266
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500267 regs->al = 0;
268 regs->ch = nlc & 0xff;
269 regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400270 regs->dh = nlh;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500271
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500272 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400273 regs->dl = count;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500274}
275
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500276// initialize drive parameters
277static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400278disk_1309(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500279{
280 DISK_STUB(regs);
281}
282
283// seek to specified cylinder
284static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400285disk_130c(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500286{
287 DISK_STUB(regs);
288}
289
290// alternate disk reset
291static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400292disk_130d(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500293{
294 DISK_STUB(regs);
295}
296
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500297// check drive ready
298static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400299disk_1310(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500300{
301 // should look at 40:8E also???
302
Kevin O'Connor42337662009-08-10 00:06:37 -0400303 struct disk_op_s dop;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400304 dop.drive_g = drive_g;
Kevin O'Connor42337662009-08-10 00:06:37 -0400305 dop.command = CMD_ISREADY;
306 int status = send_disk_op(&dop);
Kevin O'Connor126eac62009-08-16 13:32:24 -0400307 disk_ret(regs, status);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500308}
309
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500310// recalibrate
311static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400312disk_1311(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500313{
314 DISK_STUB(regs);
315}
316
317// controller internal diagnostic
318static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400319disk_1314(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500320{
321 DISK_STUB(regs);
322}
323
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500324// read disk drive size
325static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400326disk_1315(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500327{
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400328 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400329 if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) {
330 // Floppy or cdrom
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400331 regs->ah = 1;
332 return;
333 }
334 // Hard drive
335
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500336 // Get logical geometry from table
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400337 u16 nlc, nlh, nlspt;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400338 fillLCHS(drive_g, &nlc, &nlh, &nlspt);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500339
340 // Compute sector count seen by int13
341 u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
342 regs->cx = lba >> 16;
343 regs->dx = lba & 0xffff;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500344 regs->ah = 3; // hard disk accessible
345}
346
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400347static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400348disk_1316(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400349{
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400350 if (regs->dl >= EXTSTART_HD) {
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400351 // Hard drive
352 disk_ret(regs, DISK_RET_EPARAM);
353 return;
354 }
355 disk_ret(regs, DISK_RET_ECHANGED);
356}
357
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500358// IBM/MS installation check
359static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400360disk_1341(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500361{
362 regs->bx = 0xaa55; // install check
363 regs->cx = 0x0007; // ext disk access and edd, removable supported
364 disk_ret(regs, DISK_RET_SUCCESS);
365 regs->ah = 0x30; // EDD 3.0
366}
367
368// IBM/MS extended read
369static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400370disk_1342(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500371{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400372 extended_access(regs, drive_g, CMD_READ);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500373}
374
375// IBM/MS extended write
376static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400377disk_1343(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500378{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400379 extended_access(regs, drive_g, CMD_WRITE);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500380}
381
382// IBM/MS verify
383static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400384disk_1344(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500385{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400386 extended_access(regs, drive_g, CMD_VERIFY);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500387}
388
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400389// lock
390static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400391disk_134500(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400392{
393 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400394 int cdid = regs->dl - EXTSTART_CD;
395 u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400396 if (locks == 0xff) {
397 regs->al = 1;
398 disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
399 return;
400 }
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400401 SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks + 1);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400402 regs->al = 1;
403 disk_ret(regs, DISK_RET_SUCCESS);
404}
405
406// unlock
407static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400408disk_134501(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400409{
410 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400411 int cdid = regs->dl - EXTSTART_CD;
412 u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400413 if (locks == 0x00) {
414 regs->al = 0;
415 disk_ret(regs, DISK_RET_ENOTLOCKED);
416 return;
417 }
418 locks--;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400419 SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400420 regs->al = (locks ? 1 : 0);
421 disk_ret(regs, DISK_RET_SUCCESS);
422}
423
424// status
425static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400426disk_134502(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400427{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400428 int cdid = regs->dl - EXTSTART_CD;
429 u8 locks = GET_EBDA(cdrom_locks[cdid]);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400430 regs->al = (locks ? 1 : 0);
431 disk_ret(regs, DISK_RET_SUCCESS);
432}
433
434static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400435disk_1345XX(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400436{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500437 disk_ret_unimplemented(regs, DISK_RET_EPARAM);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400438}
439
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500440// IBM/MS lock/unlock drive
441static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400442disk_1345(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500443{
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400444 if (regs->dl < EXTSTART_CD) {
445 // Always success for HD
446 disk_ret(regs, DISK_RET_SUCCESS);
447 return;
448 }
449
450 switch (regs->al) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400451 case 0x00: disk_134500(regs, drive_g); break;
452 case 0x01: disk_134501(regs, drive_g); break;
453 case 0x02: disk_134502(regs, drive_g); break;
454 default: disk_1345XX(regs, drive_g); break;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400455 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500456}
457
458// IBM/MS eject media
459static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400460disk_1346(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500461{
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400462 if (regs->dl < EXTSTART_CD) {
463 // Volume Not Removable
464 disk_ret(regs, DISK_RET_ENOTREMOVABLE);
465 return;
466 }
467
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400468 int cdid = regs->dl - EXTSTART_CD;
469 u8 locks = GET_EBDA(cdrom_locks[cdid]);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400470 if (locks != 0) {
471 disk_ret(regs, DISK_RET_ELOCKED);
472 return;
473 }
474
475 // FIXME should handle 0x31 no media in device
476 // FIXME should handle 0xb5 valid request failed
477
478 // Call removable media eject
479 struct bregs br;
480 memset(&br, 0, sizeof(br));
481 br.ah = 0x52;
482 call16_int(0x15, &br);
483
484 if (br.ah || br.flags & F_CF) {
485 disk_ret(regs, DISK_RET_ELOCKED);
486 return;
487 }
488 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500489}
490
491// IBM/MS extended seek
492static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400493disk_1347(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500494{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400495 extended_access(regs, drive_g, CMD_SEEK);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500496}
497
498// IBM/MS get drive parameters
499static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400500disk_1348(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500501{
502 u16 size = GET_INT13DPT(regs, size);
503
504 // Buffer is too small
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400505 if (size < 26) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500506 disk_ret(regs, DISK_RET_EPARAM);
507 return;
508 }
509
510 // EDD 1.x
511
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400512 u8 type = GET_GLOBAL(drive_g->type);
513 u16 npc = GET_GLOBAL(drive_g->pchs.cylinders);
514 u16 nph = GET_GLOBAL(drive_g->pchs.heads);
515 u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
516 u64 lba = GET_GLOBAL(drive_g->sectors);
517 u16 blksize = GET_GLOBAL(drive_g->blksize);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500518
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400519 dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
520 , size, type, npc, nph, npspt, (u32)lba, blksize);
521
522 SET_INT13DPT(regs, size, 26);
Kevin O'Connorb1144362009-08-11 20:43:38 -0400523 if (type == DTYPE_ATAPI) {
524 // 0x74 = removable, media change, lockable, max values
525 SET_INT13DPT(regs, infos, 0x74);
526 SET_INT13DPT(regs, cylinders, 0xffffffff);
527 SET_INT13DPT(regs, heads, 0xffffffff);
528 SET_INT13DPT(regs, spt, 0xffffffff);
529 SET_INT13DPT(regs, sector_count, (u64)-1);
530 } else {
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400531 if (lba > (u64)npspt*nph*0x3fff) {
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500532 SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
533 SET_INT13DPT(regs, cylinders, 0x3fff);
534 } else {
535 SET_INT13DPT(regs, infos, 0x02); // geometry is valid
536 SET_INT13DPT(regs, cylinders, (u32)npc);
537 }
538 SET_INT13DPT(regs, heads, (u32)nph);
539 SET_INT13DPT(regs, spt, (u32)npspt);
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400540 SET_INT13DPT(regs, sector_count, lba);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500541 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500542 SET_INT13DPT(regs, blksize, blksize);
543
Kevin O'Connorb1144362009-08-11 20:43:38 -0400544 if (size < 30 || (type != DTYPE_ATA && type != DTYPE_ATAPI)) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500545 disk_ret(regs, DISK_RET_SUCCESS);
546 return;
547 }
548
549 // EDD 2.x
550
Kevin O'Connor08815372008-12-29 21:16:31 -0500551 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400552 SET_INT13DPT(regs, size, 30);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500553
Kevin O'Connor08815372008-12-29 21:16:31 -0500554 SET_INT13DPT(regs, dpte_segment, ebda_seg);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500555 SET_INT13DPT(regs, dpte_offset
Kevin O'Connor609da232008-12-28 23:18:57 -0500556 , offsetof(struct extended_bios_data_area_s, dpte));
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500557
558 // Fill in dpte
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400559 u8 ataid = GET_GLOBAL(drive_g->cntl_id);
Kevin O'Connorb1144362009-08-11 20:43:38 -0400560 u8 channel = ataid / 2;
561 u8 slave = ataid % 2;
Kevin O'Connorc892b132009-08-11 21:59:37 -0400562 u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
563 u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
564 u8 irq = GET_GLOBAL(ATA_channels[channel].irq);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500565
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400566 u16 options = 0;
Kevin O'Connor42337662009-08-10 00:06:37 -0400567 if (type == DTYPE_ATA) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400568 u8 translation = GET_GLOBAL(drive_g->translation);
Kevin O'Connor42337662009-08-10 00:06:37 -0400569 if (translation != TRANSLATION_NONE) {
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400570 options |= 1<<3; // CHS translation
Kevin O'Connor42337662009-08-10 00:06:37 -0400571 if (translation == TRANSLATION_LBA)
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400572 options |= 1<<9;
Kevin O'Connor42337662009-08-10 00:06:37 -0400573 if (translation == TRANSLATION_RECHS)
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400574 options |= 3<<9;
575 }
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500576 } else {
577 // ATAPI
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400578 options |= 1<<5; // removable device
579 options |= 1<<6; // atapi device
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500580 }
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400581 options |= 1<<4; // lba translation
Kevin O'Connor32945af2009-02-27 21:23:01 -0500582 if (CONFIG_ATA_PIO32)
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400583 options |= 1<<7;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500584
Kevin O'Connor08815372008-12-29 21:16:31 -0500585 SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
586 SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
587 SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
588 | ATA_CB_DH_LBA));
589 SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
590 SET_EBDA2(ebda_seg, dpte.irq, irq);
591 SET_EBDA2(ebda_seg, dpte.blkcount, 1);
592 SET_EBDA2(ebda_seg, dpte.dma, 0);
593 SET_EBDA2(ebda_seg, dpte.pio, 0);
594 SET_EBDA2(ebda_seg, dpte.options, options);
595 SET_EBDA2(ebda_seg, dpte.reserved, 0);
596 SET_EBDA2(ebda_seg, dpte.revision, 0x11);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500597
Kevin O'Connor8b267cb2009-01-19 19:25:21 -0500598 u8 sum = checksum_far(
599 ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15);
600 SET_EBDA2(ebda_seg, dpte.checksum, -sum);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500601
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400602 if (size < 66) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500603 disk_ret(regs, DISK_RET_SUCCESS);
604 return;
605 }
606
607 // EDD 3.x
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500608 SET_INT13DPT(regs, key, 0xbedd);
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400609 SET_INT13DPT(regs, dpi_length, 36);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500610 SET_INT13DPT(regs, reserved1, 0);
611 SET_INT13DPT(regs, reserved2, 0);
612
Kevin O'Connor4ccb2312009-12-05 11:25:09 -0500613 int bdf = GET_GLOBAL(ATA_channels[channel].pci_bdf);
614 if (bdf != -1) {
615 SET_INT13DPT(regs, host_bus[0], 'P');
616 SET_INT13DPT(regs, host_bus[1], 'C');
617 SET_INT13DPT(regs, host_bus[2], 'I');
618 SET_INT13DPT(regs, host_bus[3], 0);
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400619
Kevin O'Connor4ccb2312009-12-05 11:25:09 -0500620 u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
621 | (pci_bdf_to_fn(bdf) << 16));
622 SET_INT13DPT(regs, iface_path, path);
623 } else {
624 // ISA
625 SET_INT13DPT(regs, host_bus[0], 'I');
626 SET_INT13DPT(regs, host_bus[1], 'S');
627 SET_INT13DPT(regs, host_bus[2], 'A');
628 SET_INT13DPT(regs, host_bus[3], 0);
629
630 SET_INT13DPT(regs, iface_path, iobase1);
631 }
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400632
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500633 SET_INT13DPT(regs, iface_type[0], 'A');
634 SET_INT13DPT(regs, iface_type[1], 'T');
635 SET_INT13DPT(regs, iface_type[2], 'A');
636 SET_INT13DPT(regs, iface_type[3], 0);
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400637 SET_INT13DPT(regs, iface_type[4], 0);
638 SET_INT13DPT(regs, iface_type[5], 0);
639 SET_INT13DPT(regs, iface_type[6], 0);
640 SET_INT13DPT(regs, iface_type[7], 0);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500641
Kevin O'Connor970a0322008-10-26 12:01:21 -0400642 SET_INT13DPT(regs, device_path, slave);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500643
Kevin O'Connor7d108212009-01-21 19:13:21 -0500644 SET_INT13DPT(regs, checksum
645 , -checksum_far(regs->ds, (void*)(regs->si+30), 35));
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400646
647 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500648}
649
650// IBM/MS extended media change
651static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400652disk_1349(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500653{
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400654 if (regs->dl < EXTSTART_CD) {
655 // Always success for HD
656 disk_ret(regs, DISK_RET_SUCCESS);
657 return;
658 }
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500659 set_invalid(regs);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400660 // always send changed ??
661 regs->ah = DISK_RET_ECHANGED;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500662}
663
664static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400665disk_134e01(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500666{
667 disk_ret(regs, DISK_RET_SUCCESS);
668}
669
670static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400671disk_134e03(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500672{
673 disk_ret(regs, DISK_RET_SUCCESS);
674}
675
676static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400677disk_134e04(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500678{
679 disk_ret(regs, DISK_RET_SUCCESS);
680}
681
682static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400683disk_134e06(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500684{
685 disk_ret(regs, DISK_RET_SUCCESS);
686}
687
688static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400689disk_134eXX(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500690{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500691 disk_ret(regs, DISK_RET_EPARAM);
692}
693
694// IBM/MS set hardware configuration
695static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400696disk_134e(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500697{
698 switch (regs->al) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400699 case 0x01: disk_134e01(regs, drive_g); break;
700 case 0x03: disk_134e03(regs, drive_g); break;
701 case 0x04: disk_134e04(regs, drive_g); break;
702 case 0x06: disk_134e06(regs, drive_g); break;
703 default: disk_134eXX(regs, drive_g); break;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500704 }
705}
706
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400707static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400708disk_13XX(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500709{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500710 disk_ret_unimplemented(regs, DISK_RET_EPARAM);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500711}
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500712
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400713static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400714disk_13(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500715{
Kevin O'Connor15aee2e2008-03-01 13:34:04 -0500716 //debug_stub(regs);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500717
718 // clear completion flag
719 SET_BDA(disk_interrupt_flag, 0);
720
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500721 switch (regs->ah) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400722 case 0x00: disk_1300(regs, drive_g); break;
723 case 0x01: disk_1301(regs, drive_g); break;
724 case 0x02: disk_1302(regs, drive_g); break;
725 case 0x03: disk_1303(regs, drive_g); break;
726 case 0x04: disk_1304(regs, drive_g); break;
727 case 0x05: disk_1305(regs, drive_g); break;
728 case 0x08: disk_1308(regs, drive_g); break;
729 case 0x09: disk_1309(regs, drive_g); break;
730 case 0x0c: disk_130c(regs, drive_g); break;
731 case 0x0d: disk_130d(regs, drive_g); break;
732 case 0x10: disk_1310(regs, drive_g); break;
733 case 0x11: disk_1311(regs, drive_g); break;
734 case 0x14: disk_1314(regs, drive_g); break;
735 case 0x15: disk_1315(regs, drive_g); break;
736 case 0x16: disk_1316(regs, drive_g); break;
737 case 0x41: disk_1341(regs, drive_g); break;
738 case 0x42: disk_1342(regs, drive_g); break;
739 case 0x43: disk_1343(regs, drive_g); break;
740 case 0x44: disk_1344(regs, drive_g); break;
741 case 0x45: disk_1345(regs, drive_g); break;
742 case 0x46: disk_1346(regs, drive_g); break;
743 case 0x47: disk_1347(regs, drive_g); break;
744 case 0x48: disk_1348(regs, drive_g); break;
745 case 0x49: disk_1349(regs, drive_g); break;
746 case 0x4e: disk_134e(regs, drive_g); break;
747 default: disk_13XX(regs, drive_g); break;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500748 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500749}
750
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400751static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400752floppy_13(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400753{
754 // Only limited commands are supported on floppies.
755 switch (regs->ah) {
756 case 0x00:
757 case 0x01:
758 case 0x02:
759 case 0x03:
760 case 0x04:
761 case 0x05:
762 case 0x08:
763 case 0x15:
764 case 0x16:
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400765 disk_13(regs, drive_g);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400766 break;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400767 default: disk_13XX(regs, drive_g); break;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400768 }
769}
770
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500771
772/****************************************************************
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500773 * Entry points
774 ****************************************************************/
775
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500776static void
Kevin O'Connor707298a2009-08-11 22:27:51 -0400777handle_legacy_disk(struct bregs *regs, u8 extdrive)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500778{
Kevin O'Connorc892b132009-08-11 21:59:37 -0400779 if (! CONFIG_DRIVES) {
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400780 // XXX - support handle_1301 anyway?
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500781 disk_ret(regs, DISK_RET_EPARAM);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500782 return;
783 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500784
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400785 if (extdrive < EXTSTART_HD) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400786 struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, extdrive);
787 if (!drive_g)
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400788 goto fail;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400789 floppy_13(regs, drive_g);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400790 return;
791 }
792
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400793 struct drive_s *drive_g;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400794 if (extdrive >= EXTSTART_CD)
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400795 drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400796 else
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400797 drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
798 if (!drive_g)
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400799 goto fail;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400800 disk_13(regs, drive_g);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400801 return;
802
803fail:
804 // XXX - support 1301/1308/1315 anyway?
805 disk_ret(regs, DISK_RET_EPARAM);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500806}
807
Kevin O'Connor19786762008-03-05 21:09:59 -0500808void VISIBLE16
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500809handle_40(struct bregs *regs)
810{
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400811 debug_enter(regs, DEBUG_HDL_40);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500812 handle_legacy_disk(regs, regs->dl);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500813}
814
815// INT 13h Fixed Disk Services Entry Point
Kevin O'Connor19786762008-03-05 21:09:59 -0500816void VISIBLE16
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500817handle_13(struct bregs *regs)
818{
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400819 debug_enter(regs, DEBUG_HDL_13);
Kevin O'Connor707298a2009-08-11 22:27:51 -0400820 u8 extdrive = regs->dl;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500821
Kevin O'Connordfa16502008-03-22 20:13:08 -0400822 if (CONFIG_CDROM_EMU) {
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500823 if (regs->ah == 0x4b) {
824 cdemu_134b(regs);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400825 return;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500826 }
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500827 u16 ebda_seg = get_ebda_seg();
828 if (GET_EBDA2(ebda_seg, cdemu.active)) {
Kevin O'Connor669e6442009-08-11 22:36:30 -0400829 u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
Kevin O'Connor707298a2009-08-11 22:27:51 -0400830 if (extdrive == emudrive) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400831 // Access to an emulated drive.
832 struct drive_s *cdemu = GET_GLOBAL(cdemu_drive);
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400833 if (regs->ah > 0x16) {
834 // Only old-style commands supported.
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400835 disk_13XX(regs, cdemu);
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400836 return;
837 }
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400838 disk_13(regs, cdemu);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400839 return;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500840 }
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400841 if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400842 // Adjust id to make room for emulated drive.
Kevin O'Connor707298a2009-08-11 22:27:51 -0400843 extdrive--;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500844 }
845 }
Kevin O'Connor707298a2009-08-11 22:27:51 -0400846 handle_legacy_disk(regs, extdrive);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500847}
848
849// record completion in BIOS task complete flag
Kevin O'Connor19786762008-03-05 21:09:59 -0500850void VISIBLE16
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500851handle_76(void)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500852{
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400853 debug_isr(DEBUG_ISR_76);
Kevin O'Connored128492008-03-11 11:14:59 -0400854 SET_BDA(disk_interrupt_flag, 0xff);
Kevin O'Connorf54c1502008-06-14 15:56:16 -0400855 eoi_pic2();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500856}
Kevin O'Connor30853762009-01-17 18:49:20 -0500857
858// Old Fixed Disk Parameter Table (newer tables are in the ebda).
859struct fdpt_s OldFDPT VAR16FIXED(0xe401);