blob: ee2c983c953ae99d1987788104ee6ed37c85e914 [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//
6// This file may be distributed under the terms of the GNU GPLv3 license.
7
8#include "disk.h" // floppy_13
9#include "biosvar.h" // struct bregs
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'Connor3491e8b2008-02-29 00:22:27 -050012#include "ata.h" // ATA_*
13
Kevin O'Connorf205f9f2008-03-09 16:11:49 -040014#define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args)
15#define DEBUGF(fmt, args...)
16
Kevin O'Connorb74102d2008-03-03 21:57:30 -050017
18/****************************************************************
19 * Helper functions
20 ****************************************************************/
21
Kevin O'Connor567e4e32008-04-05 11:37:51 -040022void
23__disk_ret(const char *fname, struct bregs *regs, u8 code)
24{
25 SET_BDA(disk_last_status, code);
26 if (code)
27 __set_code_fail(fname, regs, code);
28 else
29 set_code_success(regs);
30}
31
32static void
33__disk_stub(const char *fname, struct bregs *regs)
34{
35 __debug_stub(fname, regs);
36 __disk_ret(fname, regs, DISK_RET_SUCCESS);
37}
38
39#define DISK_STUB(regs) \
40 __disk_stub(__func__, (regs))
Kevin O'Connore43df9e2008-03-01 22:16:32 -050041
Kevin O'Connore43df9e2008-03-01 22:16:32 -050042static void
43basic_access(struct bregs *regs, u8 device, u16 command)
44{
Kevin O'Connoraa2590c2008-03-22 23:13:24 -040045 u8 type = GET_EBDA(ata.devices[device].type);
46 u16 nlc, nlh, nlspt;
47 if (type == ATA_TYPE_ATA) {
48 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
49 nlh = GET_EBDA(ata.devices[device].lchs.heads);
50 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
51 } else {
52 // Must be cd emulation.
53 nlc = GET_EBDA(cdemu.vdevice.cylinders);
54 nlh = GET_EBDA(cdemu.vdevice.heads);
55 nlspt = GET_EBDA(cdemu.vdevice.spt);
56 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -050057
Kevin O'Connor0cdac0e2008-03-29 12:45:53 -040058 u16 count = regs->al;
59 u16 cylinder = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
60 u16 sector = regs->cl & 0x3f;
61 u16 head = regs->dh;
62
63 if (count > 128 || count == 0 || sector == 0) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -040064 dprintf(1, "int13_harddisk: function %02x, parameter out of range!\n"
Kevin O'Connor0cdac0e2008-03-29 12:45:53 -040065 , regs->ah);
66 disk_ret(regs, DISK_RET_EPARAM);
67 return;
68 }
69
Kevin O'Connore43df9e2008-03-01 22:16:32 -050070 // sanity check on cyl heads, sec
Kevin O'Connor1fcf1442008-03-11 19:42:41 -040071 if (cylinder >= nlc || head >= nlh || sector > nlspt) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -040072 dprintf(1, "int13_harddisk: function %02x, parameters out of"
Kevin O'Connore43df9e2008-03-01 22:16:32 -050073 " range %04x/%04x/%04x!\n"
74 , regs->ah, cylinder, head, sector);
75 disk_ret(regs, DISK_RET_EPARAM);
76 return;
77 }
78
Kevin O'Connor3a049632008-03-11 11:48:04 -040079 if (!command) {
80 // If verify or seek
Kevin O'Connore43df9e2008-03-01 22:16:32 -050081 disk_ret(regs, DISK_RET_SUCCESS);
82 return;
83 }
84
Kevin O'Connor049d5a22008-03-13 19:09:49 -040085 // translate lchs to lba
86 u32 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
Kevin O'Connor1fcf1442008-03-11 19:42:41 -040087 + (u32)sector - 1);
Kevin O'Connoraa2590c2008-03-22 23:13:24 -040088
89 u16 segment = regs->es;
90 u16 offset = regs->bx;
91 void *far_buffer = MAKE_FARPTR(segment, offset);
92
Kevin O'Connor049d5a22008-03-13 19:09:49 -040093 irq_enable();
Kevin O'Connoraa2590c2008-03-22 23:13:24 -040094
95 int status;
96 if (type == ATA_TYPE_ATA)
97 status = ata_cmd_data(device, command, lba, count, far_buffer);
98 else
99 status = cdrom_read_emu(device, lba, count, far_buffer);
100
Kevin O'Connor74799df2008-03-12 20:49:07 -0400101 irq_disable();
102
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500103 // Set nb of sector transferred
104 regs->al = GET_EBDA(ata.trsfsectors);
105
106 if (status != 0) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400107 dprintf(1, "int13_harddisk: function %02x, error %02x !\n"
Kevin O'Connorfad2da82008-03-22 20:37:44 -0400108 , regs->ah, status);
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500109 disk_ret(regs, DISK_RET_EBADTRACK);
110 }
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500111 disk_ret(regs, DISK_RET_SUCCESS);
112}
113
Kevin O'Connored128492008-03-11 11:14:59 -0400114static void
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500115extended_access(struct bregs *regs, u8 device, u16 command)
116{
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400117 // Get lba and check.
118 u64 lba = GET_INT13EXT(regs, lba);
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500119 u8 type = GET_EBDA(ata.devices[device].type);
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500120 if (type == ATA_TYPE_ATA
121 && lba >= GET_EBDA(ata.devices[device].sectors)) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400122 dprintf(1, "int13_harddisk: function %02x. LBA out of range\n"
123 , regs->ah);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500124 disk_ret(regs, DISK_RET_EPARAM);
125 return;
126 }
127
Kevin O'Connor3a049632008-03-11 11:48:04 -0400128 if (!command) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500129 // If verify or seek
130 disk_ret(regs, DISK_RET_SUCCESS);
131 return;
132 }
133
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400134 u16 segment = GET_INT13EXT(regs, segment);
135 u16 offset = GET_INT13EXT(regs, offset);
136 void *far_buffer = MAKE_FARPTR(segment, offset);
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400137 u16 count = GET_INT13EXT(regs, count);
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400138
Kevin O'Connor74799df2008-03-12 20:49:07 -0400139 irq_enable();
140
Kevin O'Connor3a049632008-03-11 11:48:04 -0400141 u8 status;
142 if (type == ATA_TYPE_ATA)
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400143 status = ata_cmd_data(device, command, lba, count, far_buffer);
Kevin O'Connor3a049632008-03-11 11:48:04 -0400144 else
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400145 status = cdrom_read(device, lba, count, far_buffer);
Kevin O'Connor3a049632008-03-11 11:48:04 -0400146
Kevin O'Connor74799df2008-03-12 20:49:07 -0400147 irq_disable();
148
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500149 SET_INT13EXT(regs, count, GET_EBDA(ata.trsfsectors));
150
151 if (status != 0) {
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400152 dprintf(1, "int13_harddisk: function %02x, error %02x !\n"
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500153 , regs->ah, status);
154 disk_ret(regs, DISK_RET_EBADTRACK);
155 return;
156 }
157 disk_ret(regs, DISK_RET_SUCCESS);
158}
159
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500160
161/****************************************************************
162 * Hard Drive functions
163 ****************************************************************/
164
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500165// disk controller reset
166static void
167disk_1300(struct bregs *regs, u8 device)
168{
169 ata_reset(device);
170}
171
172// read disk status
173static void
174disk_1301(struct bregs *regs, u8 device)
175{
Kevin O'Connorfad2da82008-03-22 20:37:44 -0400176 u8 v = GET_BDA(disk_last_status);
177 regs->ah = v;
178 set_cf(regs, v);
179 // XXX - clear disk_last_status?
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500180}
181
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500182// read disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500183static void
184disk_1302(struct bregs *regs, u8 device)
185{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500186 basic_access(regs, device, ATA_CMD_READ_SECTORS);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500187}
188
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500189// write disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500190static void
191disk_1303(struct bregs *regs, u8 device)
192{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500193 basic_access(regs, device, ATA_CMD_WRITE_SECTORS);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500194}
195
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500196// verify disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500197static void
198disk_1304(struct bregs *regs, u8 device)
199{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500200 basic_access(regs, device, 0);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500201 // FIXME verify
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500202}
203
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500204// format disk track
205static void
206disk_1305(struct bregs *regs, u8 device)
207{
208 DISK_STUB(regs);
209}
210
211// read disk drive parameters
212static void
213disk_1308(struct bregs *regs, u8 device)
214{
215 // Get logical geometry from table
216 u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
217 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
218 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
219 u16 count = GET_EBDA(ata.hdcount);
220
221 nlc = nlc - 2; /* 0 based , last sector not used */
222 regs->al = 0;
223 regs->ch = nlc & 0xff;
224 regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
225 regs->dh = nlh - 1;
226 regs->dl = count; /* FIXME returns 0, 1, or n hard drives */
227
228 // FIXME should set ES & DI
229 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500230}
231
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500232// initialize drive parameters
233static void
234disk_1309(struct bregs *regs, u8 device)
235{
236 DISK_STUB(regs);
237}
238
239// seek to specified cylinder
240static void
241disk_130c(struct bregs *regs, u8 device)
242{
243 DISK_STUB(regs);
244}
245
246// alternate disk reset
247static void
248disk_130d(struct bregs *regs, u8 device)
249{
250 DISK_STUB(regs);
251}
252
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500253// check drive ready
254static void
255disk_1310(struct bregs *regs, u8 device)
256{
257 // should look at 40:8E also???
258
259 // Read the status from controller
260 u8 status = inb(GET_EBDA(ata.channels[device/2].iobase1) + ATA_CB_STAT);
261 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY )
262 disk_ret(regs, DISK_RET_SUCCESS);
263 else
264 disk_ret(regs, DISK_RET_ENOTREADY);
265}
266
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500267// recalibrate
268static void
269disk_1311(struct bregs *regs, u8 device)
270{
271 DISK_STUB(regs);
272}
273
274// controller internal diagnostic
275static void
276disk_1314(struct bregs *regs, u8 device)
277{
278 DISK_STUB(regs);
279}
280
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500281// read disk drive size
282static void
283disk_1315(struct bregs *regs, u8 device)
284{
285 // Get logical geometry from table
286 u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
287 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
288 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
289
290 // Compute sector count seen by int13
291 u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
292 regs->cx = lba >> 16;
293 regs->dx = lba & 0xffff;
294
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500295 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500296 regs->ah = 3; // hard disk accessible
297}
298
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500299// IBM/MS installation check
300static void
301disk_1341(struct bregs *regs, u8 device)
302{
303 regs->bx = 0xaa55; // install check
304 regs->cx = 0x0007; // ext disk access and edd, removable supported
305 disk_ret(regs, DISK_RET_SUCCESS);
306 regs->ah = 0x30; // EDD 3.0
307}
308
309// IBM/MS extended read
310static void
311disk_1342(struct bregs *regs, u8 device)
312{
313 extended_access(regs, device, ATA_CMD_READ_SECTORS);
314}
315
316// IBM/MS extended write
317static void
318disk_1343(struct bregs *regs, u8 device)
319{
320 extended_access(regs, device, ATA_CMD_WRITE_SECTORS);
321}
322
323// IBM/MS verify
324static void
325disk_1344(struct bregs *regs, u8 device)
326{
327 extended_access(regs, device, 0);
328}
329
330// IBM/MS lock/unlock drive
331static void
332disk_1345(struct bregs *regs, u8 device)
333{
334 // Always success for HD
335 disk_ret(regs, DISK_RET_SUCCESS);
336}
337
338// IBM/MS eject media
339static void
340disk_1346(struct bregs *regs, u8 device)
341{
342 // Volume Not Removable
343 disk_ret(regs, DISK_RET_ENOTREMOVABLE);
344}
345
346// IBM/MS extended seek
347static void
348disk_1347(struct bregs *regs, u8 device)
349{
350 extended_access(regs, device, 0);
351}
352
353// IBM/MS get drive parameters
354static void
355disk_1348(struct bregs *regs, u8 device)
356{
357 u16 size = GET_INT13DPT(regs, size);
358
359 // Buffer is too small
360 if (size < 0x1a) {
361 disk_ret(regs, DISK_RET_EPARAM);
362 return;
363 }
364
365 // EDD 1.x
366
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500367 u8 type = GET_EBDA(ata.devices[device].type);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500368 u16 npc = GET_EBDA(ata.devices[device].pchs.cylinders);
369 u16 nph = GET_EBDA(ata.devices[device].pchs.heads);
370 u16 npspt = GET_EBDA(ata.devices[device].pchs.spt);
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400371 u64 lba = GET_EBDA(ata.devices[device].sectors);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500372 u16 blksize = GET_EBDA(ata.devices[device].blksize);
373
374 SET_INT13DPT(regs, size, 0x1a);
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500375 if (type == ATA_TYPE_ATA) {
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400376 if (lba > (u64)npspt*nph*0x3fff) {
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500377 SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
378 SET_INT13DPT(regs, cylinders, 0x3fff);
379 } else {
380 SET_INT13DPT(regs, infos, 0x02); // geometry is valid
381 SET_INT13DPT(regs, cylinders, (u32)npc);
382 }
383 SET_INT13DPT(regs, heads, (u32)nph);
384 SET_INT13DPT(regs, spt, (u32)npspt);
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400385 SET_INT13DPT(regs, sector_count, lba);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500386 } else {
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500387 // ATAPI
388 // 0x74 = removable, media change, lockable, max values
389 SET_INT13DPT(regs, infos, 0x74);
390 SET_INT13DPT(regs, cylinders, 0xffffffff);
391 SET_INT13DPT(regs, heads, 0xffffffff);
392 SET_INT13DPT(regs, spt, 0xffffffff);
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400393 SET_INT13DPT(regs, sector_count, (u64)-1);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500394 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500395 SET_INT13DPT(regs, blksize, blksize);
396
397 if (size < 0x1e) {
398 disk_ret(regs, DISK_RET_SUCCESS);
399 return;
400 }
401
402 // EDD 2.x
403
404 SET_INT13DPT(regs, size, 0x1e);
405
Kevin O'Connor438f6352008-03-30 21:46:53 -0400406 SET_INT13DPT(regs, dpte_segment, SEG_EBDA);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500407 SET_INT13DPT(regs, dpte_offset
408 , offsetof(struct extended_bios_data_area_s, ata.dpte));
409
410 // Fill in dpte
411 u8 channel = device / 2;
412 u16 iobase1 = GET_EBDA(ata.channels[channel].iobase1);
413 u16 iobase2 = GET_EBDA(ata.channels[channel].iobase2);
414 u8 irq = GET_EBDA(ata.channels[channel].irq);
415 u8 mode = GET_EBDA(ata.devices[device].mode);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500416
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500417 u16 options;
418 if (type == ATA_TYPE_ATA) {
419 u8 translation = GET_EBDA(ata.devices[device].translation);
420 options = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
421 options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
422 options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
423 } else {
424 // ATAPI
425 options = (1<<5); // removable device
426 options |= (1<<6); // atapi device
427 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500428 options |= (1<<4); // lba translation
429 options |= (mode==ATA_MODE_PIO32?1:0)<<7;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500430
431 SET_EBDA(ata.dpte.iobase1, iobase1);
432 SET_EBDA(ata.dpte.iobase2, iobase2 + ATA_CB_DC);
433 SET_EBDA(ata.dpte.prefix, (0xe | (device % 2))<<4 );
434 SET_EBDA(ata.dpte.unused, 0xcb );
435 SET_EBDA(ata.dpte.irq, irq );
436 SET_EBDA(ata.dpte.blkcount, 1 );
437 SET_EBDA(ata.dpte.dma, 0 );
438 SET_EBDA(ata.dpte.pio, 0 );
439 SET_EBDA(ata.dpte.options, options);
440 SET_EBDA(ata.dpte.reserved, 0);
441 if (size >= 0x42)
442 SET_EBDA(ata.dpte.revision, 0x11);
443 else
444 SET_EBDA(ata.dpte.revision, 0x10);
445
Kevin O'Connor438f6352008-03-30 21:46:53 -0400446 u8 *p = MAKE_FARPTR(SEG_EBDA
Kevin O'Connor2e7ab8b2008-03-29 14:29:35 -0400447 , offsetof(struct extended_bios_data_area_s, ata.dpte));
448 u8 sum = checksum(p, 15);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500449 SET_EBDA(ata.dpte.checksum, ~sum);
450
451 if (size < 0x42) {
452 disk_ret(regs, DISK_RET_SUCCESS);
453 return;
454 }
455
456 // EDD 3.x
457 channel = device / 2;
458 u8 iface = GET_EBDA(ata.channels[channel].iface);
459 iobase1 = GET_EBDA(ata.channels[channel].iobase1);
460
461 SET_INT13DPT(regs, size, 0x42);
462 SET_INT13DPT(regs, key, 0xbedd);
463 SET_INT13DPT(regs, dpi_length, 0x24);
464 SET_INT13DPT(regs, reserved1, 0);
465 SET_INT13DPT(regs, reserved2, 0);
466
467 if (iface==ATA_IFACE_ISA) {
468 SET_INT13DPT(regs, host_bus[0], 'I');
469 SET_INT13DPT(regs, host_bus[1], 'S');
470 SET_INT13DPT(regs, host_bus[2], 'A');
471 SET_INT13DPT(regs, host_bus[3], 0);
472 } else {
473 // FIXME PCI
474 }
475 SET_INT13DPT(regs, iface_type[0], 'A');
476 SET_INT13DPT(regs, iface_type[1], 'T');
477 SET_INT13DPT(regs, iface_type[2], 'A');
478 SET_INT13DPT(regs, iface_type[3], 0);
479
480 if (iface==ATA_IFACE_ISA) {
481 SET_INT13DPT(regs, iface_path[0], iobase1);
482 SET_INT13DPT(regs, iface_path[2], 0);
483 SET_INT13DPT(regs, iface_path[4], 0L);
484 } else {
485 // FIXME PCI
486 }
487 SET_INT13DPT(regs, device_path[0], device%2);
488 SET_INT13DPT(regs, device_path[1], 0);
489 SET_INT13DPT(regs, device_path[2], 0);
490 SET_INT13DPT(regs, device_path[4], 0L);
491
Kevin O'Connor2e7ab8b2008-03-29 14:29:35 -0400492 sum = checksum(MAKE_FARPTR(regs->ds, 30), 34);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500493 SET_INT13DPT(regs, checksum, ~sum);
494}
495
496// IBM/MS extended media change
497static void
498disk_1349(struct bregs *regs, u8 device)
499{
500 // Always success for HD
501 disk_ret(regs, DISK_RET_SUCCESS);
502}
503
504static void
505disk_134e01(struct bregs *regs, u8 device)
506{
507 disk_ret(regs, DISK_RET_SUCCESS);
508}
509
510static void
511disk_134e03(struct bregs *regs, u8 device)
512{
513 disk_ret(regs, DISK_RET_SUCCESS);
514}
515
516static void
517disk_134e04(struct bregs *regs, u8 device)
518{
519 disk_ret(regs, DISK_RET_SUCCESS);
520}
521
522static void
523disk_134e06(struct bregs *regs, u8 device)
524{
525 disk_ret(regs, DISK_RET_SUCCESS);
526}
527
528static void
529disk_134eXX(struct bregs *regs, u8 device)
530{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500531 disk_ret(regs, DISK_RET_EPARAM);
532}
533
534// IBM/MS set hardware configuration
535static void
536disk_134e(struct bregs *regs, u8 device)
537{
538 switch (regs->al) {
539 case 0x01: disk_134e01(regs, device); break;
540 case 0x03: disk_134e03(regs, device); break;
541 case 0x04: disk_134e04(regs, device); break;
542 case 0x06: disk_134e06(regs, device); break;
543 default: disk_134eXX(regs, device); break;
544 }
545}
546
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500547void
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500548disk_13XX(struct bregs *regs, u8 device)
549{
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500550 disk_ret(regs, DISK_RET_EPARAM);
551}
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500552
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500553void
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500554disk_13(struct bregs *regs, u8 device)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500555{
Kevin O'Connor15aee2e2008-03-01 13:34:04 -0500556 //debug_stub(regs);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500557
558 // clear completion flag
559 SET_BDA(disk_interrupt_flag, 0);
560
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500561 switch (regs->ah) {
562 case 0x00: disk_1300(regs, device); break;
563 case 0x01: disk_1301(regs, device); break;
564 case 0x02: disk_1302(regs, device); break;
565 case 0x03: disk_1303(regs, device); break;
566 case 0x04: disk_1304(regs, device); break;
567 case 0x05: disk_1305(regs, device); break;
568 case 0x08: disk_1308(regs, device); break;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500569 case 0x09: disk_1309(regs, device); break;
570 case 0x0c: disk_130c(regs, device); break;
571 case 0x0d: disk_130d(regs, device); break;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500572 case 0x10: disk_1310(regs, device); break;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500573 case 0x11: disk_1311(regs, device); break;
574 case 0x14: disk_1314(regs, device); break;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500575 case 0x15: disk_1315(regs, device); break;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500576 case 0x41: disk_1341(regs, device); break;
577 case 0x42: disk_1342(regs, device); break;
578 case 0x43: disk_1343(regs, device); break;
579 case 0x44: disk_1344(regs, device); break;
580 case 0x45: disk_1345(regs, device); break;
581 case 0x46: disk_1346(regs, device); break;
582 case 0x47: disk_1347(regs, device); break;
583 case 0x48: disk_1348(regs, device); break;
584 case 0x49: disk_1349(regs, device); break;
585 case 0x4e: disk_134e(regs, device); break;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500586 default: disk_13XX(regs, device); break;
587 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500588}
589
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500590
591/****************************************************************
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500592 * Entry points
593 ****************************************************************/
594
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500595static u8
Kevin O'Connor180a9592008-03-04 22:50:53 -0500596get_device(struct bregs *regs, u8 iscd, u8 drive)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500597{
598 // basic check : device has to be defined
599 if (drive >= CONFIG_MAX_ATA_DEVICES) {
600 disk_ret(regs, DISK_RET_EPARAM);
601 return CONFIG_MAX_ATA_DEVICES;
602 }
603
604 // Get the ata channel
Kevin O'Connor180a9592008-03-04 22:50:53 -0500605 u8 device = GET_EBDA(ata.idmap[iscd][drive]);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500606
607 // basic check : device has to be valid
608 if (device >= CONFIG_MAX_ATA_DEVICES) {
609 disk_ret(regs, DISK_RET_EPARAM);
610 return CONFIG_MAX_ATA_DEVICES;
611 }
612
613 return device;
614}
615
616static void
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500617handle_legacy_disk(struct bregs *regs, u8 drive)
618{
619 if (drive < 0x80) {
620 floppy_13(regs, drive);
621 return;
622 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500623
624 if (! CONFIG_ATA) {
625 // XXX - old code had other disk access method.
626 disk_ret(regs, DISK_RET_EPARAM);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500627 return;
628 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500629
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500630 if (drive >= 0xe0) {
Kevin O'Connor180a9592008-03-04 22:50:53 -0500631 u8 device = get_device(regs, 1, drive - 0xe0);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500632 if (device >= CONFIG_MAX_ATA_DEVICES)
633 return;
634 cdrom_13(regs, device);
635 return;
636 }
637
Kevin O'Connor180a9592008-03-04 22:50:53 -0500638 u8 device = get_device(regs, 0, drive - 0x80);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500639 if (device >= CONFIG_MAX_ATA_DEVICES)
640 return;
641 disk_13(regs, device);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500642}
643
Kevin O'Connor19786762008-03-05 21:09:59 -0500644void VISIBLE16
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500645handle_40(struct bregs *regs)
646{
647 debug_enter(regs);
648 handle_legacy_disk(regs, regs->dl);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500649}
650
651// INT 13h Fixed Disk Services Entry Point
Kevin O'Connor19786762008-03-05 21:09:59 -0500652void VISIBLE16
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500653handle_13(struct bregs *regs)
654{
Kevin O'Connor127cbd72008-03-08 11:34:28 -0500655 //debug_enter(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500656 u8 drive = regs->dl;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500657
Kevin O'Connordfa16502008-03-22 20:13:08 -0400658 if (CONFIG_CDROM_EMU) {
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500659 if (regs->ah == 0x4b) {
660 cdemu_134b(regs);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400661 return;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500662 }
663 if (GET_EBDA(cdemu.active)) {
664 if (drive == GET_EBDA(cdemu.emulated_drive)) {
665 cdemu_13(regs);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400666 return;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500667 }
Kevin O'Connor180a9592008-03-04 22:50:53 -0500668 if (drive < 0xe0)
669 drive--;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500670 }
671 }
672 handle_legacy_disk(regs, drive);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500673}
674
675// record completion in BIOS task complete flag
Kevin O'Connor19786762008-03-05 21:09:59 -0500676void VISIBLE16
Kevin O'Connored128492008-03-11 11:14:59 -0400677handle_76()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500678{
Kevin O'Connored128492008-03-11 11:14:59 -0400679 debug_isr();
680 SET_BDA(disk_interrupt_flag, 0xff);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500681 eoi_both_pics();
682}