aboutsummaryrefslogtreecommitdiffstats
path: root/src/cdrom.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2009-09-12 19:35:04 -0400
committerKevin O'Connor <kevin@koconnor.net>2009-09-12 19:35:04 -0400
commit36c93a5e97931eedab98350d12d8a5ee7d8872bb (patch)
tree6f41287867be60097d4e7efc42ca42b41a7bbfdc /src/cdrom.c
parent51fd0a17153a8c94c97f9a80afd6e238fb542e3b (diff)
downloadseabios-36c93a5e97931eedab98350d12d8a5ee7d8872bb.tar.gz
Unify cd emulation access and main disk access code.
Add a new backend driver for cd emulation (DTYPE_CDEMU). This backend driver now does the work of scheduling mis-sized reads. Add mechanism for obtaining emulated drive geometry. Extend disk_1308() to support cdrom emulation. Use regular disk_13*() calls even for cdemu. Also, unify the X_SECTOR_SIZE definitions.
Diffstat (limited to 'src/cdrom.c')
-rw-r--r--src/cdrom.c164
1 files changed, 96 insertions, 68 deletions
diff --git a/src/cdrom.c b/src/cdrom.c
index 1801d22f..67d7016b 100644
--- a/src/cdrom.c
+++ b/src/cdrom.c
@@ -1,4 +1,4 @@
-// 16bit code to access cdrom drives.
+// Support for booting from cdroms (the "El Torito" spec).
//
// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2002 MandrakeSoft S.A.
@@ -16,85 +16,113 @@
* CD emulation
****************************************************************/
-static void
-cdemu_wp(struct bregs *regs, u8 driveid)
+static int
+cdemu_read(struct disk_op_s *op)
{
- disk_ret(regs, DISK_RET_EWRITEPROTECT);
-}
+ u16 ebda_seg = get_ebda_seg();
+ u8 driveid = GET_EBDA2(ebda_seg, cdemu.emulated_driveid);
+ struct disk_op_s dop;
+ dop.driveid = driveid;
+ dop.command = op->command;
+ dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) + op->lba / 4;
+
+ int count = op->count;
+ op->count = 0;
+ u8 *cdbuf_far = (void*)offsetof(struct extended_bios_data_area_s, cdemu_buf);
+
+ if (op->lba & 3) {
+ // Partial read of first block.
+ dop.count = 1;
+ dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
+ int ret = process_op(&dop);
+ if (ret)
+ return ret;
+ u8 thiscount = 4 - (op->lba & 3);
+ if (thiscount > count)
+ thiscount = count;
+ count -= thiscount;
+ memcpy_far(FLATPTR_TO_SEG(op->buf_fl)
+ , (void*)FLATPTR_TO_OFFSET(op->buf_fl)
+ , ebda_seg, cdbuf_far + (op->lba & 3) * 512
+ , thiscount * 512);
+ op->buf_fl += thiscount * 512;
+ op->count += thiscount;
+ dop.lba++;
+ }
-static void
-cdemu_1302(struct bregs *regs, u8 driveid)
-{
- cdemu_access(regs, driveid, CMD_READ);
-}
+ if (count > 3) {
+ // Read n number of regular blocks.
+ dop.count = count / 4;
+ dop.buf_fl = op->buf_fl;
+ int ret = process_op(&dop);
+ op->count += dop.count * 4;
+ if (ret)
+ return ret;
+ u8 thiscount = count & ~3;
+ count &= 3;
+ op->buf_fl += thiscount * 512;
+ dop.lba += thiscount / 4;
+ }
-static void
-cdemu_1304(struct bregs *regs, u8 driveid)
-{
- cdemu_access(regs, driveid, CMD_VERIFY);
+ if (count) {
+ // Partial read on last block.
+ dop.count = 1;
+ dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
+ int ret = process_op(&dop);
+ if (ret)
+ return ret;
+ u8 thiscount = count;
+ memcpy_far(FLATPTR_TO_SEG(op->buf_fl)
+ , (void*)FLATPTR_TO_OFFSET(op->buf_fl)
+ , ebda_seg, cdbuf_far, thiscount * 512);
+ op->count += thiscount;
+ }
+
+ return DISK_RET_SUCCESS;
}
-// read disk drive parameters
-static void
-cdemu_1308(struct bregs *regs, u8 driveid)
+int
+process_cdemu_op(struct disk_op_s *op)
{
- u16 ebda_seg = get_ebda_seg();
- u16 nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders) - 1;
- u16 nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads) - 1;
- u16 nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
-
- regs->al = 0x00;
- regs->bl = 0x00;
- regs->ch = nlc & 0xff;
- regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
- regs->dh = nlh;
- // FIXME ElTorito Various. should send the real count of drives 1 or 2
- // FIXME ElTorito Harddisk. should send the HD count
- regs->dl = 0x02;
- u8 media = GET_EBDA2(ebda_seg, cdemu.media);
- if (media <= 3)
- regs->bl = media * 2;
-
- regs->es = SEG_BIOS;
- regs->di = (u32)&diskette_param_table2;
+ if (!CONFIG_CDROM_EMU)
+ return 0;
- disk_ret(regs, DISK_RET_SUCCESS);
+ switch (op->command) {
+ case CMD_READ:
+ return cdemu_read(op);
+ case CMD_WRITE:
+ case CMD_FORMAT:
+ return DISK_RET_EWRITEPROTECT;
+ case CMD_VERIFY:
+ case CMD_RESET:
+ case CMD_SEEK:
+ case CMD_ISREADY:
+ return DISK_RET_SUCCESS;
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
}
+int cdemu_driveid VAR16VISIBLE;
+
void
-cdemu_13(struct bregs *regs)
+cdemu_setup()
{
- //debug_stub(regs);
-
- u16 ebda_seg = get_ebda_seg();
- u8 driveid = GET_EBDA2(ebda_seg, cdemu.emulated_driveid);
+ if (!CONFIG_CDROM_EMU)
+ return;
- switch (regs->ah) {
- case 0x02: cdemu_1302(regs, driveid); break;
- case 0x04: cdemu_1304(regs, driveid); break;
- case 0x08: cdemu_1308(regs, driveid); break;
-
- case 0x03:
- case 0x05:
- cdemu_wp(regs, driveid);
- break;
-
- // These functions are the same as standard CDROM.
- case 0x00:
- case 0x01:
- case 0x09:
- case 0x0c:
- case 0x0d:
- case 0x10:
- case 0x11:
- case 0x14:
- case 0x15:
- case 0x16:
- disk_13(regs, driveid);
- break;
-
- default: disk_13XX(regs, driveid); break;
+ int driveid = Drives.drivecount;
+ if (driveid >= ARRAY_SIZE(Drives.drives)) {
+ cdemu_driveid = -1;
+ return;
}
+ Drives.drivecount++;
+ cdemu_driveid = driveid;
+ memset(&Drives.drives[driveid], 0, sizeof(Drives.drives[0]));
+ Drives.drives[driveid].type = DTYPE_CDEMU;
+ Drives.drives[driveid].blksize = DISK_SECTOR_SIZE;
+ Drives.drives[driveid].sectors = (u64)-1;
}
struct eltorito_s {
@@ -329,7 +357,7 @@ cdrom_boot(int cdid)
}
// Emulation of a floppy/harddisk requested
- if (! CONFIG_CDROM_EMU)
+ if (! CONFIG_CDROM_EMU || cdemu_driveid < 0)
return 13;
// Set emulated drive id and increase bios installed hardware