blob: 2cb3f0f96d87036a169a829db3f03fe2a1ec2893 [file] [log] [blame]
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -05001// 16bit code to access cdrom 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'Connor31d8c8a2008-03-04 19:56:41 -05007
8#include "disk.h" // cdrom_13
9#include "util.h" // memset
Kevin O'Connor9521e262008-07-04 13:04:29 -040010#include "bregs.h" // struct bregs
11#include "biosvar.h" // GET_EBDA
Kevin O'Connor4524bf72008-12-31 00:31:03 -050012#include "atabits.h" // ATA_TYPE_ATAPI
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050013
14
15/****************************************************************
16 * CDROM functions
17 ****************************************************************/
18
19// read disk drive size
20static void
21cdrom_1315(struct bregs *regs, u8 device)
22{
23 disk_ret(regs, DISK_RET_EADDRNOTFOUND);
24}
25
26// lock
27static void
28cdrom_134500(struct bregs *regs, u8 device)
29{
Kevin O'Connor08815372008-12-29 21:16:31 -050030 u16 ebda_seg = get_ebda_seg();
31 u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[device]);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050032 if (locks == 0xff) {
33 regs->al = 1;
34 disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
35 return;
36 }
Kevin O'Connor08815372008-12-29 21:16:31 -050037 SET_EBDA2(ebda_seg, cdrom_locks[device], locks + 1);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050038 regs->al = 1;
39 disk_ret(regs, DISK_RET_SUCCESS);
40}
41
42// unlock
43static void
44cdrom_134501(struct bregs *regs, u8 device)
45{
Kevin O'Connor08815372008-12-29 21:16:31 -050046 u16 ebda_seg = get_ebda_seg();
47 u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[device]);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050048 if (locks == 0x00) {
49 regs->al = 0;
50 disk_ret(regs, DISK_RET_ENOTLOCKED);
51 return;
52 }
53 locks--;
Kevin O'Connor08815372008-12-29 21:16:31 -050054 SET_EBDA2(ebda_seg, cdrom_locks[device], locks);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050055 regs->al = (locks ? 1 : 0);
56 disk_ret(regs, DISK_RET_SUCCESS);
57}
58
59// status
60static void
61cdrom_134502(struct bregs *regs, u8 device)
62{
Kevin O'Connor609da232008-12-28 23:18:57 -050063 u8 locks = GET_EBDA(cdrom_locks[device]);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050064 regs->al = (locks ? 1 : 0);
65 disk_ret(regs, DISK_RET_SUCCESS);
66}
67
68static void
69cdrom_1345XX(struct bregs *regs, u8 device)
70{
71 disk_ret(regs, DISK_RET_EPARAM);
72}
73
74// IBM/MS lock/unlock drive
75static void
76cdrom_1345(struct bregs *regs, u8 device)
77{
78 switch (regs->al) {
79 case 0x00: cdrom_134500(regs, device); break;
80 case 0x01: cdrom_134501(regs, device); break;
81 case 0x02: cdrom_134502(regs, device); break;
82 default: cdrom_1345XX(regs, device); break;
83 }
84}
85
86// IBM/MS eject media
87static void
88cdrom_1346(struct bregs *regs, u8 device)
89{
Kevin O'Connor609da232008-12-28 23:18:57 -050090 u8 locks = GET_EBDA(cdrom_locks[device]);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050091 if (locks != 0) {
92 disk_ret(regs, DISK_RET_ELOCKED);
93 return;
94 }
95
96 // FIXME should handle 0x31 no media in device
97 // FIXME should handle 0xb5 valid request failed
98
99 // Call removable media eject
100 struct bregs br;
101 memset(&br, 0, sizeof(br));
102 br.ah = 0x52;
103 call16_int(0x15, &br);
104
105 if (br.ah || br.flags & F_CF) {
106 disk_ret(regs, DISK_RET_ELOCKED);
107 return;
108 }
109 disk_ret(regs, DISK_RET_SUCCESS);
110}
111
112// IBM/MS extended media change
113static void
114cdrom_1349(struct bregs *regs, u8 device)
115{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400116 set_fail(regs);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500117 // always send changed ??
118 regs->ah = DISK_RET_ECHANGED;
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500119}
120
121static void
122cdrom_ok(struct bregs *regs, u8 device)
123{
124 disk_ret(regs, DISK_RET_SUCCESS);
125}
126
127static void
128cdrom_wp(struct bregs *regs, u8 device)
129{
130 disk_ret(regs, DISK_RET_EWRITEPROTECT);
131}
132
133void
134cdrom_13(struct bregs *regs, u8 device)
135{
136 //debug_stub(regs);
137
138 switch (regs->ah) {
139 case 0x15: cdrom_1315(regs, device); break;
140 case 0x45: cdrom_1345(regs, device); break;
141 case 0x46: cdrom_1346(regs, device); break;
142 case 0x49: cdrom_1349(regs, device); break;
143
144 // These functions are the same as for hard disks
145 case 0x01:
146 case 0x41:
147 case 0x42:
148 case 0x44:
149 case 0x47:
150 case 0x48:
151 case 0x4e:
152 disk_13(regs, device);
153 break;
154
155 // all these functions return SUCCESS
156 case 0x00: // disk controller reset
157 case 0x09: // initialize drive parameters
158 case 0x0c: // seek to specified cylinder
159 case 0x0d: // alternate disk reset
160 case 0x10: // check drive ready
161 case 0x11: // recalibrate
162 case 0x14: // controller internal diagnostic
163 case 0x16: // detect disk change
164 cdrom_ok(regs, device);
165 break;
166
167 // all these functions return disk write-protected
168 case 0x03: // write disk sectors
169 case 0x05: // format disk track
170 case 0x43: // IBM/MS extended write
171 cdrom_wp(regs, device);
172 break;
173
174 default: disk_13XX(regs, device); break;
175 }
176}
177
178
179/****************************************************************
180 * CD emulation
181 ****************************************************************/
182
Kevin O'Connor1625a752009-08-09 13:08:21 -0400183static void
184cdemu_1302(struct bregs *regs, u8 device)
185{
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400186 cdemu_access(regs, device, CMD_READ);
Kevin O'Connor1625a752009-08-09 13:08:21 -0400187}
188
189static void
190cdemu_1304(struct bregs *regs, u8 device)
191{
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400192 cdemu_access(regs, device, CMD_VERIFY);
Kevin O'Connor1625a752009-08-09 13:08:21 -0400193}
194
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500195// read disk drive parameters
196static void
197cdemu_1308(struct bregs *regs, u8 device)
198{
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500199 u16 ebda_seg = get_ebda_seg();
Kevin O'Connorb68ac712009-08-09 17:25:19 -0400200 u16 nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders) - 1;
201 u16 nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads) - 1;
202 u16 nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500203
204 regs->al = 0x00;
205 regs->bl = 0x00;
206 regs->ch = nlc & 0xff;
Kevin O'Connor4c0c85a2009-04-11 23:31:29 -0400207 regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500208 regs->dh = nlh;
209 // FIXME ElTorito Various. should send the real count of drives 1 or 2
210 // FIXME ElTorito Harddisk. should send the HD count
211 regs->dl = 0x02;
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500212 u8 media = GET_EBDA2(ebda_seg, cdemu.media);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500213 if (media <= 3)
214 regs->bl = media * 2;
215
216 regs->es = SEG_BIOS;
Kevin O'Connor117fc212008-04-13 18:17:02 -0400217 regs->di = (u32)&diskette_param_table2;
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500218
219 disk_ret(regs, DISK_RET_SUCCESS);
220}
221
222void
223cdemu_13(struct bregs *regs)
224{
225 //debug_stub(regs);
226
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500227 u16 ebda_seg = get_ebda_seg();
228 u8 device = GET_EBDA2(ebda_seg, cdemu.controller_index) * 2;
229 device += GET_EBDA2(ebda_seg, cdemu.device_spec);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500230
231 switch (regs->ah) {
Kevin O'Connor1625a752009-08-09 13:08:21 -0400232 case 0x02: cdemu_1302(regs, device); break;
233 case 0x04: cdemu_1304(regs, device); break;
234 case 0x08: cdemu_1308(regs, device); break;
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400235
Kevin O'Connoraa7ddd72008-03-22 23:58:26 -0400236 // These functions are the same as standard CDROM.
237 case 0x00:
238 case 0x01:
239 case 0x03:
240 case 0x05:
241 case 0x09:
242 case 0x0c:
243 case 0x0d:
244 case 0x10:
245 case 0x11:
246 case 0x14:
247 case 0x15:
248 case 0x16:
249 cdrom_13(regs, device);
250 break;
251
Kevin O'Connoraa7ddd72008-03-22 23:58:26 -0400252 default: disk_13XX(regs, device); break;
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500253 }
254}
255
256struct eltorito_s {
257 u8 size;
258 u8 media;
259 u8 emulated_drive;
260 u8 controller_index;
261 u32 ilba;
262 u16 device_spec;
263 u16 buffer_segment;
264 u16 load_segment;
265 u16 sector_count;
266 u8 cylinders;
267 u8 sectors;
268 u8 heads;
269};
270
271#define SET_INT13ET(regs,var,val) \
272 SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
273
274// ElTorito - Terminate disk emu
275void
276cdemu_134b(struct bregs *regs)
277{
278 // FIXME ElTorito Hardcoded
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500279 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500280 SET_INT13ET(regs, size, 0x13);
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500281 SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media));
282 SET_INT13ET(regs, emulated_drive, GET_EBDA2(ebda_seg, cdemu.emulated_drive));
283 SET_INT13ET(regs, controller_index
284 , GET_EBDA2(ebda_seg, cdemu.controller_index));
285 SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba));
286 SET_INT13ET(regs, device_spec, GET_EBDA2(ebda_seg, cdemu.device_spec));
287 SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
288 SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
289 SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
Kevin O'Connorb68ac712009-08-09 17:25:19 -0400290 SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders));
291 SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt));
292 SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads));
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500293
294 // If we have to terminate emulation
295 if (regs->al == 0x00) {
296 // FIXME ElTorito Various. Should be handled accordingly to spec
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500297 SET_EBDA2(ebda_seg, cdemu.active, 0x00); // bye bye
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500298 }
299
300 disk_ret(regs, DISK_RET_SUCCESS);
301}
Kevin O'Connor180a9592008-03-04 22:50:53 -0500302
303
304/****************************************************************
305 * CD booting
306 ****************************************************************/
307
308// Request SENSE
Kevin O'Connora05223c2008-06-28 12:15:57 -0400309static int
Kevin O'Connora0c68792009-02-12 20:47:59 -0500310atapi_get_sense(int device, u8 *asc, u8 *ascq)
Kevin O'Connor180a9592008-03-04 22:50:53 -0500311{
Kevin O'Connora0c68792009-02-12 20:47:59 -0500312 u8 atacmd[12], buffer[18];
Kevin O'Connor180a9592008-03-04 22:50:53 -0500313 memset(atacmd, 0, sizeof(atacmd));
314 atacmd[0] = ATA_CMD_REQUEST_SENSE;
315 atacmd[4] = sizeof(buffer);
Kevin O'Connora05223c2008-06-28 12:15:57 -0400316 int ret = ata_cmd_packet(device, atacmd, sizeof(atacmd), sizeof(buffer)
Kevin O'Connor35ae7262009-01-19 15:44:44 -0500317 , MAKE_FLATPTR(GET_SEG(SS), buffer));
Kevin O'Connora0c68792009-02-12 20:47:59 -0500318 if (ret)
Kevin O'Connora05223c2008-06-28 12:15:57 -0400319 return ret;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500320
321 *asc = buffer[12];
322 *ascq = buffer[13];
323
324 return 0;
325}
326
Kevin O'Connora0c68792009-02-12 20:47:59 -0500327// Request capacity
328static int
329atapi_read_capacity(int device, u32 *blksize, u32 *sectors)
330{
331 u8 packet[12], buf[8];
332 memset(packet, 0, sizeof(packet));
333 packet[0] = 0x25; /* READ CAPACITY */
334 int ret = ata_cmd_packet(device, packet, sizeof(packet), sizeof(buf)
335 , MAKE_FLATPTR(GET_SEG(SS), buf));
336 if (ret)
337 return ret;
338
339 *blksize = (((u32)buf[4] << 24) | ((u32)buf[5] << 16)
340 | ((u32)buf[6] << 8) | ((u32)buf[7] << 0));
341 *sectors = (((u32)buf[0] << 24) | ((u32)buf[1] << 16)
342 | ((u32)buf[2] << 8) | ((u32)buf[3] << 0));
343
344 return 0;
345}
346
Kevin O'Connora05223c2008-06-28 12:15:57 -0400347static int
Kevin O'Connor180a9592008-03-04 22:50:53 -0500348atapi_is_ready(u16 device)
349{
Kevin O'Connora0c68792009-02-12 20:47:59 -0500350 dprintf(6, "atapi_is_ready (device=%d)\n", device);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500351
Kevin O'Connora0c68792009-02-12 20:47:59 -0500352 /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is
353 * reported by the device. If the device reports "IN PROGRESS",
Kevin O'Connor180a9592008-03-04 22:50:53 -0500354 * 30 seconds is added. */
Kevin O'Connora0c68792009-02-12 20:47:59 -0500355 u32 blksize, sectors;
356 int in_progress = 0;
357 u64 end = calc_future_tsc(5000);
358 for (;;) {
359 if (rdtscll() > end) {
Kevin O'Connora05223c2008-06-28 12:15:57 -0400360 dprintf(1, "read capacity failed\n");
Kevin O'Connor180a9592008-03-04 22:50:53 -0500361 return -1;
362 }
Kevin O'Connora0c68792009-02-12 20:47:59 -0500363
364 int ret = atapi_read_capacity(device, &blksize, &sectors);
365 if (!ret)
366 // Success
Kevin O'Connor180a9592008-03-04 22:50:53 -0500367 break;
368
Kevin O'Connora0c68792009-02-12 20:47:59 -0500369 u8 asc, ascq;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500370 ret = atapi_get_sense(device, &asc, &ascq);
Kevin O'Connora0c68792009-02-12 20:47:59 -0500371 if (ret)
372 // Error - retry.
Kevin O'Connor180a9592008-03-04 22:50:53 -0500373 continue;
374
Kevin O'Connora0c68792009-02-12 20:47:59 -0500375 // Sense succeeded.
Kevin O'Connor180a9592008-03-04 22:50:53 -0500376 if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
Kevin O'Connora05223c2008-06-28 12:15:57 -0400377 dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
Kevin O'Connor180a9592008-03-04 22:50:53 -0500378 return -1;
379 }
380
381 if (asc == 0x04 && ascq == 0x01 && !in_progress) {
382 /* IN PROGRESS OF BECOMING READY */
383 printf("Waiting for device to detect medium... ");
384 /* Allow 30 seconds more */
Kevin O'Connora0c68792009-02-12 20:47:59 -0500385 end = calc_future_tsc(30000);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500386 in_progress = 1;
387 }
388 }
389
Kevin O'Connora0c68792009-02-12 20:47:59 -0500390 if (blksize != GET_GLOBAL(ATA.devices[device].blksize)) {
391 printf("Unsupported sector size %u\n", blksize);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500392 return -1;
393 }
Kevin O'Connor180a9592008-03-04 22:50:53 -0500394
Kevin O'Connora05223c2008-06-28 12:15:57 -0400395 dprintf(6, "sectors=%u\n", sectors);
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500396 printf("%dMB medium detected\n", sectors>>(20-11));
Kevin O'Connor180a9592008-03-04 22:50:53 -0500397 return 0;
398}
399
Kevin O'Connora05223c2008-06-28 12:15:57 -0400400int
Kevin O'Connor7da1dcd2009-02-16 10:51:24 -0500401cdrom_boot(int cdid)
Kevin O'Connor180a9592008-03-04 22:50:53 -0500402{
Kevin O'Connor7da1dcd2009-02-16 10:51:24 -0500403 // Verify device is a cdrom.
404 if (cdid >= ATA.cdcount)
405 return 1;
406 int driveid = GET_GLOBAL(ATA.idmap[1][cdid]);
407 if (GET_GLOBAL(ATA.devices[driveid].device) != ATA_DEVICE_CDROM)
Kevin O'Connor37ef9ae2008-11-09 17:35:05 -0500408 return 2;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500409
Kevin O'Connor7da1dcd2009-02-16 10:51:24 -0500410 int ret = atapi_is_ready(driveid);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500411 if (ret)
Kevin O'Connor65e63422008-07-19 14:12:32 -0400412 dprintf(1, "atapi_is_ready returned %d\n", ret);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500413
414 // Read the Boot Record Volume Descriptor
415 u8 buffer[2048];
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500416 struct disk_op_s dop;
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400417 memset(&dop, 0, sizeof(dop));
Kevin O'Connor7da1dcd2009-02-16 10:51:24 -0500418 dop.driveid = driveid;
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500419 dop.lba = 0x11;
420 dop.count = 1;
Kevin O'Connor35ae7262009-01-19 15:44:44 -0500421 dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500422 ret = cdrom_read(&dop);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500423 if (ret)
424 return 3;
425
426 // Validity checks
427 if (buffer[0])
428 return 4;
Kevin O'Connor38d1a342009-04-18 16:59:47 -0400429 if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
Kevin O'Connor180a9592008-03-04 22:50:53 -0500430 return 5;
431
432 // ok, now we calculate the Boot catalog address
433 u32 lba = *(u32*)&buffer[0x47];
434
435 // And we read the Boot Catalog
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500436 dop.lba = lba;
437 ret = cdrom_read(&dop);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500438 if (ret)
439 return 7;
440
441 // Validation entry
442 if (buffer[0x00] != 0x01)
443 return 8; // Header
444 if (buffer[0x01] != 0x00)
445 return 9; // Platform
446 if (buffer[0x1E] != 0x55)
447 return 10; // key 1
448 if (buffer[0x1F] != 0xAA)
449 return 10; // key 2
450
451 // Initial/Default Entry
452 if (buffer[0x20] != 0x88)
453 return 11; // Bootable
454
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500455 u16 ebda_seg = get_ebda_seg();
Kevin O'Connordfa16502008-03-22 20:13:08 -0400456 u8 media = buffer[0x21];
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500457 SET_EBDA2(ebda_seg, cdemu.media, media);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500458
Kevin O'Connor7da1dcd2009-02-16 10:51:24 -0500459 SET_EBDA2(ebda_seg, cdemu.controller_index, driveid/2);
460 SET_EBDA2(ebda_seg, cdemu.device_spec, driveid%2);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500461
462 u16 boot_segment = *(u16*)&buffer[0x22];
463 if (!boot_segment)
464 boot_segment = 0x07C0;
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500465 SET_EBDA2(ebda_seg, cdemu.load_segment, boot_segment);
466 SET_EBDA2(ebda_seg, cdemu.buffer_segment, 0x0000);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500467
468 u16 nbsectors = *(u16*)&buffer[0x26];
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500469 SET_EBDA2(ebda_seg, cdemu.sector_count, nbsectors);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500470
471 lba = *(u32*)&buffer[0x28];
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500472 SET_EBDA2(ebda_seg, cdemu.ilba, lba);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500473
474 // And we read the image in memory
Kevin O'Connora4d70aa2009-08-09 11:32:00 -0400475 dop.lba = lba;
476 dop.count = DIV_ROUND_UP(nbsectors, 4);
Kevin O'Connor35ae7262009-01-19 15:44:44 -0500477 dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
Kevin O'Connora4d70aa2009-08-09 11:32:00 -0400478 ret = cdrom_read(&dop);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500479 if (ret)
480 return 12;
481
Kevin O'Connordfa16502008-03-22 20:13:08 -0400482 if (media == 0) {
483 // No emulation requested - return success.
Kevin O'Connor7da1dcd2009-02-16 10:51:24 -0500484 SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0xE0 + cdid);
Kevin O'Connordfa16502008-03-22 20:13:08 -0400485 return 0;
486 }
487
488 // Emulation of a floppy/harddisk requested
489 if (! CONFIG_CDROM_EMU)
490 return 13;
491
492 // Set emulated drive id and increase bios installed hardware
493 // number of devices
494 if (media < 4) {
495 // Floppy emulation
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500496 SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0x00);
Kevin O'Connordfa16502008-03-22 20:13:08 -0400497 SETBITS_BDA(equipment_list_flags, 0x41);
Kevin O'Connor95827c42009-02-07 00:04:57 -0500498
499 switch (media) {
500 case 0x01: // 1.2M floppy
Kevin O'Connorb68ac712009-08-09 17:25:19 -0400501 SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15);
502 SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
503 SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
Kevin O'Connor95827c42009-02-07 00:04:57 -0500504 break;
505 case 0x02: // 1.44M floppy
Kevin O'Connorb68ac712009-08-09 17:25:19 -0400506 SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18);
507 SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
508 SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
Kevin O'Connor95827c42009-02-07 00:04:57 -0500509 break;
510 case 0x03: // 2.88M floppy
Kevin O'Connorb68ac712009-08-09 17:25:19 -0400511 SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36);
512 SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
513 SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
Kevin O'Connor95827c42009-02-07 00:04:57 -0500514 break;
515 }
Kevin O'Connordfa16502008-03-22 20:13:08 -0400516 } else {
517 // Harddrive emulation
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500518 SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0x80);
519 SET_BDA(hdcount, GET_BDA(hdcount) + 1);
Kevin O'Connordfa16502008-03-22 20:13:08 -0400520
Kevin O'Connor95827c42009-02-07 00:04:57 -0500521 // Peak at partition table to get chs.
522 struct mbr_s *mbr = (void*)0;
523 u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl);
524 u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
525 u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
526
Kevin O'Connorb68ac712009-08-09 17:25:19 -0400527 SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f);
528 SET_EBDA2(ebda_seg, cdemu.lchs.cylinders
529 , ((sptcyl<<2)&0x300) + cyllow + 1);
530 SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500531 }
532
Kevin O'Connordfa16502008-03-22 20:13:08 -0400533 // everything is ok, so from now on, the emulation is active
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500534 SET_EBDA2(ebda_seg, cdemu.active, 0x01);
Kevin O'Connora05223c2008-06-28 12:15:57 -0400535 dprintf(6, "cdemu media=%d\n", media);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500536
537 return 0;
538}