Esempio n. 1
0
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);
}
Esempio n. 2
0
/* 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;
}