STDMETHODIMP CDisk::lsecid(IGeometry *g, long track, VARIANT *buffer) { DSK_GEOMETRY geom; DSK_FORMAT fmt; unsigned char buf[4]; dsk_err_t err; g_to_dg(g, &geom); err = dsk_lsecid(m_driver, &geom, track, &fmt); buf[0] = fmt.fmt_cylinder; buf[1] = fmt.fmt_head; buf[2] = fmt.fmt_sector; buf[3] = dsk_get_psh(fmt.fmt_secsize); return PutBuffer(buf, buffer, 4, err); }
/* Probe the geometry of a disc. This will always use the boot sector. */ dsk_err_t dsk_defgetgeom(DSK_DRIVER *self, DSK_GEOMETRY *geom) { DSK_FORMAT secid; dsk_err_t e; unsigned char *secbuf; unsigned long dsksize; dsk_rate_t oldrate; if (!self || !geom || !self->dr_class) return DSK_ERR_BADPTR; memset(geom, 0, sizeof(*geom)); /* Switch to a minimal format */ e = dg_stdformat(geom, FMT_180K, NULL, NULL); if (e) return e; /* Allocate buffer for boot sector (512 bytes) */ secbuf = dsk_malloc(geom->dg_secsize); if (!secbuf) return DSK_ERR_NOMEM; /* Check for CPC6128 type discs. Also probe the data rate; if we get a * missing address mark, then the data rate is wrong. */ e = dg_stdformat(geom, FMT_180K, NULL, NULL); if (e) return e; e = dsk_lsecid(self, geom, 0, &secid); /* Check for HD discs */ if (e == DSK_ERR_NOADDR) { geom->dg_datarate = RATE_HD; e = dsk_lsecid(self, geom, 0, &secid); } /* Check for DD 5.25" disc in HD 5.25" drive */ if (e == DSK_ERR_NOADDR) { geom->dg_datarate = RATE_DD; e = dsk_lsecid(self, geom, 0, &secid); } /* Check for BBC micro DFS discs (FM encoded) */ if (e == DSK_ERR_NOADDR) { e = dg_stdformat(geom, FMT_BBC100, NULL, NULL); if (!e) e = dsk_lsecid(self, geom, 0, &secid); } if (!e) /* We could get the sector ID */ { if ((secid.fmt_sector & 0xF0) == 0x10 && secid.fmt_secsize == 512) /* Ampro 40 track double sided */ { dsk_free(secbuf); e = dg_stdformat(geom, FMT_AMPRO400D, NULL, NULL); if (!e) set_fixed_fs(self, FMT_AMPRO400D); return e; } if ((secid.fmt_sector & 0xC0) == 0x40 && secid.fmt_secsize == 512) /* CPC system */ { dsk_free(secbuf); e = dg_stdformat(geom, FMT_CPCSYS, NULL, NULL); if (!e) set_pcw_fs(self, geom, boot_cpcsys); return e; } if ((secid.fmt_sector & 0xC0) == 0xC0 && secid.fmt_secsize == 512) /* CPC data */ { dsk_free(secbuf); e = dg_stdformat(geom, FMT_CPCDATA, NULL, NULL); if (!e) set_pcw_fs(self, geom, boot_cpcdata); return e; } /* [v0.6.0] Handle discs with non-512 byte sectors */ if (secid.fmt_secsize == 256) { if (geom->dg_fm) /* BBC Micro FM floppy */ { unsigned int tot_sectors; e = dsk_lread(self, geom, secbuf, 1); tot_sectors = secbuf[7] + 256 * (secbuf[6] & 3); /* If disc is FM recorded but does not have 400 or 800 sectors, fail. */ if (e == DSK_ERR_OK && tot_sectors != 400 && tot_sectors != 800) e = DSK_ERR_BADFMT; geom->dg_cylinders = tot_sectors / (geom->dg_heads * geom->dg_sectors); dsk_free(secbuf); return e; } else /* MFM */ { e = dg_stdformat(geom, FMT_ACORN160, NULL, NULL); if (!e) e = dsk_lread(self, geom, secbuf, 0); if (e) { dsk_free(secbuf); return DSK_ERR_BADFMT; } /* Acorn ADFS discs have a size in sectors at 0xFC in the * first sector */ dsksize = secbuf[0xFC] + 256 * secbuf[0xFD] + 65536L * secbuf[0xFE]; dsk_free(secbuf); if (dsksize == 640) return dg_stdformat(geom, FMT_ACORN160, NULL, NULL); if (dsksize == 1280) return dg_stdformat(geom, FMT_ACORN320, NULL, NULL); if (dsksize == 2560) return dg_stdformat(geom, FMT_ACORN640, NULL, NULL); /* The DOS Plus boot floppy has 2720 here for * some reason */ if (dsksize == 2720) return dg_stdformat(geom, FMT_ACORN640, NULL, NULL); return DSK_ERR_BADFMT; } } if (secid.fmt_secsize == 1024) { dsk_rate_t rate; /* Ampro 80 track double sided */ if ((secid.fmt_sector & 0xF0) == 0x10) { dsk_free(secbuf); e = dg_stdformat(geom, FMT_AMPRO800, NULL, NULL); if (!e) set_fixed_fs(self, FMT_AMPRO800); return e; } /* Save the data rate, which we know to be correct */ rate = geom->dg_datarate; dsk_free(secbuf); /* Switch to a format with 1k sectors */ if (geom->dg_datarate == RATE_HD) e = dg_stdformat(geom, FMT_ACORN1600, NULL, NULL); else e = dg_stdformat(geom, FMT_ACORN800, NULL, NULL); if (e) return e; /* And restore it. */ geom->dg_datarate = rate; /* Allocate buffer for boot sector (1k bytes) */ secbuf = dsk_malloc(geom->dg_secsize); if (!secbuf) return DSK_ERR_NOMEM; e = dsk_lread(self, geom, secbuf, 0); if (!e) { dsksize = secbuf[0xFC] + 256 * secbuf[0xFD] + 65536L * secbuf[0xFE]; /* Check for 1600k-format */ if (geom->dg_datarate == RATE_HD) { /* XXX Need a better check for Acorn 1600k */ dsk_free(secbuf); return DSK_ERR_OK; } /* Check for D-format magic */ if (dsksize == 3200) { dsk_free(secbuf); return DSK_ERR_OK; } /* Check for E-format magic */ if (secbuf[4] == 10 && secbuf[5] == 5 && secbuf[6] == 2 && secbuf[7] == 2) { dsk_free(secbuf); return DSK_ERR_OK; } } /* Check for DOS Plus magic. DOS Plus has sectors * based at 1, not 0. */ geom->dg_secbase = 1; e = dsk_lread(self, geom, secbuf, 0); if (!e) { if (secbuf[0] == 0xFD && secbuf[1] == 0xFF && secbuf[2] == 0xFF) { dsk_free(secbuf); return DSK_ERR_OK; } } dsk_free(secbuf); return DSK_ERR_BADFMT; } /* Can't handle other discs with non-512 sector sizes. */ if ((secid.fmt_secsize != 512)) { dsk_free(secbuf); return DSK_ERR_BADFMT; } } /* If the driver couldn't do a READ ID call, then ignore it */ if (e == DSK_ERR_NOTIMPL) e = DSK_ERR_OK; /* Try to ID the disc from its boot sector */ if (!e) e = dsk_lread(self, geom, secbuf, 0); if (e) { dsk_free(secbuf); return e; } /* Save the data rate, because what we have is right, and what's * in the sector might not be. */ oldrate = geom->dg_datarate; /* We have the sector. Let's try to guess what it is */ e = dg_dosgeom(geom, secbuf); if (e == DSK_ERR_OK) { set_dos_fs(self, geom, secbuf + 11); } if (e == DSK_ERR_BADFMT) { /* If dg_pcwgeom succeeded, we have a CP/M filesystem with known parameters */ e = dg_pcwgeom(geom, secbuf); if (e == DSK_ERR_OK) set_pcw_fs(self, geom, secbuf); } if (e == DSK_ERR_BADFMT) { e = dg_aprigeom(geom, secbuf); if (e == DSK_ERR_OK) { set_dos_fs(self, geom, secbuf + 80); } } if (e == DSK_ERR_BADFMT) { e = dg_cpm86geom(geom, secbuf); if (e == DSK_ERR_OK) set_cpm86_fs(self, geom, secbuf); } /* Check for Oups Discovery 1 */ if (e == DSK_ERR_BADFMT) { e = dg_opusgeom(geom, secbuf); /* if (e == DSK_ERR_OK) set_opus_fs(self, geom, secbuf); */ } geom->dg_datarate = oldrate; dsk_free(secbuf); return e; }