aboutsummaryrefslogtreecommitdiff
path: root/src/disk.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/disk.c
parent51fd0a17153a8c94c97f9a80afd6e238fb542e3b (diff)
downloadseabios-hppa-36c93a5e97931eedab98350d12d8a5ee7d8872bb.zip
seabios-hppa-36c93a5e97931eedab98350d12d8a5ee7d8872bb.tar.gz
seabios-hppa-36c93a5e97931eedab98350d12d8a5ee7d8872bb.tar.bz2
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/disk.c')
-rw-r--r--src/disk.c166
1 files changed, 65 insertions, 101 deletions
diff --git a/src/disk.c b/src/disk.c
index b021c40..4ebccee 100644
--- a/src/disk.c
+++ b/src/disk.c
@@ -43,10 +43,33 @@ __disk_stub(struct bregs *regs, int lineno, const char *fname)
#define DISK_STUB(regs) \
__disk_stub((regs), __LINE__, __func__)
-// Obtain the requested disk lba from an old-style chs request.
-static int
-legacy_lba(struct bregs *regs, u16 lchs_seg, struct chs_s *lchs_far)
+static void
+fillLCHS(u8 driveid, u16 *nlc, u16 *nlh, u16 *nlspt)
{
+ if (CONFIG_CDROM_EMU && driveid == GET_GLOBAL(cdemu_driveid)) {
+ // Emulated drive - get info from ebda. (It's not possible to
+ // populate the geometry directly in the driveid because the
+ // geometry is only known after the bios segment is made
+ // read-only).
+ u16 ebda_seg = get_ebda_seg();
+ *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
+ *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
+ *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
+ return;
+ }
+ *nlc = GET_GLOBAL(Drives.drives[driveid].lchs.cylinders);
+ *nlh = GET_GLOBAL(Drives.drives[driveid].lchs.heads);
+ *nlspt = GET_GLOBAL(Drives.drives[driveid].lchs.spt);
+}
+
+// Perform read/write/verify using old-style chs accesses
+static void
+basic_access(struct bregs *regs, u8 driveid, u16 command)
+{
+ struct disk_op_s dop;
+ dop.driveid = driveid;
+ dop.command = command;
+
u8 count = regs->al;
u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
u16 sector = regs->cl & 0x3f;
@@ -56,12 +79,12 @@ legacy_lba(struct bregs *regs, u16 lchs_seg, struct chs_s *lchs_far)
dprintf(1, "int13_harddisk: function %02x, parameter out of range!\n"
, regs->ah);
disk_ret(regs, DISK_RET_EPARAM);
- return -1;
+ return;
}
+ dop.count = count;
- u16 nlc = GET_FARVAR(lchs_seg, lchs_far->cylinders);
- u16 nlh = GET_FARVAR(lchs_seg, lchs_far->heads);
- u16 nlspt = GET_FARVAR(lchs_seg, lchs_far->spt);
+ u16 nlc, nlh, nlspt;
+ fillLCHS(driveid, &nlc, &nlh, &nlspt);
// sanity check on cyl heads, sec
if (cylinder >= nlc || head >= nlh || sector > nlspt) {
@@ -69,26 +92,13 @@ legacy_lba(struct bregs *regs, u16 lchs_seg, struct chs_s *lchs_far)
" range %04x/%04x/%04x!\n"
, regs->ah, cylinder, head, sector);
disk_ret(regs, DISK_RET_EPARAM);
- return -1;
+ return;
}
// translate lchs to lba
- return (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
- + (u32)sector - 1);
-}
+ dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
+ + (u32)sector - 1);
-// Perform read/write/verify using old-style chs accesses
-static void
-basic_access(struct bregs *regs, u8 driveid, u16 command)
-{
- struct disk_op_s dop;
- dop.driveid = driveid;
- dop.command = command;
- int lba = legacy_lba(regs, get_global_seg(), &Drives.drives[driveid].lchs);
- if (lba < 0)
- return;
- dop.lba = lba;
- dop.count = regs->al;
dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
int status = send_disk_op(&dop);
@@ -98,72 +108,6 @@ basic_access(struct bregs *regs, u8 driveid, u16 command)
disk_ret(regs, status);
}
-// Perform cdemu read/verify
-void
-cdemu_access(struct bregs *regs, u8 driveid, u16 command)
-{
- struct disk_op_s dop;
- dop.driveid = driveid;
- dop.command = command;
- u16 ebda_seg = get_ebda_seg();
- int vlba = legacy_lba(
- regs, ebda_seg
- , (void*)offsetof(struct extended_bios_data_area_s, cdemu.lchs));
- if (vlba < 0)
- return;
- dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) + vlba / 4;
- u8 count = regs->al;
- u8 *cdbuf_far = (void*)offsetof(struct extended_bios_data_area_s, cdemu_buf);
- u8 *dest_far = (void*)(regs->bx+0);
- regs->al = 0;
- int status = DISK_RET_SUCCESS;
-
- if (vlba & 3) {
- dop.count = 1;
- dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
- status = send_disk_op(&dop);
- if (status)
- goto fail;
- u8 thiscount = 4 - (vlba & 3);
- if (thiscount > count)
- thiscount = count;
- count -= thiscount;
- memcpy_far(regs->es, dest_far
- , ebda_seg, cdbuf_far + (vlba & 3) * 512
- , thiscount * 512);
- dest_far += thiscount * 512;
- regs->al += thiscount;
- dop.lba++;
- }
-
- if (count > 3) {
- dop.count = count / 4;
- dop.buf_fl = MAKE_FLATPTR(regs->es, dest_far);
- status = send_disk_op(&dop);
- regs->al += dop.count * 4;
- if (status)
- goto fail;
- u8 thiscount = count & ~3;
- count &= 3;
- dest_far += thiscount * 512;
- dop.lba += thiscount / 4;
- }
-
- if (count) {
- dop.count = 1;
- dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
- status = send_disk_op(&dop);
- if (status)
- goto fail;
- u8 thiscount = count;
- memcpy_far(regs->es, dest_far, ebda_seg, cdbuf_far, thiscount * 512);
- regs->al += thiscount;
- }
-
-fail:
- disk_ret(regs, status);
-}
-
// Perform read/write/verify using new-style "int13ext" accesses.
static void
extended_access(struct bregs *regs, u8 driveid, u16 command)
@@ -249,8 +193,8 @@ disk_1305(struct bregs *regs, u8 driveid)
{
DISK_STUB(regs);
- u16 nlh = GET_GLOBAL(Drives.drives[driveid].lchs.heads);
- u16 nlspt = GET_GLOBAL(Drives.drives[driveid].lchs.spt);
+ u16 nlc, nlh, nlspt;
+ fillLCHS(driveid, &nlc, &nlh, &nlspt);
u8 num_sectors = regs->al;
u8 head = regs->dh;
@@ -274,16 +218,21 @@ disk_1305(struct bregs *regs, u8 driveid)
static void
disk_1308(struct bregs *regs, u8 driveid)
{
+ u16 ebda_seg = get_ebda_seg();
// Get logical geometry from table
- u16 nlc = GET_GLOBAL(Drives.drives[driveid].lchs.cylinders) - 1;
- u16 nlh = GET_GLOBAL(Drives.drives[driveid].lchs.heads) - 1;
- u16 nlspt = GET_GLOBAL(Drives.drives[driveid].lchs.spt);
+ u16 nlc, nlh, nlspt;
+ fillLCHS(driveid, &nlc, &nlh, &nlspt);
+ nlc--;
+ nlh--;
u8 count;
if (regs->dl < EXTSTART_HD) {
// Floppy
count = GET_GLOBAL(Drives.floppycount);
- regs->bx = GET_GLOBAL(Drives.drives[driveid].floppy_type);
+ if (CONFIG_CDROM_EMU && driveid == GET_GLOBAL(cdemu_driveid))
+ regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
+ else
+ regs->bx = GET_GLOBAL(Drives.drives[driveid].floppy_type);
// set es & di to point to 11 byte diskette param table in ROM
regs->es = SEG_BIOS;
@@ -298,6 +247,16 @@ disk_1308(struct bregs *regs, u8 driveid)
return;
}
+ if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) {
+ u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+ if (((emudrive ^ regs->dl) & 0x80) == 0)
+ // Note extra drive due to emulation.
+ count++;
+ if (regs->dl < EXTSTART_HD && count > 2)
+ // Max of two floppy drives.
+ count = 2;
+ }
+
regs->al = 0;
regs->ch = nlc & 0xff;
regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
@@ -368,9 +327,8 @@ disk_1315(struct bregs *regs, u8 driveid)
// Hard drive
// Get logical geometry from table
- u16 nlc = GET_GLOBAL(Drives.drives[driveid].lchs.cylinders);
- u16 nlh = GET_GLOBAL(Drives.drives[driveid].lchs.heads);
- u16 nlspt = GET_GLOBAL(Drives.drives[driveid].lchs.spt);
+ u16 nlc, nlh, nlspt;
+ fillLCHS(driveid, &nlc, &nlh, &nlspt);
// Compute sector count seen by int13
u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
@@ -725,13 +683,13 @@ disk_134e(struct bregs *regs, u8 driveid)
}
}
-void
+static void
disk_13XX(struct bregs *regs, u8 driveid)
{
disk_ret(regs, DISK_RET_EPARAM);
}
-void
+static void
disk_13(struct bregs *regs, u8 driveid)
{
//debug_stub(regs);
@@ -866,7 +824,13 @@ handle_13(struct bregs *regs)
if (GET_EBDA2(ebda_seg, cdemu.active)) {
u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
if (extdrive == emudrive) {
- cdemu_13(regs);
+ int cdemuid = GET_GLOBAL(cdemu_driveid);
+ if (regs->ah > 0x16) {
+ // Only old-style commands supported.
+ disk_13XX(regs, cdemuid);
+ return;
+ }
+ disk_13(regs, cdemuid);
return;
}
if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)