Sophie

Sophie

distrib > Mageia > 3 > i586 > by-pkgid > 6d5b8295b159386e3c8a7f157dbaddee > files > 7

libdsk-devel-1.2.1-2.mga3.i586.rpm

#LyX 1.3 created this file. For more info see http://www.lyx.org/
\lyxformat 221
\textclass article
\language english
\inputencoding latin1
\fontscheme times
\graphics default
\paperfontsize default
\spacing single 
\papersize a4paper
\paperpackage a4
\use_geometry 0
\use_amsmath 0
\use_natbib 0
\use_numerical_citations 0
\paperorientation portrait
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\defskip medskip
\quotes_language english
\quotes_times 2
\papercolumns 1
\papersides 1
\paperpagestyle default

\layout Title

LibDsk v1.2.1 
\layout Author

John Elliott
\layout Abstract

LibDsk is a library intended to give transparent access to floppy drives
 and to the 
\begin_inset Quotes eld
\end_inset 

disc image files
\begin_inset Quotes erd
\end_inset 

 used by emulators to represent floppy drives.
\layout Abstract

This library is free software, released under the GNU Library GPL.
 See COPYING for details.
\layout Standard
\pagebreak_top \pagebreak_bottom 

\begin_inset LatexCommand \tableofcontents{}

\end_inset 


\layout Section

Introduction
\layout Subsection

About this document
\layout Standard

This document only covers LibDsk -- the library -- itself.
 For information on the example utilities supplied with LibDsk (apriboot,
 dskform, dsktrans, dskid, dskdump, dskscan, dskutil and md3serial) see
 their respective manual pages.
\layout Subsection

About LibDsk
\layout Standard

LibDsk is a library for accessing floppy drives and disc images transparently.
 It currently supports the following disc image formats:
\layout Itemize

Raw 
\begin_inset Quotes eld
\end_inset 

dd if=foo of=bar
\begin_inset Quotes erd
\end_inset 

 images;
\layout Itemize

Raw images in logical filesystem order;
\layout Itemize

CPCEMU-format .DSK images (normal and extended); 
\layout Itemize

MYZ80-format hard drive images; 
\layout Itemize

CFI-format disc images, as produced by FDCOPY.COM under DOS and used to distribut
e some Amstrad system discs; 
\layout Itemize

ApriDisk-format disc images, used by the utility of the same name under
 DOS.
\layout Itemize

NanoWasp-format disc images, used by the eponymous emulator.
\layout Itemize

Disc images created by the Sydex imaging programs Teledisk and CopyQM (read
 only in both cases).
\layout Itemize

The floppy drive under Linux; 
\layout Itemize

The floppy drive under Windows.
 Windows support is a complicated subject - see section 
\begin_inset LatexCommand \ref{ldwindows}

\end_inset 

 below.
\layout Itemize

The floppy drive (and hard drive partitions) under DOS.
\layout Standard

LibDsk also supports compressed disc images in the following formats: 
\layout Itemize

Squeeze (Huffman coded) 
\layout Itemize

GZip (Deflate ) 
\layout Itemize

BZip2 (Burrows-Wheeler; support is read-only)
\layout Subsection

What's new? 
\layout Standard

For full details, see the file ChangeLog.
\layout Itemize

Should now compile out of the box on FreeBSD.
\layout Itemize

A bugfix to the rcpmfs driver should allow it to simulate a CP/M 2 filesystem
 as well as CP/M 3.
\layout Itemize

Added two new drivers: 
\begin_inset Quotes eld
\end_inset 

teledisk
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

logical
\begin_inset Quotes erd
\end_inset 

.
\layout Itemize

Changes by Ramlaid <www.ramlaid.com> to the DSK and NTWDM drivers to improve
 compatibility, and another fix to stop file handles leaking.
\layout Itemize

Added a new driver: 
\begin_inset Quotes eld
\end_inset 

int25
\begin_inset Quotes erd
\end_inset 

.
 This allows the DOS version to run on Apricot PCs (which do not have an
 IBM-compatible BIOS) and to access hard drive partitions.
\layout Itemize

Bugfix in the Linux floppy driver, which could cause 
\begin_inset Quotes eld
\end_inset 

No data
\begin_inset Quotes erd
\end_inset 

 errors logging in certain disc formats.
\layout Itemize

Bugfix in the rcpmfs driver: Files saved to user 1 no longer go to user
 0.
\layout Itemize

Enhanced the ApriDisk driver to handle disc images that start with a 'creator'
 block.
\layout Itemize

Enhanced the rcpmfs driver to deal with truncation of existing files.
\layout Itemize

Added initial support for 'multiple/weak' sectors in the 'dsk' driver.
 LibDsk can read such sectors, but not write them (they get written as normal
 sectors).
\layout Itemize

Bug fix: Don't leak file handles in the 'dsk' driver.
\layout Itemize

The internal RPC system has been expanded to allow operation over a serial
 line.
 
\layout Itemize

The Win32 (VC++ 6) version now includes an ATL project to present LibDsk
 as a COM object.
\layout Itemize

'ntwdm' driver added by Simon Owen.
\layout Itemize

dsk_dirty() function added by Philip Kendall.
\layout Itemize

LibDsk now reads a 'libdskrc' file (section 
\begin_inset LatexCommand \ref{sub:libdskrc-format}

\end_inset 

) at startup; this can contain additional format definitions.
\layout Itemize

An experimental read-only driver to handle CopyQM disc images (written by
 Per Ola Ingvarsson, who also documented the file format - section 
\begin_inset LatexCommand \ref{sec:copyqm}

\end_inset 

).
\layout Itemize

Experimental support for an 'rcpmfs' driver (section 
\begin_inset LatexCommand \ref{sec:rcpmfs}

\end_inset 

) which presents directories as CP/M disk images.
\layout Itemize

DSK files now store density and recording mode.
\layout Itemize

LibDsk can now retry failed reads/writes/formats.
\layout Itemize

Extra functions have been added to support disc images that contain comments.
\layout Itemize

Extra functions have been added for display of messages from LibDsk.
\layout Itemize

A driver has been added for the disc image files used by the ApriDisk utility.
\layout Itemize

The parameter order of the example utilities has been made less rigid.
\layout Subsection

Terms and definitions
\layout Standard

In this document, I use the word 
\noun on 
cylinder
\noun toggle 
 to refer to a position on a floppy disc, and 
\noun on 
track
\noun toggle 
 to refer to the data within a cylinder on one side of the disc.
 For a single-sided disc, these are the same; for a double-sided disc, there
 are twice as many tracks as cylinders.
 
\layout Section


\begin_inset LatexCommand \label{formats}

\end_inset 

Supported file formats
\layout Standard

The following disc image file formats are supported by LibDsk.
\layout Description


\begin_inset Quotes eld
\end_inset 

dsk
\begin_inset Quotes erd
\end_inset 

 : Disc image in the DSK format used by CPCEMU.
 The format of a .DSK file is described in the CPCEMU documentation.
\layout Description


\begin_inset Quotes eld
\end_inset 

edsk
\begin_inset Quotes erd
\end_inset 

 : Disc image in the extended CPCEMU DSK format.
 
\layout Description


\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 : Raw disc image - as produced by 
\begin_inset Quotes eld
\end_inset 


\family typewriter 
dd if=/dev/fd0 of=image
\family default 

\begin_inset Quotes erd
\end_inset 

.
 On systems other than Linux, DOS or Windows, this is also used to access
 the host system's floppy drive.
\layout Description


\begin_inset Quotes eld
\end_inset 

logical
\begin_inset Quotes erd
\end_inset 

 : Raw disc image in logical filesystem order.
 Previous versions of LibDsk could generate such images (for example, by
 using the now-deprecated
\family typewriter 
 -logical
\family default 
 option to dsktrans) but couldn't then write them back or use them in emulators.
\layout Description


\begin_inset Quotes eld
\end_inset 

floppy
\begin_inset Quotes erd
\end_inset 

 : Host system's floppy drive (under Linux, DOS or Windows).
 
\layout Description


\begin_inset Quotes eld
\end_inset 

int25
\begin_inset Quotes erd
\end_inset 

 : Hard drive partition under DOS.
 Also used for the floppy drive on Apricot PCs.
\layout Description


\begin_inset Quotes eld
\end_inset 

ntwdm
\begin_inset Quotes erd
\end_inset 

 : Enhanced floppy support under Windows 2000 and XP, using an additional
 kernel-mode driver.
\layout Description


\begin_inset Quotes eld
\end_inset 

myz80
\begin_inset Quotes erd
\end_inset 

 : MYZ80 hard drive image, which is 
\emph on 
nearly
\emph toggle 
 the same as 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 but has a 256 byte header.
 
\layout Description


\begin_inset Quotes eld
\end_inset 

cfi
\begin_inset Quotes erd
\end_inset 

 : Compressed floppy image, as produced by FDCOPY.COM under DOS.
 Its format is described in cfi.html.
\layout Description


\begin_inset Quotes eld
\end_inset 

qm
\begin_inset Quotes erd
\end_inset 

 : Disc images created by Sydex's CopyQM.
 This is a read-only driver.
\layout Description


\begin_inset Quotes eld
\end_inset 

teledisk
\begin_inset Quotes erd
\end_inset 

 : Disc images created by Sydex's TeleDisk.
 This is a read-only driver.
\layout Description


\begin_inset Quotes eld
\end_inset 

nanowasp
\begin_inset Quotes erd
\end_inset 

 : Disc image in the 400k Microbee format used by the NanoWasp emulator.
 This is similar to 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

, but the tracks are stored in a different order.
 LibDsk also applies a sector skew so that the sectors are read/written
 in the logical order.
 Strictly speaking, it should not do this (when libdsk is used with cpmtools,
 cpmtools is the one that does the skewing) but cpmtools cannot handle the
 skewing scheme used by the Microbee format.
\layout Description


\begin_inset Quotes eld
\end_inset 

apridisk
\begin_inset Quotes erd
\end_inset 

: Disc image in the format used by the ApriDisk utility.
 The format is described in apridisk.html.
\layout Description


\begin_inset Quotes eld
\end_inset 

rcpmfs
\begin_inset Quotes erd
\end_inset 

: Reverse CP/M filesystem.
 A directory is made to appear as a CP/M disk.
 This is an experimental system and should be approached with caution.
\layout Description


\begin_inset Quotes eld
\end_inset 

remote
\begin_inset Quotes erd
\end_inset 

: Remote LibDsk server, most likely at the other end of a serial line.
\layout Section

Architecture 
\layout Standard

LibDsk is composed of a fixed core (files named 
\family typewriter 
dsk*.c
\family default 
) and a number of drivers (files named 
\family typewriter 
drv*.c
\family default 
).
 When you open an image or a drive (using 
\family typewriter 
dsk_open()
\family default 
 or 
\family typewriter 
dsk_creat()
\family default 
 ) then a driver is chosen.
 This driver is then used until it's closed (
\family typewriter 
dsk_close()
\family default 
).
 
\layout Standard

Each driver is identified by a name.
 To get a list of available drivers, use 
\family typewriter 
dsk_type_enum()
\family default 
.
 To get the driver that is being used by an open DSK image, use 
\family typewriter 
dsk_drvname()
\family default 
 or 
\family typewriter 
dsk_drvdesc()
\family default 
.
\layout Subsection

Logical and physical sectors
\layout Standard

LibDsk has two models of disc geometry.
 One is as a linear array of 
\begin_inset Quotes eld
\end_inset 

logical
\begin_inset Quotes erd
\end_inset 

 sectors - for example, a 720k floppy appears as 1440 512-byte sectors numbered
 0 to 1439.
 The other locates each sector using a (Cylinder, Head, Sector) triple -
 so on the 720k floppy described earlier, sectors would run from (0,0,1)
 to (79,1,9).
 
\layout Standard

Internally, all LibDsk drivers are written to use the Cylinder/Head/Sector
 model.
 For those calls which take parameters in logical sectors, LibDsk uses the
 information in a 
\family typewriter 
DSK_GEOMETRY
\family default 
 structure to convert to C/H/S.
 
\family typewriter 
DSK_GEOMETRY
\family default 
 also contains information such as the sector size and data rate used to
 access a given disc.
 
\layout Standard

Those functions which deal with whole tracks (such as the command to format
 a track) use logical tracks and (cylinder,head) pairs instead.
 To initialise a 
\family typewriter 
DSK_GEOMETRY
\family default 
 structure, either: 
\layout Itemize

call 
\family typewriter 
dsk_getgeom()
\family default 
 to try and detect it from the disc; or 
\layout Itemize

call 
\family typewriter 
dg_stdformat()
\family default 
 to select one of the 
\begin_inset Quotes eld
\end_inset 

standard
\begin_inset Quotes erd
\end_inset 

 formats that LibDsk knows about; or 
\layout Itemize

call 
\family typewriter 
dg_dosgeom()
\family default 
 / 
\family typewriter 
dg_cpm86geom()
\family default 
 / 
\family typewriter 
dg_pcwgeom() 
\family default 
/
\family typewriter 
 dg_aprigeom()
\family default 
 to initialise it from a copy of a DOS / CP/M86 / PCW / Apricot boot sector;
 or 
\layout Itemize

Set all the members manually.
\layout Subsubsection


\begin_inset LatexCommand \label{sec: dskgeom}

\end_inset 

DSK_GEOMETRY in detail
\layout LyX-Code

typedef struct
\layout LyX-Code

{
\layout Description


\family typewriter 
dsk_sides_t\SpecialChar ~
dg_sidedness;
\family default 
 /* This describes the logical sequence of tracks on the disc - the order
 in which their host system reads them.
 This will only be used if 
\family typewriter 
dg_heads
\family default 
 is greater than 1 (otherwise all the methods are equivalent) and you are
 using functions that take logical sectors or tracks as parameters.
 It will be one of: 
\begin_deeper 
\layout Description


\family typewriter 
SIDES_ALT
\family default 
 The tracks are ordered Cylinder 0 Head 0; C0H1; C1H0; C1H1; C2H0; C2H1
 etc.
 This layout is used by most PC-hosted operating systems, including DOS
 and Linux.
 Amstrad's 8-bit operating systems also use this ordering.
\layout Description


\family typewriter 
SIDES_OUTBACK
\family default 
 The tracks go out to the edge on Head 0, and then back in on Head 1 (so
 Cylinder 0 Head 0 is the first track, while Cylinder 0 Head 1 is the last).
 This layout is used by Freek Heite's 144FEAT driver (for CP/M-86 on the
 PC) but I have not seen it elsewhere.
\layout Description


\family typewriter 
SIDES_OUTOUT
\family default 
 The tracks go out to the edge on Head 0, then out again on Head 1 (so the
 order goes C(last)H0, C0H1, C1H1, ..., C(last)H1).
 This ordering is used by Acorn-format discs.
\layout Standard

*/
\end_deeper 
\layout Description


\family typewriter 
dsk_pcyl_t\SpecialChar ~
dg_cylinders;
\family default 
 /* The number of cylinders this disc has.
 Usually 40 or 80.
 */
\layout Description


\family typewriter 
dsk_phead_t\SpecialChar ~
dg_heads;
\family default 
 /* The number of heads (sides) the disc has.
 Usually 1 or 2.
 */
\layout Description


\family typewriter 
dsk_psect_t\SpecialChar ~
dg_sectors;
\family default 
 /* The number of sectors per track.
 */
\layout Description


\family typewriter 
dsk_psect_t\SpecialChar ~
dg_secbase;
\family default 
 /* The first physical sector number.
 Most systems start numbering their sectors at 1; Acorn systems start at
 0, and Amstrad CPCs start at 65 or 193.
 */
\layout Description


\family typewriter 
size_t\SpecialChar ~
dg_secsize;
\family default 
 /* Sector size in bytes.
 Note that several drivers rely on this being a power of 2.
 */
\layout Description


\family typewriter 
dsk_rate_t\SpecialChar ~
dg_datarate;
\family default 
 /* Data rate.
 This will be one of:
\begin_deeper 
\layout Description


\family typewriter 
RATE_HD 
\family default 
High-density disc (1.4Mb or 1.2Mb)
\layout Description


\family typewriter 
RATE_DD 
\family default 
Double-density disc in 1.2Mb drive (ie, 360k disc in 1.2Mb drive)
\layout Description


\family typewriter 
RATE_SD
\family default 
 Double-density disc in 1.4Mb or 720k drive
\layout Description


\family typewriter 
RATE_ED
\family default 
 Extra-density disc (2.8Mb) */
\end_deeper 
\layout Description


\family typewriter 
dsk_gap_t\SpecialChar ~
dg_rwgap;
\family default 
 /* Read/write gap length */
\layout Description


\family typewriter 
dsk_gap_t\SpecialChar ~
dg_fmtgap; 
\family default 
/* Format gap length */
\layout Description


\family typewriter 
int\SpecialChar ~
dg_fm;
\family default 
 /* Set to nonzero to use FM (single density) recording mode.
 Not all PC floppy controllers support this mode; the National Semiconductor
 PC87306 and the Future Domain TMC series SCSI controllers can at least
 read FM discs.
 The BBC Micro used FM recording for its 100k and 200k DFS formats.
 The Windows / DOS floppy drivers do not support FM recording.
 */
\layout Description


\family typewriter 
int\SpecialChar ~
dg_nomulti; 
\family default 
/* Set to nonzero to disable multitrack mode.
 This only affects attempts to read normal data from tracks containing deleted
 data (or vice versa).
 */
\layout Description


\family typewriter 
int\SpecialChar ~
dg_noskip;
\family default 
 /* Set to nonzero to disable skipping deleted data when searching for non-delet
ed data (or vice versa).
 */
\layout LyX-Code

} DSK_GEOMETRY;
\layout Section

LibDsk Function Reference 
\layout Subsection

dsk_open: Open an existing disc image
\layout LyX-Code

dsk_err_t dsk_open(DSK_PDRIVER *self, const char *filename, const char *type,
 const char *compress)
\layout Standard

Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is the address of a DSK_PDRIVER variable (treat it as a handle to a drive
 / disc file).
 On return, the variable will be non-null (if the operation succeeded) or
 null (if the operation failed).
  
\layout Itemize


\begin_inset Quotes eld
\end_inset 

filename
\begin_inset Quotes erd
\end_inset 

 is the name of the disc image file.
 On DOS and Windows, 
\begin_inset Quotes eld
\end_inset 

A:
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

B:
\begin_inset Quotes erd
\end_inset 

 refer to the two floppy drives.
 On Apricot MS-DOS, 
\begin_inset Quotes eld
\end_inset 

0:
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

1:
\begin_inset Quotes erd
\end_inset 

 refer to the floppy drives.
\layout Itemize


\begin_inset Quotes eld
\end_inset 

type
\begin_inset Quotes erd
\end_inset 

 is NULL to detect the disc image format automatically, or the name of a
 LibDsk driver to force that driver to be used.
 See 
\family typewriter 
dsk_type_enum()
\family default 
 below.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

compress
\begin_inset Quotes erd
\end_inset 

 is NULL to auto-detect compressed files, or the name of a LibDsk compression
 scheme.
 See 
\family typewriter 
dsk_comp_enum()
\family default 
.
 
\layout Standard

Returns: A 
\family typewriter 
dsk_err_t,
\family default 
 which will be 0 (
\family typewriter 
DSK_ERR_OK
\family default 
) if successful, or a negative integer if failed.
 See 
\family typewriter 
dsk_strerror()
\family default 
.
 The error 
\family typewriter 
DSK_ERR_NOTME
\family default 
 means either that no driver was able to open the disc / disc image (if
 
\begin_inset Quotes eld
\end_inset 

type
\begin_inset Quotes erd
\end_inset 

 was NULL) or that the requested driver could not open the file (if 
\begin_inset Quotes eld
\end_inset 

type
\begin_inset Quotes erd
\end_inset 

 was not NULL).
\layout Standard

Standard LibDsk drivers are listed in section 
\begin_inset LatexCommand \ref{formats}

\end_inset 

.
\layout Standard

Compression schemes are: 
\layout Description


\begin_inset Quotes eld
\end_inset 

sq
\begin_inset Quotes erd
\end_inset 

 : Huffman (squeezed).
 The reason for the inclusion of this system is to support .DQK images (see
 appendix 
\begin_inset LatexCommand \ref{sec: dqk}

\end_inset 

).
 
\layout Description


\begin_inset Quotes eld
\end_inset 

gz
\begin_inset Quotes erd
\end_inset 

 : GZip (deflate).
 This will only be present if libdsk was built with zlib support.
 
\layout Description


\begin_inset Quotes eld
\end_inset 

bz2
\begin_inset Quotes erd
\end_inset 

 : BZip2 (Burrows-Wheeler compression).
 This support is currently read-only, and will only be present if LibDsk
 was built with bzlib support.
\layout Subsection

dsk_creat: Create a new disc image
\layout LyX-Code

dsk_err_t dsk_creat(DSK_PDRIVER *self, const char *filename, const char
 *type)
\layout Standard

In the case of floppy drives, this acts exactly as 
\family typewriter 
dsk_open()
\family default 
.
 For image files, the file will be deleted and recreated.
 Parameters and results are as for 
\family typewriter 
dsk_open()
\family default 
, except that 
\begin_inset Quotes eld
\end_inset 

type
\begin_inset Quotes erd
\end_inset 

 cannot be NULL (it must specify the type of disc image to be created) and
 if 
\begin_inset Quotes eld
\end_inset 

compress
\begin_inset Quotes erd
\end_inset 

 is NULL, it means that the file being created should not be compressed.
\layout Subsection

dsk_close: Close a drive or disc image
\layout LyX-Code

dsk_err_t dsk_close(DSK_PDRIVER *self)
\layout Standard

Pass the address of an opaque pointer returned from 
\family typewriter 
dsk_open() 
\family default 
/ 
\family typewriter 
dsk_creat()
\family default 
.
 On return, the drive will have been closed and the pointer set to NULL.
\layout Subsection

dsk_dirty: Read the dirty flag
\layout LyX-Code

int dsk_dirty(DSK_PDRIVER self)
\layout Standard

This function returns non-zero if the disc has been modified since it was
 inserted into the drive, and zero if it has not been modified.
 
\layout Subsection

dsk_pread, dsk_lread : Read a sector
\layout LyX-Code

dsk_err_t dsk_pread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector) 
\layout LyX-Code

dsk_err_t dsk_lread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_lsect_t sector)
\layout Standard

These functions read a single sector from the disc.
 There are two of them, depending on whether you are using logical or physical
 sector addresses.
\layout Standard

Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is a handle to an open drive / image file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 points to the geometry for the drive.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

buf
\begin_inset Quotes erd
\end_inset 

 is the buffer into which data will be loaded.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

, 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

sector
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_pread
\family default 
) or 
\begin_inset Quotes eld
\end_inset 

sector
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_lread
\family default 
) give the location of the sector.
 
\layout Standard

Returns: 
\layout Itemize

If successful, DSK_ERR_OK.
 Otherwise, a negative DSK_ERR_* value.
 
\layout Itemize

If the driver cannot read sectors, DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_pwrite, dsk_lwrite: Write a sector
\layout LyX-Code

dsk_err_t dsk_pwrite(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector) 
\layout LyX-Code

dsk_err_t dsk_lwrite(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_lsect_t sector)
\layout Standard

As dsk_pread / dsk_lread, but write their buffers to disc rather than reading
 them from disc.
 If the driver cannot write sectors, DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_pcheck, dsk_lcheck: Verify sectors on disc against memory
\layout LyX-Code

dsk_err_t dsk_pcheck(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector) 
\layout LyX-Code

dsk_err_t dsk_lcheck(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_lsect_t sector)
\layout Standard

As 
\family typewriter 
dsk_pread
\family default 
 / 
\family typewriter 
dsk_lread
\family default 
, but rather than reading their buffers from disc, they compare the contents
 of their buffers with the data already on the disc.
 If the data match, the functions return DSK_ERR_OK.
 If there is a mismatch, they return DSK_ERR_MISMATCH.
 In case of error, other DSK_ERR_* values are returned.
 If the driver cannot read sectors, DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_pformat, dsk_lformat: Format a disc track
\layout LyX-Code

dsk_err_t dsk_pformat(DSK_PDRIVER self, DSK_GEOMETRY *geom, dsk_pcyl_t cylinder,
 dsk_phead_t head, const DSK_FORMAT *format, unsigned char filler) 
\layout LyX-Code

dsk_err_t dsk_lformat(DSK_PDRIVER self, DSK_GEOMETRY *geom, dsk_ltrack_t
 track, const DSK_FORMAT *format, unsigned char filler)
\layout Standard

Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is a handle to an open drive / image file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 points to the geometry for the drive.
 The formatter may modify this if (for example) it's asked to format track
 41 of a 40-track drive.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

 / 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_pformat
\family default 
) or 
\begin_inset Quotes eld
\end_inset 

track
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_lformat
\family default 
) give the location of the track to format.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

format
\begin_inset Quotes erd
\end_inset 

 should be an array of (
\family typewriter 
geom->dg_sectors
\family default 
) DSK_FORMAT structures.
 These structures must contain sector headers for the track being formatted.
 For example, to format the first track of a 720k disc, you would pass in
 an array of 9 such structures: { 0, 0, 1, 512 }, { 0, 0, 2, 512, } ..., {
 0, 0, 9, 512 } 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

filler
\begin_inset Quotes erd
\end_inset 

 should be the filler byte to use.
 Currently the Win32 driver ignores this parameter.
 If the driver cannot format tracks, DSK_ERR_NOTIMPL will be returned.
\layout Standard

Note that when formatting a .DSK file that has more than one head, you must
 format cylinder 0 for each head before formatting other cylinders.
\layout Subsection

dsk_apform, dsk_alform: Automatic format
\layout LyX-Code

dsk_err_t dsk_apform(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, unsigned char filler) 
\layout LyX-Code

dsk_err_t dsk_alform(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_ltrack_t
 track, unsigned char filler)
\layout Standard

These function calls behave as 
\family typewriter 
dsk_pformat()
\family default 
 and 
\family typewriter 
dsk_lformat() 
\family default 
above, except that the sector headers are automatically generated.
 This saves time and trouble setting up sector headers on discs with standard
 layouts such as DOS, PCW or Linux floppies.
 If the driver cannot format tracks, DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_psecid, dsk_lsecid: Read a sector ID.
\layout LyX-Code

dsk_err_t dsk_psecid(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, DSK_FORMAT *result) 
\layout LyX-Code

dsk_err_t dsk_lsecid(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_ltrack_t
 track, DSK_FORMAT *result)
\layout Standard

Read a sector ID from the given track.
 This can be used to probe for discs with oddly-numbered sectors (eg, numbered
 65-74).
 Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is a handle to an open drive / image file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 points to the geometry for the drive.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

 / 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_psecid
\family default 
) or 
\begin_inset Quotes eld
\end_inset 

track
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_lsecid
\family default 
) give the location of the track to read the sector from.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

result
\begin_inset Quotes erd
\end_inset 

 points to an uninitialised 
\family typewriter 
DSK_FORMAT
\family default 
 structure.
 
\layout Standard

On return: 
\layout Itemize

If successful, the buffer at 
\begin_inset Quotes eld
\end_inset 

result
\begin_inset Quotes erd
\end_inset 

 will be initialised with the sector header found, and DSK_ERR_OK will be
 returned.
 
\layout Itemize

If the driver cannot provide this functionality (for example, the Win32
 driver under NT), DSK_ERR_NOTIMPL will be returned.
\layout Standard

Note that the DOS, Win16 and Win32 (under Win9x) drivers implement a limited
 version of this call, which will work on normal DOS / CP/M86 / PCW discs
 and CPC discs.
 However it will not be usable for other purposes.
\layout Subsection

dsk_ptrackids, dsk_ltrackids: Identify sectors on track.
\layout LyX-Code

dsk_err_t dsk_ptrackids(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, dsk_psect_t *count, DSK_FORMAT **result) 
\layout LyX-Code

\layout LyX-Code

dsk_err_t dsk_ltrackids(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_ltrack_t
 track, dsk_psect_t *count, DSK_FORMAT **result)
\layout Standard

These functions are intended to read all the sector IDs from a track, in
 order, and (preferably) starting at the index hole.
 If they succeed, 'result' will point at an array of DSK_FORMAT structures
 describing the sectors found.
 This array will have been allocated with dsk_malloc() and should be freed
 with dsk_free().
\layout Subsection

dsk_rtread: Reserved.
\layout LyX-Code

dsk_err_t  dsk_rtread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, int reserved); 
\layout Standard

This function is reserved for future expansion.
 The intention is to use it for diagnostic read commands (such as reading
 the raw bits from a track).
 Currently it returns DSK_ERR_NOTIMPL.
\layout Subsection

dsk_xread, dsk_xwrite: Low-level reading and writing
\layout LyX-Code

dsk_err_t dsk_xread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead_t
 head_expected, dsk_psect_t sector, size_t sector_len, int *deleted); 
\layout LyX-Code

dsk_err_t dsk_xwrite(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const void
 *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead
_t head_expected, dsk_psect_t sector, size_t sector_len, int deleted);
\layout Standard

dsk_xread() and dsk_xwrite() are extended versions of dsk_pread() and dsk_pwrite
().
 They allow the caller to read/write sectors whose sector ID differs from
 the physical location of the sector, or to read/write deleted data..
 The 
\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 arguments specify where to look; the 
\begin_inset Quotes eld
\end_inset 

cyl_expected
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

head_expected
\begin_inset Quotes erd
\end_inset 

 are the values to search for in the sector header.
 
\layout Standard

These functions are only supported by the CPCEMU driver, the Linux floppy
 driver and the NTWDM floppy driver.
 Other drivers will return DSK_ERR_NOTIMPL.
 Unless you are emulating a floppy controller, or you need to read discs
 that contain deleted data or misnumbered sectors, it should not be necessary
 to call these functions.
\layout Subsubsection

dsk_xread(), dsk_xwrite(): Deleted data 
\layout Standard

The 
\begin_inset Quotes eld
\end_inset 

deleted
\begin_inset Quotes erd
\end_inset 

 argument is used if you want to read or write sectors that have been marked
 as deleted.
 In 
\family typewriter 
dsk_xwrite()
\family default 
, this is a simple value; pass 0 to write normal data, or 1 to write deleted
 data.
 In 
\family typewriter 
dsk_xread()
\family default 
, pass the address of an integer containing 0 (read normal data) or 1 (read
 deleted data).
 On return, the integer will contain: 
\layout Itemize

If the requested data type was read: 0 
\layout Itemize

If the other data type was read: 1 
\layout Itemize

If the command failed: Value is meaningless.
 
\layout Standard

Passing 
\family typewriter 
NULL
\family default 
 acts the same as passing a pointer to 0.
\layout Standard

The opposite type of data will only be read if you set 
\family typewriter 
geom->dg_noskip
\family default 
 to nonzero.
 Some examples:
\layout Standard
\added_space_top 0.3cm \added_space_bottom 0.3cm \align center 

\begin_inset  Tabular
<lyxtabular version="3" rows="8" columns="5">
<features>
<column alignment="center" valignment="top" leftline="true" width="0pt">
<column alignment="center" valignment="top" leftline="true" width="0pt">
<column alignment="center" valignment="top" leftline="true" rightline="true" width="0pt">
<column alignment="center" valignment="top" leftline="true" width="0pt">
<column alignment="center" valignment="top" leftline="true" rightline="true" width="0pt">
<row topline="true" bottomline="true">
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

geom->dg_noskip
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

deleted
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Data on disc
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Results
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

*deleted becomes
\end_inset 
</cell>
</row>
<row topline="true" bottomline="true">
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

-> 0
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Normal
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
</row>
<row bottomline="true">
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

-> 0
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Deleted
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

DSK_ERR_NODATA
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

??
\end_inset 
</cell>
</row>
<row bottomline="true">
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

-> 1
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Deleted
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

DSK_ERR_NODATA
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

??
\end_inset 
</cell>
</row>
<row bottomline="true">
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

-> 0
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Normal
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
</row>
<row bottomline="true">
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

-> 0
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Deleted
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
</row>
<row bottomline="true">
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

-> 1
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Normal
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
</row>
<row bottomline="true">
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

-> 1
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Deleted
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

DSK_ERR_OK
\end_inset 
</cell>
<cell alignment="center" valignment="top" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

0
\end_inset 
</cell>
</row>
</lyxtabular>

\end_inset 


\layout Subsection

dsk_ltread, dsk_ptread, dsk_xtread 
\layout LyX-Code

dsk_err_t dsk_ltread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_ltrack_t track) 
\layout LyX-Code

dsk_err_t dsk_ptread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head) 
\layout LyX-Code

dsk_err_t dsk_xtread(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead_t
 head_expected)
\layout Standard

These functions read a track from the disc, using the FDC's 
\begin_inset Quotes eld
\end_inset 

READ TRACK
\begin_inset Quotes erd
\end_inset 

 command.
 There are three of them - logical, physical and extended physical.
\layout Standard

If the driver does not support this functionality, LibDsk will attempt to
 simulate it using multiple sector reads.
\layout Standard

Enter with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is a handle to an open drive / image file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 points to the geometry for the drive.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

buf
\begin_inset Quotes erd
\end_inset 

 is the buffer into which data will be loaded.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

cylinder
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_ptread
\family default 
, 
\family typewriter 
dsk_xtread
\family default 
) or 
\begin_inset Quotes eld
\end_inset 

track
\begin_inset Quotes erd
\end_inset 

 (
\family typewriter 
dsk_ltread
\family default 
) give the location of the track to read.
 
\layout Itemize

(
\family typewriter 
dsk_xtread
\family default 
) 
\begin_inset Quotes eld
\end_inset 

cyl_expected
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

head_expected
\begin_inset Quotes erd
\end_inset 

 are used as the values to search for in the sector headers.
 
\layout Standard

Returns: 
\layout Itemize

If successful, DSK_ERR_OK.
 Otherwise, a negative DSK_ERR_* value.
 
\layout Itemize

(
\family typewriter 
dsk_xtread()
\family default 
 only) If the driver does not support extended sector reads/writes, then
 DSK_ERR_NOTIMPL will be returned.
\layout Subsection

dsk_lseek, dsk_pseek 
\layout LyX-Code

dsk_err_t dsk_lseek(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_ltrack_t
 track)
\layout LyX-Code

dsk_err_t dsk_pseek(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head)
\layout Standard

Seek to a given cylinder.
 Only the CPCEMU driver, the Linux floppy driver and the NTWDM floppy driver
 support this; other drivers return DSK_ERR_NOTIMPL.
 You should not normally need to call these functions.
 They have been provided to support programs that emulate a uPD765A controller.
\layout Subsection

dsk_drive_status 
\layout LyX-Code

dsk_err_t dsk_drive_status(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_phead
_t head, unsigned char *result)
\layout Standard

Get the drive's status (ready, read-only etc.).
 The byte 
\begin_inset Quotes eld
\end_inset 

result
\begin_inset Quotes erd
\end_inset 

 will have one or more of the following bits set:
\layout Description

DSK_ST3_FAULT: Drive fault 
\layout Description

DSK_ST3_RO: Read-only 
\layout Description

DSK_ST3_READY: Ready 
\layout Description

DSK_ST3_TRACK0: Head is over track 0 
\layout Description

DSK_ST3_DSDRIVE: Drive is double-sided 
\layout Description

DSK_ST3_HEAD1: Current head is head 1, not head 0.
 Usually this just depends on the value of the 
\begin_inset Quotes eld
\end_inset 

head
\begin_inset Quotes erd
\end_inset 

 parameter to this function.
 
\layout Standard

Which bits will be 
\begin_inset Quotes eld
\end_inset 

live
\begin_inset Quotes erd
\end_inset 

 depends on which driver is in use, but the most trustworthy will be DSK_ST3_REA
DY and DSK_ST3_RO.
 This function will never return DSK_ERR_NOTIMPL; if the facility is not
 provided by the driver, a default version will be used.
 
\layout Subsection

dsk_dirty: Has drive been written to?
\layout LyX-Code

int dsk_dirty(DSK_PDRIVER self); 
\layout Standard

This returns zero if the disc has not been written to since it was opened,
 nonzero if it has.
\layout Subsection

dsk_getgeom: Guess disc geometry
\layout LyX-Code

dsk_err_t dsk_getgeom(DSK_PDRIVER self, DSK_GEOMETRY *geom)
\layout Standard

This attempts to determine the geometry of a disc (number of cylinders,
 tracks, sectors etc.) by loading the boot sector.
 It understands DOS, Apricot, CP/M-86 and PCW boot sectors.
 If the geometry could be guessed, then 
\begin_inset Quotes eld
\end_inset 

geom
\begin_inset Quotes erd
\end_inset 

 will be initialised and DSK_ERR_OK will be returned.
 If no guess could be made, then DSK_ERR_BADFMT will be returned.
 Other values will result if the disc could not be read.
\layout Standard

Some drivers (in particular the MYZ80 driver, and the Win32 driver under
 NT) only support certain fixed disc geometries.
 In this case, the geometry returned will reflect what the driver can use,
 rather than what the boot sector says.
\layout Subsection

dg_*geom : Initialise disc geometry from boot sector
\layout LyX-Code

dsk_err_t dg_dosgeom(DSK_GEOMETRY *self, const unsigned char *bootsect)
 
\layout LyX-Code

dsk_err_t dg_pcwgeom(DSK_GEOMETRY *self, const unsigned char *bootsect)
 
\layout LyX-Code

dsk_err_t dg_cpm86geom(DSK_GEOMETRY *self, const unsigned char *bootsect)
\layout LyX-Code

dsk_err_t dg_aprigeom(DSK_GEOMETRY *self, const unsigned char *bootsect)
\layout Standard

These functions are used by 
\family typewriter 
dsk_getgeom()
\family default 
, but can also be called independently.
 Enter them with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 is the structure to initialise;
\layout Itemize


\begin_inset Quotes eld
\end_inset 

bootsect
\begin_inset Quotes erd
\end_inset 

 is the boot sector to initialise the structure from.
\layout Standard

Returns DSK_ERR_BADFMT if the sector does not contain a suitable disc specificat
ion, or DSK_ERR_OK otherwise.
\layout Description

dg_dosgeom will check for a PC-DOS boot sector.
\layout Description

dg_pcwgeom will check for an Amstrad PCW boot sector.
\layout Description

dg_cpm86geom will check for a CP/M-86 boot sector.
\layout Description

dg_aprigeom will check for an Apricot DOS boot sector.
\layout Subsection

dg_stdformat : Initialise disc geometry from a standard LibDsk format.
\layout LyX-Code

dsk_err_t dg_stdformat(DSK_GEOMETRY *self, dsk_format_t formatid, dsk_cchar_t
 *fname, dsk_cchar_t *fdesc)
\layout Standard

Initialises a DSK_GEOMETRY structure with one of the standard formats LibDsk
 knows about.
 Formats are:
\layout Description

FMT_180K: 180k, 9 512 byte sectors, 40 tracks, 1 side 
\layout Description

FMT_200K: 200k, 10 512 byte sectors, 40 tracks, 1 side 
\layout Description

FMT_CPCSYS: Amstrad CPC system format - as FMT_180K, but physical sectors
 are numbered 65-73 
\layout Description

FMT_CPCDATA: Amstrad CPC data format - as FMT_180K, but physical sectors
 are numbered 193-201 
\layout Description

FMT_720K: 720k, 9 512 byte sectors, 80 tracks, 2 sides 
\layout Description

FMT_800K: 800k, 10 512 byte sectors, 80 tracks, 2 sides 
\layout Description

FMT_1440K: 1.4M, 18 512 byte sectors, 80 tracks, 2 sides 
\layout Description

FMT_160K: 160k, 8 512 byte sectors, 40 tracks, 1 side 
\layout Description

FMT_320K: As FMT_160K, but 2 sides 
\layout Description

FMT_360K: As FMT_180K, but 2 sides 
\layout Description

FMT_720F: As FMT_720K, but the physical/logical sector mapping is 
\begin_inset Quotes eld
\end_inset 

out-and-back
\begin_inset Quotes erd
\end_inset 

 rather than 
\begin_inset Quotes eld
\end_inset 

alternate sides
\begin_inset Quotes erd
\end_inset 

.
 See section 
\begin_inset LatexCommand \ref{sec: dskgeom}

\end_inset 

 for details.
 
\layout Description

FMT_1200F: As FMT_720F, but with 15 sectors 
\layout Description

FMT_1440F: As FMT_720F, but with 18 sectors 
\layout Description

FMT_ACORN160: Acorn 40 track single sided 160k (used by ADFS 'S' format)
 
\layout Description

FMT_ACORN320: Acorn 80 track single sided 320k (used by ADFS 'M' format)
 
\layout Description

FMT_ACORN640: Acorn 80 track double sided 640k (used by ADFS 'L' format)
 
\layout Description

FMT_ACORN800: Acorn 80 track double sided 800k (used by ADFS 'D' and 'E')
 
\layout Description

FMT_ACORN1600: Acorn 80 track high density 1600k (used by ADFS 'F' format)
 
\layout Description

FMT_BBC100 BBC micro 40 track single sided 100k (using FM encoding) 
\layout Description

FMT_BBC200 BBC micro 80 track single sided 200k (using FM encoding)
\layout Description

FMT_MBEE400 Microbee 40 track double sided 400k
\layout Description

FMT_MGT800 MGT 80 track double sided 800k (used by MGT +D and Sam Coupé).
\layout Standard

If the 
\begin_inset Quotes eld
\end_inset 

fname
\begin_inset Quotes erd
\end_inset 

 is not NULL, it will be pointed at a short name for the format (suitable
 for use as a program option; see 
\family typewriter 
tools/dskform.c
\family default 
).
 
\layout Standard

If the 
\begin_inset Quotes eld
\end_inset 

fdesc
\begin_inset Quotes erd
\end_inset 

 is not NULL, it will be pointed at a description string for the format.
 With these two, it's possible to enumerate geometries supported by the
 library without keeping a separate list in your program - see 
\family typewriter 
tools/formnames.c
\family default 
 for example code that does this.
\layout Standard

If additional formats have been specified in the libdskrc file (section
 
\begin_inset LatexCommand \ref{sub:libdskrc-format}

\end_inset 

), they will be returned by this function, using format numbers starting
 at the last builtin format plus 1.
\layout Subsection

dsk_*_forcehead: Override disc head
\layout LyX-Code

dsk_err_t dsk_set_forcehead(DSK_PDRIVER self, int force) 
\layout LyX-Code

dsk_err_t dsk_get_forcehead(DSK_PDRIVER self, int *force)
\layout Standard

(This function is deprecated; it is equivalent to dsk_set_option() / dsk_get_opt
ion() with 
\begin_inset Quotes eld
\end_inset 

HEAD
\begin_inset Quotes erd
\end_inset 

 as the option name).
\layout Standard

Forces the driver to ignore the head number passed to it and always use
 either side 0 or side 1 of the disc.
 This is used to read discs recorded on PCW / CPC / Spectrum+3 add-on 3.5"
 drives.
 Instead of the system software being programmed to use both sides of the
 disc, a switch on the drive was used to set which side was being used.
 Thus discs would end up with both sides saying they were head 0.
\layout Standard

Anyway, when using dsk_set_forcehead, pass: 
\layout Description

-1: Normal - the head passed as a parameter to other calls is used.
 
\layout Description

0: Always use side 0.
 
\layout Description

1: Always use side 1.
\layout Subsection

dsk_*_option: Set/get driver option
\layout LyX-Code

dsk_err_t dsk_set_option(DSK_PDRIVER self, const char *name, int value)
\layout LyX-Code

dsk_err_t dsk_get_option(DSK_PDRIVER self, const char *name, int *value)
\layout Standard

Sets or gets a driver-specific numeric option.
\layout Standard

The 
\begin_inset Quotes eld
\end_inset 

name
\begin_inset Quotes erd
\end_inset 

 field is the option name.
 If the selected driver does not support the appropriate option, then the
 error DSK_ERR_BADOPT will be returned.
 If the option is valid but the value requested is not, DSK_ERR_BADVAL will
 be returned.
\layout Standard

The following driver options are supported by the Linux and NTWDM floppy
 drivers:
\layout Description

HEAD Force the drive always to use one or other side of the disc, ignoring
 the disc geometry.
 Valid values are 0 or 1 to force one or other side of the disc, -1 to allow
 either.
\layout Description

DOUBLESTEP To support a 48tpi disc in a 96tpi drive, double all cylinder
 numbers.
 Valid values are 1 (enable) or 0 (disable).
\layout Description

ST0\SpecialChar ~
/\SpecialChar ~
ST1\SpecialChar ~
/\SpecialChar ~
ST2\SpecialChar ~
/\SpecialChar ~
ST3 These are the values of the floppy controller's 4 status
 registers returned by the last operation.
 They cannot be changed, only read.
\layout Standard

The 'remote' driver supports the following option (plus any options that
 the remote driver supports):
\layout Description

REMOTE:TESTING This disables an optimisation in the remote driver, so that
 it sends method calls to the remote server even if it has been asked not
 to.
 The purpose of this is to ensure that all calls to the remote driver result
 in RPC packets being sent.
\layout Subsection

dsk_option_enum: Get list of driver options
\layout LyX-Code

dsk_err_t dsk_option_enum(DSK_PDRIVER self, int idx, char **optname)
\layout Standard

If 
\begin_inset Quotes eld
\end_inset 

idx
\begin_inset Quotes erd
\end_inset 

 is in the range 0 -> number of driver options, (*optname) is set to the
 name of the appropriate driver option.
 If not, (*optname) is set to NULL.
\layout Subsection

dsk_*_comment: Set comment for disc image
\layout LyX-Code

dsk_err_t dsk_set_comment(DSK_PDRIVER self, const char *comment) 
\layout LyX-Code

dsk_err_t dsk_get_comment(DSK_PDRIVER self, char **comment)
\layout Standard

Used to get or set the comment (if any) for the current disc.
 Comments are only supported by the ApriDisk format; you can set a comment
 for other file types but it will not be saved.
 The pointer passed or returned may be NULL (meaning 
\begin_inset Quotes eld
\end_inset 

No comment
\begin_inset Quotes erd
\end_inset 

).
\layout Subsection

dsk_type_enum 
\layout LyX-Code

dsk_err_t dsk_type_enum(int index, char **drvname)
\layout Standard

If 
\begin_inset Quotes eld
\end_inset 

index
\begin_inset Quotes erd
\end_inset 

 is in the range 0 -> number of LibDsk drivers, (
\family typewriter 
*drvname
\family default 
) is set to the short name for that driver (eg: 
\begin_inset Quotes eld
\end_inset 

myz80
\begin_inset Quotes erd
\end_inset 

 or 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

).
 If not, (*drvname) is set to 
\family typewriter 
NULL
\family default 
.
\layout Subsection

dsk_comp_enum 
\layout LyX-Code

dsk_err_t dsk_comp_enum(int index, char **compname)
\layout Standard

As 
\family typewriter 
dsk_type_enum()
\family default 
, but lists supported compression schemes.
\layout Subsection

dsk_drvname, dsk_drvdesc 
\layout LyX-Code

const char *dsk_drvname(DSK_PDRIVER self) 
\layout LyX-Code

const char *dsk_drvdesc(DSK_PDRIVER self)
\layout Standard

Returns the driver name (eg: 
\begin_inset Quotes eld
\end_inset 

myz80
\begin_inset Quotes erd
\end_inset 

) or description (eg 
\begin_inset Quotes eld
\end_inset 

MYZ80 hard drive driver
\begin_inset Quotes erd
\end_inset 

) for an open disc image.
\layout Subsection

dsk_compname, dsk_compdesc 
\layout LyX-Code

const char *dsk_compname(DSK_PDRIVER self); 
\layout LyX-Code

const char *dsk_compdesc(DSK_PDRIVER self);
\layout Standard

Returns the compression system name (eg: 
\begin_inset Quotes eld
\end_inset 

gz
\begin_inset Quotes erd
\end_inset 

; NULL if the disc image isn't compressed) or description (eg: 
\begin_inset Quotes eld
\end_inset 

GZip compressed
\begin_inset Quotes erd
\end_inset 

) for an open disc image.
\layout Subsection

dg_ps2ls, dg_ls2ps, dg_pt2lt, dg_lt2pt 
\layout Standard

Convert between logical sectors and physical cylinder/head/sector addresses.
 Normally these functions are called internally and you don't need to use
 them.
\layout LyX-Code

dsk_err_t dg_ps2ls(const DSK_GEOMETRY *self, dsk_pcyl_t cyl, dsk_phead_t
 head, dsk_psect_t sec, dsk_lsect_t *logical)
\layout Standard

Converts physical C/H/S to logical sector.
\layout LyX-Code

dsk_err_t dg_ls2ps(const DSK_GEOMETRY *self, dsk_lsect_t logical, dsk_pcyl_t
 *cyl, dsk_phead_t *head, dsk_psect_t *sec)
\layout Standard

Converts logical sector to physical C/H/S.
\layout LyX-Code

dsk_err_t dg_pt2lt(const DSK_GEOMETRY *self, dsk_pcyl_t cyl, dsk_phead_t
 head, dsk_ltrack_t *logical)
\layout Standard

Converts physical C/H to logical track.
\layout LyX-Code

dsk_err_t dg_lt2pt(const DSK_GEOMETRY *self, dsk_ltrack_t logical, dsk_pcyl_t
 *cyl, dsk_phead_t *head)
\layout Standard

Converts logical track to physical C/H.
\layout Subsection

dsk_strerror: Convert error code to string
\layout LyX-Code

char *dsk_strerror(dsk_err_t err)
\layout Standard

Converts an error code returned by one of the other LibDsk functions into
 a printable string.
\layout Subsection

dsk_reportfunc_set / dsk_reportfunc_get
\layout LyX-Code

void dsk_reportfunc_set(DSK_REPORTFUNC report, DSK_REPORTEND repend);
\layout LyX-Code

void dsk_reportfunc_get(DSK_REPORTFUNC *report, DSK_REPORTEND *repend);
\layout Standard

Used to set callbacks from LibDsk to your own code, for LibDsk to display
 messages during processing that may take time.
 The code could be used to set the text on the status line of your program
 window, for example.
\layout LyX-Code

typedef void (*DSK_REPORTFUNC)(const char *message); 
\layout LyX-Code

typedef void (*DSK_REPORTEND)(void);
\layout Standard

The first function you provide will be called when LibDsk wants to display
 a message (such as 
\begin_inset Quotes eld
\end_inset 

Decompressing...
\begin_inset Quotes erd
\end_inset 

).
 The second will be called when the processing has finished.
\layout Subsection

dsk_set_retry / dsk_get_retry
\layout LyX-Code

dsk_err_t dsk_set_retry(DSK_PDRIVER self, unsigned int count);
\layout LyX-Code

dsk_err_t dsk_get_retry(DSK_PDRIVER self, unsigned int *count);
\layout Standard

Sets the number of times that a failed read, write, check or format operation
 will be attempted.
 1 means 
\begin_inset Quotes eld
\end_inset 

only try once, do not retry
\begin_inset Quotes erd
\end_inset 

.
 
\layout Subsection

dsk_get_psh 
\layout LyX-Code

unsigned char dsk_get_psh(size_t sector_size)
\layout Standard

Converts a sector size into the sector shift used by the uPD765A controller
 (eg: 128 -> 0, 256 -> 1, 512 -> 2 etc.) You should not need to use this.
 The reverse operation is: sectorsize = (128 << psh).
\layout Subsection

Structure: DSK_FORMAT
\layout Standard

This structure is used to represent a sector header.
 It has four members:
\layout Description

fmt_cylinder: Cylinder number.
 
\layout Description

fmt_head: Head number.
 
\layout Description

fmt_sector: Sector number.
 
\layout Description

fmt_secsize: Sector size in bytes.
\layout Subsection

LibDsk errors 
\layout Description

DSK_ERR_OK: No error.
\layout Description

DSK_ERR_BADPTR: A null or otherwise invalid pointer was passed to a LibDsk
 routine.
 
\layout Description

DSK_ERR_DIVZERO: Division by zero: For example, a DSK_GEOMETRY is set to
 have zero sectors.
 
\layout Description

DSK_ERR_BADPARM: Bad parameter (eg: if a DSK_GEOMETRY is set up with 
\family typewriter 
dg_cylinders
\family default 
 = 40, trying to convert a sector in cylinder 65 to a logical sector will
 give this error).
 
\layout Description

DSK_ERR_NODRVR: Requested driver not found in 
\family typewriter 
dsk_open()
\family default 
 / 
\family typewriter 
dsk_creat()
\family default 
.
 
\layout Description

DSK_ERR_NOTME: Disc image could not be opened by requested driver.
\layout Description

DSK_ERR_SYSERR: System call failed.
 errno holds the reason.
 
\layout Description

DSK_ERR_NOMEM: 
\family typewriter 
malloc()
\family default 
 failed to allocate memory.
 
\layout Description

DSK_ERR_NOTIMPL: Function is not implemented (eg, this driver doesn't support
 
\family typewriter 
dsk_xread()
\family default 
).
 
\layout Description

DSK_ERR_MISMATCH: In 
\family typewriter 
dsk_lcheck() 
\family default 
/ 
\family typewriter 
dsk_pcheck()
\family default 
, sectors didn't match.
 
\layout Description

DSK_ERR_NOTRDY: Drive is not ready.
 
\layout Description

DSK_ERR_RDONLY: Disc is read-only.
 
\layout Description

DSK_ERR_SEEKFAIL: Seek fail.
 
\layout Description

DSK_ERR_DATAERR: Data error.
 
\layout Description

DSK_ERR_NODATA: Sector ID found, but not sector data.
 
\layout Description

DSK_ERR_NOADDR: Sector not found at all.
 
\layout Description

DSK_ERR_BADFMT: Not a valid format.
 
\layout Description

DSK_ERR_CHANGED: Disc has been changed unexpectedly.
 
\layout Description

DSK_ERR_ECHECK: Equipment check.
 
\layout Description

DSK_ERR_OVERRUN: Overrun.
 
\layout Description

DSK_ERR_ACCESS: Access denied.
 
\layout Description

DSK_ERR_CTRLR: Controller failed.
 
\layout Description

DSK_ERR_COMPRESS: Compressed file is corrupt.
 
\layout Description

DSK_ERR_RPC: Error in remote procedure call.
\layout Description

DSK_ERR_BADOPT: Driver does not support the requested option.
\layout Description

DSK_ERR_BADVAL: Driver does support the requested option, but the passed
 value is out of range.
\layout Description

DSK_ERR_UNKNOWN: Unknown error
\layout Subsection

Miscellaneous 
\layout Standard

LIBDSK_VERSION is a macro, defined as a string containing the library version
 - eg 
\begin_inset Quotes eld
\end_inset 

1.0.0
\begin_inset Quotes erd
\end_inset 


\layout Section

Initialisation files
\layout Standard

In addition to its built-in library of formats, LibDsk can also load formats
 from one or two external files - a systemwide file (libdskrc) and a user-specif
ic file (.libdskrc).
 The rules for how these files are found differ from platform to platform.
\layout Subsection


\begin_inset LatexCommand \label{sub:libdskrc-format}

\end_inset 

libdskrc format
\layout Standard

The file format is similar to a Windows .INI file.
 Each format is described in a section, which starts with the format name
 in square brackets (format names may not start with a hyphen).
 After the format name, there are a number of lines of the form variable=value.
\layout Standard

Anything after a semicolon or hash character is treated as a comment and
 ignored.
 Blank lines are also ignored.
 
\layout Standard

For each geometry, the entries listed below can be present.
 If not all the values are present, LibDsk will use default values from
 its "pcw180" format.
 As you can see, they correspond to members of the DSK_GEOMETRY structure.
\layout Description

description=DESC The description of the format as shown by (for example)
 dskform --help.
 
\layout Description

sides=TREATMENT How a double-sided disk is handled.
 This can either be 
\emph on 
alt 
\emph default 
(sides alternate -- used by most PC-hosted operating systems), 
\emph on 
outback
\emph default 
 (use side 0 tracks 0-79, then side 1 tracks 79-0 -- used by 144FEAT CP/M
 disks), or 
\emph on 
outout
\emph default 
 (use side 0 tracks 0-79, then side 1 tracks 0-79 -- used by some Acorn
 formats).
 If the disk is single-sided, this parameter can be omitted.
\layout Description

cylinders=COUNT Sets the number of cylinders (usually 40 or 80).
 
\layout Description

heads=COUNT Sets the number of heads (usually 1 or 2 for single- or double-
 sided).
\layout Description

sectors=COUNT Sets the number of sectors per track.
 
\layout Description

secbase=NUMBER Sets the first sector number on a track.
 Usually 1; some Acorn formats use 0.
 
\layout Description

secsize=COUNT Sets the size of a sector in bytes.
 This should be a power of 2.
\layout Description

datarate=VALUE Sets the rate at which the disk should be accessed.
 This is one of 
\emph on 
HD, DD, SD or ED.
\layout Description

rwgap=VALUE Sets the read/write gap.
\layout Description

fmtgap=VALUE Sets the format gap.
\layout Description

fm=Y\SpecialChar ~
or\SpecialChar ~
N Sets the recording mode - Y for FM, N for MFM.
\layout Description

multitrack=Y\SpecialChar ~
or\SpecialChar ~
N Sets multitrack mode.
\layout Description

skipdeleted=Y\SpecialChar ~
or\SpecialChar ~
N Sets whether to skip deleted data.
\layout Subsubsection

libdskrc example
\layout LyX-Code

; This is FMT_800K as a libdskrc entry
\layout LyX-Code

[xcf2dd] 
\layout LyX-Code

Description = 800k XCF2DD format 
\layout LyX-Code

Sides = Alt 
\layout LyX-Code

Cylinders = 80    
\layout LyX-Code

Heads = 2 
\layout LyX-Code

Sectors = 10 
\layout LyX-Code

SecBase = 1 
\layout LyX-Code

SecSize = 512 
\layout LyX-Code

DataRate = SD 
\layout LyX-Code

RWGap = 12 
\layout LyX-Code

FmtGap = 23
\layout LyX-Code

\layout LyX-Code

[xcf2]
\layout LyX-Code

Description = 200k XCF2 format
\layout LyX-Code

Cylinders = 40
\layout Standard

...
 etc.
\layout Subsection

Locating libdskrc
\layout Subsubsection


\noun on 
Unix
\layout Standard

The systemwide file is located at ${datadir}/LibDsk/libdskrc.
 The ${datadir} is usually /usr/local/share; you can change it with the
 --datadir or --prefix arguments to the configure script.
 
\layout Standard

The user-specific file is $(HOME)/.libdskrc.
 
\layout Subsubsection

Win32
\layout Standard

The systemwide file is in the path specified at
\layout LyX-Code

HKEY_LOCAL_MACHINE
\backslash 
Software
\backslash 
jce@seasip
\backslash 
LibDsk
\backslash 
ShareDir
\layout Standard

If this registry key is not found, LibDsk finds the path of the program
 that called it (using GetModuleFileName()), and then uses 
\begin_inset Quotes eld
\end_inset 

/...program path.../share/libdskrc
\begin_inset Quotes erd
\end_inset 

.
\layout Standard

The user-specific file is in the path specified at
\layout LyX-Code

HKEY_CURRENT_USER
\backslash 
Software
\backslash 
jce@seasip
\backslash 
LibDsk
\backslash 
HomeDir
\layout Standard

If this registry key is not present, the user's 
\begin_inset Quotes eld
\end_inset 

My Documents
\begin_inset Quotes erd
\end_inset 

 directory is used.
 Either way, the file is called .libdskrc.
\layout Subsubsection

Win16
\layout Standard

The systemwide file is found from the location of the calling program using
 GetModuleFileName().
 There is no user-specific file.
\layout Subsubsection

DOS
\layout Standard

The systemwide file is only searched for if the LIBDSK environment variable
 is set; if it is set, it is assumed to be the name of the directory containing
 libdskrc.
 There is no user-specific file.
\layout Section


\begin_inset LatexCommand \label{sec:rcpmfs}

\end_inset 

Reverse CP/M-FS (rcpmfs) backend
\layout Standard

The rcpmfs backend is designed to present a host directory as a read/write
 CP/M disk image.
 This has a number of uses:
\layout Itemize

You could construct a CP/M disk image using dsktrans 
\emph on 
directory filename
\emph default 
 .
\layout Itemize

Conversely, you could extract the files from a CP/M disk image using dsktrans
 
\emph on 
filename directory
\emph default 
.
\layout Itemize

It is possible for a CP/M emulator running a genuine copy of CP/M to use
 LibDsk to access files on the host system, without altering the BDOS or
 installing additional drivers.
 
\layout Standard

rcpmfs does not work with systems that only support 
\begin_inset Quotes eld
\end_inset 

8.3
\begin_inset Quotes erd
\end_inset 

 format filenames; it also needs a system call that can set the size of
 a file (such as truncate() under 
\noun on 
Unix
\noun default 
).
 It therefore remains unimplemented in the DOS and Win16 versions of the
 library.
 
\layout Subsection

In Use
\layout Standard

To use an rcpmfs directory in LibDsk, pass a directory name instead of a
 filename.
 Files in the directory which match CP/M naming conventions (8.3 filenames)
 will appear in the emulated disk image; if there are more files than will
 fit in the emulated disk, LibDsk will stop when it reaches one that doesn't
 fit.
 Under Windows, the 'short filename' is used, so files with names not matching
 CP/M conventions may also be mapped with names like README~1.HTM.
 
\layout Standard

CP/M has 16 user areas (some variants support 32; rcpmfs does not), and
 files with the same name can exist in each area.
 rcpmfs represents nonzero user areas by prepending 
\begin_inset Quotes eld
\end_inset 

nn..
\begin_inset Quotes erd
\end_inset 

 to the filename; so if a CP/M program created a file called EXAMPLE.DAT
 in user 4, this would be saved as 
\begin_inset Quotes eld
\end_inset 

04..example.dat
\begin_inset Quotes erd
\end_inset 

 in the underlying directory.
 The double dot ensures that the resulting filename is not a valid CP/M
 name, and therefore won't conflict with any file in user 0.
\layout Standard

rcpmfs can behave as a CP/M 2 or CP/M 3 filesystem.
 If the latter, it constructs a disc label (based on the name of the directory)
 and turns on date/time stamping.
 Update and access stamps are used, because they map nicely to the utime()
 system call.
\layout Subsection

rcpmfs initialisation file
\layout Standard

For a directory to be usable by rcpmfs, it should contain a file called
 .libdsk.ini describing the format to use.
 This file is in INI format, similar to libdskrc (section 
\begin_inset LatexCommand \ref{sub:libdskrc-format}

\end_inset 

).
 It must contain only one section: [RCPMFS].
 Within that section, the following variables may be present:
\layout Description

BlockSize Size of a CP/M data block.
 Must be a power of 2, and at least 1024.
 If there are more than 255 blocks in the CP/M filesystem, this must be
 at least 2048.
\layout Description

DirBlocks Number of blocks containing the CP/M directory.
\layout Description

TotalBlocks Total number of data and directory blocks.
\layout Description

SysTracks Number of system tracks.
 These will be stored in a file called .libdsk.boot.
 
\layout Description

Version CP/M version that will be accessing the filesystem - either 2 or
 3.
 Setting it to 2 should disable time stamps and disk labels.
\layout Description

Format Name of one of the LibDsk built-in or user-supplied formats, giving
 the geometry that the simulated disk will have.
 Alternatively, you can specify the format manually, using the same variable
 names as in libdskrc.
\layout Standard

If there is no .libdsk.ini file present, LibDsk will assume BlockSize=1024,
 DirBlocks=2, TotalBlocks=175,SysTracks=1, Version=3, Format=pcw180.
\layout Subsection

Bugs
\layout Standard

rcpmfs is new and untried code.
 The following are known bugs or missing features:
\layout Itemize

So far, rcpmfs has only been tested under the dsktrans pattern of usage
 (which writes the directory and then the file space), and with fairly simple
 operations in a CP/M emulator.
 It is not known how well it holds up under heavy use as a live CP/M filesystem.
\layout Itemize

The CP/M attributes F1-F4, passwords and permissions are not mapped.
 The SYS and ARC attributes are only mapped in the Win32 version.
\layout Itemize

Formatting (or reformatting) an rcpmfs directory writes out a new .libdsk.ini
 containing the geometry used to do the format.
 However, since DSK_GEOMETRY doesn't contain the CP/M filesystem parameters
 (block size, block count, etc.) these will be the ones previously used in
 that directory, and quite possibly completely wrong.
 It's a much better idea to 'format' the directory using means other than
 LibDsk.
\layout Section


\begin_inset LatexCommand \label{sec:copyqm}

\end_inset 

The CopyQM file format
\layout Subsection

Introduction
\layout Standard

This section describes the file format of files created by CopyQM.
 A lot of the information has been extracted by looking at hex-dumps of
 the files, so there might be some errors in the description.
 
\layout Subsection

Header
\layout Standard

The CopyQM files consist of a header, an optional comment (if indicated
 by the header) followed by the tracks of the image encoded with a run length
 encoding scheme.
 The header is 133 bytes long, see table.
 It always starts with {0x43, 0x51, 0x14 }, which can be used for auto-detection
 of the image.
 All numbers have little-endian byte ordering.
 When all bytes in the header are added together in a byte, the result should
 be zero.
\layout Standard


\begin_inset  Tabular
<lyxtabular version="3" rows="22" columns="3">
<features>
<column alignment="center" valignment="top" leftline="true" width="0">
<column alignment="center" valignment="top" leftline="true" width="0">
<column alignment="left" valignment="top" leftline="true" rightline="true" width="0">
<row topline="true" bottomline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Offset
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Size
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Comment
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x00
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Always 0x43 ('C')
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x01
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Always 0x51 ('Q')
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x02
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Always 0x14
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x03
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

2
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Sector size
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x0b
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

2
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Total number of sectors.
 (DOS)
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x10
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

2
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Number of sectors per track
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x12
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

2?
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Number of heads
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x1c
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

60?
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Description (e.g.
 
\begin_inset Quotes eld
\end_inset 

0K Double-Sided
\begin_inset Quotes erd
\end_inset 

)
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x58
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Type of image.
 0=blind, 1=DOS, 2=HFS
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x59
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Density.
 0=DD, 1=HD, 2=ED
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x5a
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Number of tracks used on image
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x5b
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Total number of tracks for image
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x5c
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

4
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

CRC for the used, unpacked tracks
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x60
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

11
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Volume label (DOS/HFS)
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x6b
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

2
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Creation time
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x6d
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

2
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Creation date
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x6f
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

2
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Length of image comment
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x71
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Number of first sector - 1
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x74
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Interleave.
 (0 for older versions of CopyQM)
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x75
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Skew.
 Normally 0.
 Negative number for alt.
 sides
\end_inset 
</cell>
</row>
<row topline="true" bottomline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

0x84
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

1
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Header checksum byte
\end_inset 
</cell>
</row>
</lyxtabular>

\end_inset 


\layout Subsection

CRC
\layout Standard

The CRC is calculated for the unpacked data for all tracks that are used
 in the image.
 The CRC value is initialized with 0 and then updated using the CRC 32 polynomia
l 0x104C11DB7, bit reverse algorithm.
 Due to a feature in CopyQM (8 bit register as an index into a 1024 byte
 table) all bytes must have their top two bits removed before added to the
 CRC.
\layout Subsection

Image comment
\layout Standard

The image comment follows the header.
 It has a variable size found in the header.
 The image comment can contain 
\backslash 
0-bytes.
\layout Subsection

Image data
\layout Standard

The image data is run length encoded.
 Each run is preceded by a 16-bit length.
 If the length is negative, the byte after the length is repeated 
\series bold 
-length
\series default 
 times.
 If the length is positive, it is followed by 
\series bold 
length 
\series default 
bytes of unencoded data.
 It seems like a new run of repeating or differing data is always started
 at each new track.
 Older versions of CopyQM always alternates between runs of differing data
 and repeating data, even if the length of one of them is zero.
\layout Section


\begin_inset LatexCommand \label{ldwindows}

\end_inset 

LibDsk under Windows
\layout Standard

This section mainly deals with the subject of direct floppy drive access.
 Other aspects of LibDsk remain relatively consistent across Windows versions.
\layout Standard

As with so many other aspects of Windows, direct access to the floppy drive
 is a case of 
\begin_inset Quotes eld
\end_inset 

write once - debug everywhere
\begin_inset Quotes erd
\end_inset 


\begin_inset Foot
collapsed true

\layout Standard

Originally said by Microsoft with respect to Java.
 Pot.
 Kettle.
 Black.
\end_inset 

.
 Not only does support vary across different systems, it varies depending
 on whether LibDsk was compiled with a 16-bit compiler or a 32-bit one.
 This table shows the different possibilities and the resulting behaviour:
\layout Standard


\begin_inset  Tabular
<lyxtabular version="3" rows="5" columns="3">
<features>
<column alignment="center" valignment="top" leftline="true" width="0pt">
<column alignment="center" valignment="top" leftline="true" width="0pt">
<column alignment="center" valignment="top" leftline="true" rightline="true" width="0pt">
<row topline="true" bottomline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Windows Version
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Win16 Subsystem
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Win32 Subsystem
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

3.x
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Fairly good
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

n/a
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

4.x (95, 98 and ME)
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Good but less stable
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Limited
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

NT, 2000, XP
\end_inset 
</cell>
<cell multicolumn="1" alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Very limited
\end_inset 
</cell>
<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

\end_inset 
</cell>
</row>
<row topline="true" bottomline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

2000, XP + ntwdm driver
\end_inset 
</cell>
<cell multicolumn="1" alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Good
\end_inset 
</cell>
<cell multicolumn="2" alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

\end_inset 
</cell>
</row>
</lyxtabular>

\end_inset 


\layout Subsection

Windows 3.x
\layout Standard

Only the 16-bit build of LibDsk will run.
 The floppy support in Win16 is pretty much the same as in DOS; there is
 support for discs with arbitrary numbers of tracks and sectors, and arbitrary
 sector sizes.
 This means that LibDsk can, for example, read Acorn ADFS floppies.
 
\layout Subsection

Windows 4.x (95, 98 and ME)
\layout Standard

Both the 16-bit and 32-bit versions of LibDsk will run.
 The 16-bit version is more capable, but less stable; it can read Acorn
 ADFS floppies, which the 32-bit version cannot.
 Unfortunately, 32-bit programs can't link to the 16-bit version of LibDsk
\begin_inset Foot
collapsed true

\layout Standard

And no, the Generic Thunk isn't good enough.
 I've tried it.
\end_inset 

, but there is a workaround (described below) involving the use of LDSERVER.
\layout Subsection

Windows NT (NT 3.x, NT 4.x, 2000, XP) without ntwdm driver
\layout Standard

The floppy drive can only read/write formats which are supported by the
 floppy driver.
 This is the case using either version of LibDsk.
\layout Subsection

Windows 2000 and XP with ntwdm driver
\layout Standard

Simon Owen's enhancement to the Windows 2000 floppy driver can be downloaded
 from <http://simonowen.com/fdrawcmd/>.
 Once it is installed, LibDsk (using its 'ntwdm' driver rather than 'floppy')
 has pretty much carte blanche regarding floppy formats, and can access
 discs in many formats including Acorn ADFS.
\layout Subsection

General comments on programming floppy access for Windows
\layout Standard

LibDsk has four independent drivers for accessing floppies under Windows.
 They are:
\layout Subsubsection

The Win16 driver.
 
\layout Standard

This uses INT 0x13 to do the reads and writes, just as in MSDOS.
 Again as in MSDOS, there is a diskette parameter table pointed to by INT
 0x1E.
 This table seems not to be documented, which is perhaps why the Win16 subsystem
 in Windows 2000/XP doesn't implement it.
 You can, fortunately, tell if this is the case; if the first two bytes
 are both 0xC4, then what you have is a Windows 2000 trap rather than a
 diskette parameter table.
 
\layout Subsubsection

The Win32c driver.
\layout Standard

This driver uses VWIN32 services to make INT 0x13-style calls under Windows9x.
 However, there is no VWIN32 call to change the diskette parameter table,
 which is why the Win16 driver can do things the Win32 drivers can't.
 It isn't possible to get round this by thunking to a 16-bit DLL either;
 the INT 0x1E vector is zero for 16-bit DLLs in 32-bit processes.
\layout Subsubsection

The Win32 driver.
\layout Standard

Windows NT gets close (but not close enough) to the UNIX idea that everything
 is a file.
 So while in theory it would be enough to use the normal 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 driver on 
\begin_inset Quotes eld
\end_inset 


\family typewriter 

\backslash 

\backslash 
.
\backslash 
A:
\family default 

\begin_inset Quotes eld
\end_inset 

 , in practice there are a number of nasty subtleties relating to such things
 as memory alignment and file locking.
\layout Subsubsection

The ntwdm driver.
\layout Standard

This driver is a wrapper around fdrawcmd.sys, which allows commands to be
 issued to the floppy controller.
 
\layout Subsubsection

Other floppy APIs
\layout Standard

Sydex produce a replacement floppy driver for 32-bit versions of Windows
 (SydexFDD) which is not supported by LibDsk.
 
\layout Subsection


\begin_inset LatexCommand \label{ldserver}

\end_inset 

LDSERVER
\layout Standard

LDSERVER is a program that makes the 16-bit LibDsk DLL available to 32-bit
 programs.
 It does this by creating a mailslot (
\begin_inset Quotes eld
\end_inset 


\family typewriter 

\backslash 

\backslash 
.
\backslash 
mailslot
\backslash 
LibDsk16
\family default 

\begin_inset Quotes erd
\end_inset 

) and listening for messages.
 Each message corresponds to a LibDsk call.
\layout Standard

The 32-bit LibDsk library checks for this mailslot and, if it finds it,
 uses it in preference to its own floppy support.
\layout Subsubsection

Compiling LDSERVER
\layout Standard

A compiled version of LDSERVER is not supplied.
 You will need to build it yourself from the files in the rpcserv directory;
 projects are provided for Microsoft Visual C++ 1.5 and Borland C++ 5.0.
\layout Standard

LDSERVER calls functions in NETAPI.DLL.
 If your compiler doesn't include an import library for this DLL, you will
 have to generate it using the IMPLIB tool - eg:
\layout LyX-Code

IMPLIB NETAPI.LIB NETAPI.DLL
\layout Standard

or the equivalent utility for your compiler.
\layout Subsubsection

Using LDSERVER
\layout Standard

Just run LDSERVER.EXE, and then use a 32-bit LibDsk program.
 The server window shows a reference count (0 if it is idle, nonzero if
 LibDsk programs are using it) and the status should change to 
\begin_inset Quotes eld
\end_inset 

Active
\begin_inset Quotes erd
\end_inset 

 when it is performing disc access.
\layout Standard

LDSERVER does not shut down automatically.
 
\layout Subsubsection

Important Security Warning
\layout Standard

LDSERVER is a 16-bit program, written using APIs intended for use on a local
 area network.
 These APIs have no security support.
 It will happily obey commands sent from anywhere on your network.
 If your computer is connected to the Internet, it will obey commands sent
 to it over the Internet.
 A malicious attacker could use LDSERVER to overwrite important system files
 or read confidential documents.
\layout Standard

If you have a firewall, then make sure that the NetBIOS ports 137, 138 and
 139 are blocked.
 If you don't have a firewall, 
\series bold 
\emph on 
do not run LDSERVER while your computer is connected to the Internet!
\layout Subsection

LibDsk and COM
\layout Standard

If you are building the 32-bit version of LibDsk with Visual C++ 6.0, you
 can also build the accompanying 'atlibdsk' project, which builds a version
 of LibDsk that exports its API through COM.
 This allows relatively easy use of LibDsk from languages that support COM
 binding, such as Visual BASIC or .NET languages.
\layout Subsubsection

General points
\layout Standard

Where LibDsk functions return a dsk_err_t, ATLIBDSK returns a COM HRESULT.
 This will be S_OK for success, a general COM error (such as E_POINTER or
 E_INVALIDARG), or a FACILITY_ITF error (0x8004xxxx).
 The low word of a FACILITY_ITF error is the LibDsk error code, converted
 to a positive number (eg: 0x8004000C is FACILITY_ITF error 12, so the LibDsk
 error is -12, DSK_ERR_SEEKFAIL).
\layout Standard

Sector buffers to be read/written must be passed as variants containing
 arrays of bytes.
 
\layout Standard

The arrays of DSK_FORMAT structures passed to dsk_lform() and dsk_pform()
 are replaced by variants containing arrays of bytes - four bytes per sector
 to format.
 The last byte is the physical sector shift (0 for 128, 1 for 256 etc.)
\layout Standard

ATLIBDSK exports four object classes: 
\layout Subsubsection

Library
\layout Standard

This contains LibDsk functions not associated with a particular disk image.
 Its methods are:
\layout Standard


\begin_inset  Tabular
<lyxtabular version="3" rows="13" columns="3">
<features>
<column alignment="center" valignment="top" leftline="true" width="0">
<column alignment="center" valignment="top" leftline="true" width="0">
<column alignment="center" valignment="top" leftline="true" rightline="true" width="0">
<row topline="true" bottomline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Method
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

Equivalent LibDsk call
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Comments
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

open 
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dsk_open
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Instantiates a new Disk object.
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

create
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dsk_creat
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Instantiates a new Disk object.
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

get_psh
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dsk_get_psh
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dosgeom
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dg_dosgeom
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Instantiates a new Geometry object.
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

cpm86geom
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dg_cpm86geom
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Instantiates a new Geometry object.
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

pcwgeom
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dg_pcwgeom
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Instantiates a new Geometry object.
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

aprigeom
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dg_aprigeom
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Instantiates a new Geometry object.
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

stdformat
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dg_stdformat
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Instantiates a new Geometry object.
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

stdformat_count
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Returns the number of formats supported by stdformat
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

type_enum
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dsk_type_enum
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Returns TRUE if the passed index is valid, else FALSE.
\end_inset 
</cell>
</row>
<row topline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

comp_enum
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dsk_comp_enum
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

Returns TRUE if the passed index is valid, else FALSE.
\end_inset 
</cell>
</row>
<row topline="true" bottomline="true">
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

reporter
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text

\layout Standard

dsk_reportfunc_{set,get}
\end_inset 
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text

\layout Standard

This is a property of type IReporter
\end_inset 
</cell>
</row>
</lyxtabular>

\end_inset 


\layout Subsubsection

Geometry
\layout Standard

This corresponds to the DSK_GEOMETRY structure.
 The following properties correspond to the structure members:
\layout Itemize

sidedness
\layout Itemize

cylinders
\layout Itemize

heads
\layout Itemize

sectors
\layout Itemize

secbase
\layout Itemize

datarate
\layout Itemize

secsize
\layout Itemize

rwgap
\layout Itemize

fmtgap
\layout Itemize

fm
\layout Itemize

nomulti
\layout Itemize

noskip
\layout Standard

There are also five functions.
 Four are for logical/physical sector conversions:
\layout Itemize

ls2ps
\layout Itemize

lt2pt
\layout Itemize

ps2ls
\layout Itemize

pt2lt
\layout Standard

and the last is stdformat(), which wraps dg_stdformat().
\layout Subsubsection

Disk
\layout Standard

The Disk object corresponds to a LibDsk DSK_PDRIVER value.
 You should not create one yourself (method calls will fail with E_POINTER)
 but call the 'create' or 'open' methods of the Library object.
\layout Standard

Functions included are:
\layout Itemize

get_geometry
\layout Itemize

close
\layout Itemize

drive_status
\layout Itemize

pread
\layout Itemize

lread
\layout Itemize

xread
\layout Itemize

pwrite
\layout Itemize

lwrite
\layout Itemize

xwrite
\layout Itemize

pcheck
\layout Itemize

lcheck
\layout Itemize

xcheck
\layout Itemize

pformat
\layout Itemize

lformat
\layout Itemize

apform
\layout Itemize

alform
\layout Itemize

ptread
\layout Itemize

ltread
\layout Itemize

xtread
\layout Itemize

psecid 
\layout Itemize

lsecid
\layout Itemize

lseek
\layout Itemize

pseek
\layout Itemize

option_enum
\layout Standard

all of which are pretty similar to their LibDsk namesakes.
 There are also the following properties:
\layout Itemize

comment 
\layout Itemize

option 
\layout Itemize

retries 
\layout Itemize

drvname 
\layout Itemize

drvdesc 
\layout Itemize

compname 
\layout Itemize

compdesc 
\layout Subsubsection

IReporter
\layout Standard

IReporter is used for the LibDsk message callback.
 It is an interface that should be implemented by an object in your program.
 Set the library's "reporter" property to your object; then its report()
 and endreport() methods will be called.
\layout Section

LibDsk RPC system
\layout Standard

The LibDsk RPC system is designed to make disc drives on remote computers
 transparently available to LibDsk applications.
 It operates on a client/server basis; LibDsk contains a driver (called
 'remote') that can act as a client, and it can be used to implement a server.
\layout Standard

The on-the-wire protocol is described in protocol.txt in the documentation
 directory.
\layout Subsection

The 'serial' driver
\layout Standard

This is designed for using LibDsk over a serial connection - say from a
 3.5
\begin_inset Quotes erd
\end_inset 

 computer to a 5.25
\begin_inset Quotes erd
\end_inset 

 computer.
 The filename specification to use at the client end is:
\layout LyX-Code

serial:
\emph on 
port
\emph default 
,
\emph on 
baud
\emph default 
,
\emph on 
remotename
\emph default 
{,
\emph on 
remotetype
\emph default 
{,
\emph on 
remotecompress
\emph default 
}}
\layout Standard

for example:
\layout LyX-Code

serial:/dev/ttyS0,9600+crtscts,A:
\layout Standard

The various parts of this filename specification are:
\layout Description

port The local serial port to use.
\begin_deeper 
\layout Itemize

Under Linux, this is the name of a serial port (eg /dev/ttyS0).
\layout Itemize

Under Windows, this is likewise the name of a serial port (eg COM1:).
\layout Itemize

Under DOS, you need to have a FOSSIL serial port driver loaded; LibDsk was
 tested using ADF <http://ftp.iis.com.br/pub/simtelnet/msdos/fossil/adf_150.zip>
 (or do a web search for adf_150.zip).
 The port is then the number assigned by the FOSSIL driver (normally 0).
 Note also that ADF uses a single fixed baud rate, so you should make sure
 that the rate on the command line matches the rate that was used when ADF
 was loaded.
\end_deeper 
\layout Description

baud The speed and handshaking options.
 LibDsk does not allow the number of bits, the parity or the count of stop
 bits to be changed; it insists on 8-bit communications with 1 stop bit
 and no parity.
 The speed is a number (300, 600, 1200 etc.) and the handshake option is
 
\begin_inset Quotes eld
\end_inset 

+crtscts
\begin_inset Quotes erd
\end_inset 

 (to use RTS/CTS handshaking) or 
\begin_inset Quotes eld
\end_inset 

-crtscts
\begin_inset Quotes erd
\end_inset 

 (not to).
 If neither handshake option is present, 
\begin_inset Quotes eld
\end_inset 

+crtscts
\begin_inset Quotes erd
\end_inset 

 is assumed.
\layout Description

remotename The name of the file or drive on the remote computer.
\layout Description

remotetype The type of the file/drive (
\begin_inset Quotes eld
\end_inset 

dsk
\begin_inset Quotes erd
\end_inset 

, 
\begin_inset Quotes eld
\end_inset 

floppy
\begin_inset Quotes erd
\end_inset 

 etc.).
 
\layout Description

remotecompress The compression to use on the remote computer.
 
\layout Subsubsection

Servers for the serial driver
\layout Standard

One of the sample utilities supplied with LibDsk is called serslave (serslave.exe
 under DOS / Windows).
 This is a server using the same serial protocol as above.
 
\layout Standard

Launch serslave with the command:
\layout LyX-Code

serslave 
\shape italic 
port,baud
\shape default 
 
\layout Standard

for example:
\layout LyX-Code

serslave COM1:,9600+crtscts
\layout Standard

or in DOS (again, a FOSSIL driver is required):
\layout LyX-Code

serslave 0,19200
\layout Standard

I have written a similar server for CP/M systems, called AUXD.
 This is a separate download from the LibDsk web page.
\layout Subsection

The 'fork' driver
\layout Standard

The 'fork' driver is used (on any system which supports the fork() system
 call) to send LibDsk requests to a local program using pipes.
 This driver was written for testing purposes, but may come in handy as
 a poor man's plugin system.
 The filename specification is: 
\layout LyX-Code

fork:
\emph on 
program
\emph default 
,
\emph on 
remotename
\emph default 
{,
\emph on 
remotetype
\emph default 
{,
\emph on 
remotecompress
\emph default 
}}
\layout Standard

for example:
\layout LyX-Code

fork:./dskslave,a.dqk,dsk,sq
\layout Standard

The various parts of this filename specification are:
\layout Description

program The name of the program to use; execlp() is used to launch it, so
 if no path is given the user's PATH will be searched.
 The program must take LibDsk calls from its standard input and send results
 to its standard output.
\layout Description

remotename The name of the file or drive.
\layout Description

remotetype The type of the file/drive (
\begin_inset Quotes eld
\end_inset 

dsk
\begin_inset Quotes erd
\end_inset 

, 
\begin_inset Quotes eld
\end_inset 

floppy
\begin_inset Quotes erd
\end_inset 

 etc.).
 
\layout Description

remotecompress The compression to use.
 
\layout Standard

An example of a server for this protocol is the example 'forkslave' program;
 this is a very simple wrapper around dsk_rpc_server() which reads RPC packets
 from its standard input and writes them to its standard output.
\layout Section

Writing new drivers
\layout Standard

The interface between LibDsk and its drivers is defined by the DRV_CLASS
 structure.
 To add a new driver, you create a new DRV_CLASS structure and add it to
 various files.
\layout Subsection

The driver header 
\layout Standard

Firstly, create a header for this driver, basing it on (for example) 
\family typewriter 
lib/drvposix.h
\family default 
.
 The first thing in the header (after the LGPL banner) is: 
\layout LyX-Code

typedef struct 
\layout LyX-Code

{ 
\layout LyX-Code

    DSK_DRIVER px_super; 
\layout LyX-Code

    FILE *px_fp; 
\layout LyX-Code

    int px_readonly;
\layout LyX-Code

    long px_filesize;
\layout LyX-Code

} POSIX_DSK_DRIVER;
\layout Standard

This is where you define any variables that your driver needs to store for
 each disc image.
 In the case of the 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 driver, this consists of a FILE pointer to access the underlying disc file,
 a 
\begin_inset Quotes eld
\end_inset 

readonly
\begin_inset Quotes erd
\end_inset 

 flag, and the current size of the drive image file.
 The first member of this structure must be of type DSK_DRIVER.
\layout Standard

The rest of this header consists of function prototypes, which I will come
 back to later.
\layout Subsection

The driver source file
\layout Standard

Secondly, create a .c file for your driver.
 Again, it's probably easiest to base this on lib/drvposix.c.
 At the start of this file, create a DRV_CLASS structure, such as:
\layout LyX-Code

DRV_CLASS dc_posix = 
\layout LyX-Code

{ 
\layout LyX-Code

    sizeof(POSIX_DSK_DRIVER), 
\layout LyX-Code

    "raw", 
\layout LyX-Code

    "Raw file driver", 
\layout LyX-Code

    posix_open, 
\layout LyX-Code

    posix_creat, 
\layout LyX-Code

    posix_close 
\layout LyX-Code

}; 
\layout Standard

The first three entries in this structure are: 
\layout Itemize

The size of your driver's instance data; 
\layout Itemize

The driver's name (as passed to 
\family typewriter 
dsk_open()
\family default 
 / 
\family typewriter 
dsk_creat()
\family default 
 ) 
\layout Itemize

The driver's description string.
 
\layout Standard

The remainder of the structure is composed of function pointers; the types
 of these are given in drv.h.
 At the very least, you will need to provide the first three pointers (*_open,
 *_creat and *_close); to make the driver vaguely useful, you will also
 need to implement some of the others.
\layout Standard

Once you have created this structure, edit: 
\layout Itemize

drivers.h.
 Add a declaration for your DRV_CLASS structure, such as 
\layout LyX-Code

extern DRV_CLASS dc_myformat; 
\layout Itemize

drivers.inc.
 Insert a reference to your structure (eg: 
\begin_inset Quotes eld
\end_inset 


\family typewriter 
&dc_myformat,
\family default 

\begin_inset Quotes erd
\end_inset 

) in the list.
 Note that order is important; the comments in drivers.inc describe how to
 decide where things go.
\layout Standard

Edit 
\begin_inset Quotes eld
\end_inset 

lib/Makefile.am
\begin_inset Quotes erd
\end_inset 

.
 Near the top of this file is a list of drivers and their header files;
 just add your .c and .h to this list.
\layout Standard

If your driver depends on certain system headers (as all the floppy drivers
 do) then you will need to add checks for these to 
\begin_inset Quotes eld
\end_inset 

configure.in
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

lib/drvi.h
\begin_inset Quotes erd
\end_inset 

; then run 
\begin_inset Quotes eld
\end_inset 

autoconf
\begin_inset Quotes erd
\end_inset 

 to rebuild the configure script.
\layout Standard

The function pointers in the DRV_CLASS structure are described in drv.h.
 The first parameter to all of them (
\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

) is declared as a pointer to DSK_DRIVER.
 In fact, it is a pointer to the first member of your instance data structure.
 Just cast the pointer to the correct type:
\layout LyX-Code

/* Sanity check: Is this meant for our driver? */ 
\layout LyX-Code

if (self->dr_class != &dc_posix) return DSK_ERR_BADPTR; 
\layout LyX-Code

pxself = (POSIX_DSK_DRIVER *)self;
\layout Standard

and you're in business.
\layout Subsection

Driver functions
\layout Subsubsection

dc_open
\layout LyX-Code

dsk_err_t (*dc_open )(DSK_PDRIVER self, const char *filename)
\layout Standard

Attempt to open a disc image.
 Entered with: 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 points to the instance data for this disc image (see above); it will have
 been initialised to zeroes using memset().
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

filename
\begin_inset Quotes erd
\end_inset 

 is the name of the image to open.
 
\layout Standard

Return: 
\layout Description

DSK_ERR_OK: The driver has successfully opened the image.
 
\layout Description

DSK_ERR_NOTME: The driver cannot handle this image.
 Other drivers should be allowed to try to use it.
 
\layout Description

other: The driver cannot handle this image.
 No other drivers should be tried (eg: the image was recognised by this
 driver, but is corrupt).
\layout Standard

If the file has a comment, record it here using dsk_set_comment().
\layout Subsubsection

dc_creat
\layout LyX-Code

dsk_err_t (*dc_creat)(DSK_PDRIVER self, const char *filename)
\layout Standard

Attempt to create a new disc image.
 For the 
\begin_inset Quotes eld
\end_inset 

floppy
\begin_inset Quotes erd
\end_inset 

 drivers, behaves exactly as dc_open.
 Parameters and results are the same as for dc_open, except that DSK_ERR_NOTME
 is treated like any other error.
\layout Subsubsection

dc_close
\layout LyX-Code

dsk_err_t (*dc_close)(DSK_PDRIVER self)
\layout Standard

Close the disc image.
 This will be the last call your driver will receive for a given disc image
 file, and it should free any resources it is using.
 Whether it returns DSK_ERR_OK or an error, this disc image will not be
 used again.
\layout Subsubsection

dc_read 
\layout LyX-Code

dsk_err_t (*dc_read)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector)
\layout Standard

Read a sector.
 Note that sector addresses passed to drivers are _always_ in C/H/S format.
 This function has the same parameters and return values as dsk_pread().
\layout Subsubsection

dc_write 
\layout LyX-Code

dsk_err_t (*dc_write)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const
 void *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_psect_t sector)
\layout Standard

Write a sector.
 This function has the same parameters and return values as dsk_pwrite().
 If your driver is read-only, leave this function pointer NULL.
\layout Subsubsection

dc_format 
\layout LyX-Code

dsk_err_t (*dc_format)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, const DSK_FORMAT *format, unsigned char filler)
\layout Standard

Format a track.
 This function has the same parameters and return values as dsk_pformat().
 If your driver cannot format tracks, leave this function pointer NULL.
\layout Subsubsection

dc_getgeom
\layout LyX-Code

dsk_err_t (*dc_getgeom)(DSK_PDRIVER self, DSK_GEOMETRY *geom)
\layout Standard

Get the disc geometry.
 Leave this function pointer as NULL unless either:
\layout Enumerate

Your disc image does not allow a caller to use an arbitrary disc geometry.
 The two drivers which currently do this are the Win32 one, because Windows
 NT decides on the geometry itself and doesn't let programs change it; and
 the MYZ80 one, which has a single fixed geometry.
\layout Enumerate

Your disc image file contains enough information to populate a DSK_GEOMETRY
 completely.
 rcpmfs does this.
 
\layout Enumerate

You want to do an extended geometry probe including a call to the default
 one.
 The internal function dsk_defgetgeom() has been provided for this; it's
 the same as dsk_getgeom() but always uses the standard probe.
\layout Standard

Returns DSK_ERR_OK if successful; DSK_ERR_NOTME or DSK_ERR_NOTIMPL to fall
 back to the standard LibDsk geometry probe; other values to indicate failure.
\layout Subsubsection

dc_secid 
\layout LyX-Code

dsk_err_t (*dc_secid)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, DSK_FORMAT *result)
\layout Standard

Read the ID of a random sector on a certain track/head, and put it in 
\begin_inset Quotes eld
\end_inset 

result
\begin_inset Quotes erd
\end_inset 

.
 This function is primarily used to test for discs in CPC format (which
 have oddly-numbered physical sectors); if the disc image can't support
 this (eg: the 
\begin_inset Quotes eld
\end_inset 

raw
\begin_inset Quotes erd
\end_inset 

 or Win32 drivers) then leave the function pointer NULL.
\layout Subsubsection

dc_xseek 
\layout LyX-Code

dsk_err_t (*dc_xseek)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head);
\layout Standard

Seek to a given cylinder / head.
 For disc images, just return DSK_ERR_OK if the cylinder/head are in range,
 or DSK_ERR_SEEKFAIL otherwise.
 For a floppy driver, only implement this function if your FDC can perform
 a seek by itself.
\layout Subsubsection

dc_xread, dc_xwrite 
\layout LyX-Code

dsk_err_t (*dc_xread)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead_t
 head_expected, dsk_psect_t sector, size_t bytes_to_write, int *deleted);
 
\layout LyX-Code

dsk_err_t (*dc_xwrite)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, const
 void *buf, dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected,
 dsk_phead_t head_expected, dsk_psect_t sector, size_t bytes_to_read, int
 *deleted);
\layout Standard

Read / write sector whose ID may not match its position on disc, or which
 is marked as deleted.
 Only implement this if your disc image emulates sector IDs or your floppy
 driver exposes this level of functionality.
 Currently it is only implemented in the Linux and CPCEMU drivers.
\layout Subsubsection

dc_status 
\layout LyX-Code

dsk_err_t (*dc_status)(DSK_PDRIVER self, const DSK_GEOMETRY &geom, dsk_phead_t
 head, unsigned char *result); 
\layout Standard

Return the drive status (see dsk_drive_status() for the bits to return).
 
\begin_inset Quotes eld
\end_inset 

*result
\begin_inset Quotes erd
\end_inset 

 will contain the value calculated by the default implementation; for most
 image file drivers, all you have to do is set the read-only bit if appropriate.
\layout Subsubsection

dc_tread 
\layout LyX-Code

dsk_err_t (*dc_tread)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head);
\layout Standard

Read a track.
 You need only implement this if your floppy driver exposes the relevant
 functionality; if you don't, the library will use multiple calls to dc_read()
 instead.
 This function has the same parameters and return values as dsk_ptread().
\layout Subsubsection

dc_xtread
\layout LyX-Code

dsk_err_t (*dc_xread)(DSK_PDRIVER self, const DSK_GEOMETRY *geom, void *buf,
 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected, dsk_phead_t
 head_expected);
\layout Standard

Read a track, with extended sector matching (sector headers on disc differ
 from physical location).
 This function has the same parameters and return values as dsk_xtread().
 As with dc_tread(), you need only implement this function if your floppy
 driver has a special READ TRACK command.
\layout Subsubsection

dc_option_enum
\layout LyX-Code

dsk_err_t (*dc_option_enum)(DSK_DRIVER *self, int idx, char **optname);
\layout Standard

List numerical options which your driver supports.
 If your driver does not support any, you need not implement this.
\layout Subsubsection

dc_option_set, dc_option_get
\layout LyX-Code

dsk_err_t (*dc_option_set)(DSK_DRIVER *self, const char *optname, int value);
 
\layout LyX-Code

dsk_err_t (*dc_option_get)(DSK_DRIVER *self, const char *optname, int *value);
\layout Standard

Get or set the value of a numerical option.
 Again, if your driver has no settable options, this need not be implemented.
\layout Subsubsection

dc_trackids
\layout LyX-Code

dsk_err_t (*dc_trackids)(DSK_DRIVER *self,  const DSK_GEOMETRY *geom, dsk_pcyl_t
 cylinder, dsk_phead_t head, dsk_psect_t *count, DSK_FORMAT **result);
\layout Standard

Read the IDs of all sectors on the specified track, preferably in the correct
 order and starting at the index hole.
 If you leave this function pointer as NULL, LibDsk will use a default implement
ation.
\layout Subsubsection

dc_rtread
\layout LyX-Code

dsk_err_t (*dc_rtread)(DSK_DRIVER *self, const DSK_GEOMETRY *geom, void
 *buf, dsk_pcyl_t cylinder,  dsk_phead_t head, int reserved);
\layout Standard

For future expansion.
 Leave this function pointer as NULL.
\layout Section

Adding new compression methods
\layout Standard

Adding a new compression method is very similar to adding a driver, though
 you only have to implement four functions.
\layout Standard

To add a new driver, you create a new COMPRESS_CLASS structure and add it
 to various files.
\layout Subsection

Driver header 
\layout Standard

This is done as for disc drivers.
 If you don't need any extra variables (for example, gzip and bzip2 compression
 don't) then you don't have to declare a new structure type - see lib/compgz.h
 for an example.
\layout Subsection

Driver implementation 
\layout Standard

Secondly, create a .c file for your driver.
 It's probably easiest to base this on lib/compgz.c.
 At the start of this file, create a COMPRESS_CLASS structure, such as:
\layout LyX-Code

COMPRESS_CLASS cc_gz = 
\layout LyX-Code

{ 
\layout LyX-Code

    sizeof(COMPRESS_DATA), 
\layout LyX-Code

    "gz", 
\layout LyX-Code

    "Gzip (deflate compression)", 
\layout LyX-Code

    gz_open, /* open */ 
\layout LyX-Code

    gz_creat, /* create new */ 
\layout LyX-Code

    gz_commit, /* commit */ 
\layout LyX-Code

    gz_abort /* abort */ 
\layout LyX-Code

};
\layout Standard

The first three entries in this structure are: 
\layout Itemize

The size of your driver's instance data.
 The GZip driver has no instance data and so just uses COMPRESS_DATA.
 If it had extra data these would be in a struct called GZ_COMPRESS_DATA,
 so the size here would be sizeof(GZ_COMPRESS_DATA).
 
\layout Itemize

The driver's name (as passed to dsk_open() / dsk_creat() ) 
\layout Itemize

The driver's description string.
 
\layout Standard

The remainder of the structure is composed of function pointers.
 The types of these are given in drv.h.
 You must implement all four.
\layout Standard

Once you have created this structure, edit: 
\layout Itemize

comp.h.
 Include your header.
 
\layout Itemize

compress.inc.
 Insert a reference to your structure (eg: 
\begin_inset Quotes eld
\end_inset 

&cc_myzip,
\begin_inset Quotes erd
\end_inset 

) in the list.
 Note that order is important.
\layout Standard

Edit 
\begin_inset Quotes eld
\end_inset 

lib/Makefile.am
\begin_inset Quotes erd
\end_inset 

.
 At the bottom of this file is a list of drivers and their header files;
 just add your .c and .h to this list.
\layout Standard

If your driver depends on certain system headers (eg, the gzip one depends
 on zlib.h) then you will need to add checks for these to 
\begin_inset Quotes eld
\end_inset 

configure.in
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

lib/compi.h
\begin_inset Quotes erd
\end_inset 

; then run 
\begin_inset Quotes eld
\end_inset 

autoconf
\begin_inset Quotes erd
\end_inset 

 to rebuild the configure script.
\layout Standard

The function pointers in the COMPRESS_CLASS structure are described in lib/compr
ess.h.
 The first parameter to all of them (
\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

) is declared as a pointer to COMPRESS_DATA.
 In fact, it is a pointer to the first member of your instance data structure.
 Just cast the pointer to the correct type:
\layout LyX-Code

/* Sanity check: Is this meant for our driver? */ 
\layout LyX-Code

if (self->cd_class != &cc_sq) return DSK_ERR_BADPTR; 
\layout LyX-Code

sqself = (SQ_COMPRESS_DATA *)self;
\layout Standard

and you're in business.
\layout Subsection

Compression functions
\layout Subsubsection

cc_open 
\layout LyX-Code

dsk_err_t (*cc_open )(COMPRESS_DATA *self)
\layout Standard

Attempt to decompress a compressed file.
 
\layout Itemize


\begin_inset Quotes eld
\end_inset 

self
\begin_inset Quotes erd
\end_inset 

 points to the instance data for this disc image.
 
\layout Itemize

self->cd_cfilename is the filename of the file to decompress.
\layout Standard

Return: 
\layout Description

DSK_ERR_OK: The file has been decompressed.
 
\layout Description

DSK_ERR_NOTME: The file is not compressed using this driver's method.
 
\layout Description

other: The file does belong to this driver, but it is corrupt or some other
 error occurred.
\layout Standard

Two helper functions may be useful when you are writing cc_open:
\layout LyX-Code

dsk_err_t comp_fopen(COMPRESS_DATA *self, FILE **pfp);
\layout Standard

Open the the file whose name is given at 
\family typewriter 
self->cd_cfilename
\family default 
.
 If successful, 
\family typewriter 
*pfp 
\family default 
will be the opened stream.
 If not, it will be NULL.
 If the file can only be opened read-only, sets 
\family typewriter 
self->cd_readonly
\family default 
 to 1.
\layout LyX-Code

dsk_err_t comp_mktemp(COMPRESS_DATA *self, FILE **pfp);
\layout Standard

Create a temporary file and store its name at 
\family typewriter 
self->cd_ufilename
\family default 
.
 You should use this to create the file that you decompress into.
\layout Subsubsection

cc_creat
\layout LyX-Code

dsk_err_t (*cc_creat)(COMPRESS_DATA *cd)
\layout Standard

Warn the compression engine that a disc image file is being created, and
 when closed it will be compressed.
 The filename is stored at 
\family typewriter 
self->cd_cfilename
\family default 
.
 Normally this just returns DSK_ERR_OK.
\layout Subsubsection

cc_commit
\layout LyX-Code

dsk_err_t (*cc_commit)(COMPRESS_DATA *cd)
\layout Standard

Compress an uncompressed file.
 
\family typewriter 
self->cd_ufilename
\family default 
 is the name of the file to compress.
 
\family typewriter 
self->cd_cfilename
\family default 
 is the name of the output file.
\layout Subsubsection

cc_abort 
\layout LyX-Code

dsk_err_t (*cc_abort)(COMPRESS_DATA *cd)
\layout Standard

This is used if a file was decompressed and it's now being closed without
 having been changed.
 There is therefore no need to compress it again.
 This normally just returns DSK_ERR_OK.
\layout Section

Adding new remote transports.
\layout Standard

Adding a new remote transport is also very similar to adding a driver.
\layout Standard

To add a new driver, you create a new REMOTE_CLASS structure and add it
 to various files.
\layout Subsection

Driver header 
\layout Standard

This is done as for disc drivers.
 Create a structure based on REMOTE_DATA to hold your class's data -- see
 lib/rpctios.h and lib/rpcfork.h for examples.
\layout Subsection

Driver implementation 
\layout Standard

Create a .c file for your driver.
 It's probably easiest to base this on lib/rpcfork.c.
 At the start of this file, create a REMOTE_CLASS structure, such as:
\layout LyX-Code

REMOTE_CLASS rpc_fork = 
\layout LyX-Code

{ 
\layout LyX-Code

    sizeof(FORK_REMOTE_DATA), 
\layout LyX-Code

    "fork", 
\layout LyX-Code

    "UNIX client using fork", 
\layout LyX-Code

    fork_open, /* open */ 
\layout LyX-Code

    fork_close, /* close */ 
\layout LyX-Code

    fork_call, /* perform RPC */ 
\layout LyX-Code

\layout LyX-Code

};
\layout Standard

The first three entries in this structure are: 
\layout Itemize

The size of your driver's instance data -- sizeof(your_REMOTE_DATA) structure.
\layout Itemize

The driver's name.
 If the filename passed to LibDsk begins with this name followed by a colon,
 then it's assumed to be using your driver.
 
\layout Itemize

The driver's description string.
 
\layout Standard

The remainder of the structure is composed of function pointers.
 The types of these are given in lib/remote.h.
 You must implement all three.
\layout Standard

Once you have created this structure, edit: 
\layout Itemize

lib/remall.h.
 Include your header.
 
\layout Itemize

lib/remote.inc.
 Insert a reference to your structure (eg: 
\begin_inset Quotes eld
\end_inset 

&rpc_fork,
\begin_inset Quotes erd
\end_inset 

) in the list.
 The drivers will be tested in the order in which they appear in the file.
\layout Standard

Edit 
\begin_inset Quotes eld
\end_inset 

lib/Makefile.am
\begin_inset Quotes erd
\end_inset 

.
 At the bottom of this file is a list of drivers and their header files;
 just add your .c and .h to this list.
\layout Standard

If your driver depends on certain system headers (eg, the termios one depends
 on termios.h) then you will need to add checks for these to 
\begin_inset Quotes eld
\end_inset 

configure.in
\begin_inset Quotes erd
\end_inset 

 and 
\begin_inset Quotes eld
\end_inset 

lib/drvi.h
\begin_inset Quotes erd
\end_inset 

; then run 
\begin_inset Quotes eld
\end_inset 

autoconf
\begin_inset Quotes erd
\end_inset 

 to rebuild the configure script.
\layout Standard

The function pointers in the REMOTE_CLASS structure are described in lib/compres
s.h.
 The first parameter to all of them (
\begin_inset Quotes eld
\end_inset 

pDriver
\begin_inset Quotes erd
\end_inset 

) is declared as DSK_PDRIVER; you can extract a pointer to your instance
 data using the dr_remote member like this:
\layout LyX-Code

/* Sanity checks */ 
\layout LyX-Code

self = (FORK_REMOTE_DATA *)pDriver->dr_remote;
\layout LyX-Code

if (self == NULL || self->super.rd_class != &rpc_fork) 
\layout LyX-Code

        return DSK_ERR_BADPTR; 
\layout LyX-Code

\layout Subsection

Remote communication functions
\layout Subsubsection

rc_open 
\layout LyX-Code

dsk_err_t (*rc_open )(DSK_PDRIVER pDriver, const char *name, char *nameout)
\layout Standard

Connect to a remote server.
 
\layout Itemize

pDriver points to a DSK_DRIVER containing the pointer to your instance data.
\layout Itemize

name is the filename as passed to LibDsk, starting with 
\begin_inset Quotes eld
\end_inset 


\emph on 
driver
\emph default 
:
\begin_inset Quotes erd
\end_inset 

 and containing any connection parameters needed.
 
\layout Itemize

nameout is an output buffer with enough space to hold a string of the same
 length as the input filename.
 If you are returning DSK_ERR_OK, it must be set to the input filename minus
 any options this driver has used.
 For example, the 
\begin_inset Quotes eld
\end_inset 

serial
\begin_inset Quotes erd
\end_inset 

 driver, given a filename like 
\begin_inset Quotes eld
\end_inset 

serial:/dev/ttyS1,2400-crtscts,example.ufi,raw
\begin_inset Quotes erd
\end_inset 

 would extract its own options and return 
\begin_inset Quotes eld
\end_inset 

example.ufi,raw
\begin_inset Quotes erd
\end_inset 

 here.
 
\layout Standard

Return: 
\layout Description

DSK_ERR_OK: Connection established.
\layout Description

DSK_ERR_NOTME: The filename passed is not recognised by this driver.
 
\layout Description

other: An error such as out-of-memory occurred.
\layout Subsubsection

rc_close
\layout LyX-Code

dsk_err_t (*rc_close)(DSK_PDRIVER pDriver)
\layout Standard

Close the connection to the remote server.
\layout Subsubsection

rc_call
\layout LyX-Code

dsk_err_t (*rc_call)(DSK_PDRIVER pDriver, unsigned char *input, int inp_len,
 unsigned char *output, int *out_len)
\layout Standard

Perform a remote procedure call to the server.
 
\layout Description

input is the packet LibDsk wants to send.
\layout Description

inp_len is the number of bytes in the packet.
\layout Description

output is a buffer for the result packet.
\layout Description

*out_len (on entry) is the size of the result buffer.
\layout Description

*out_len (on return) is the number of bytes that were populated in the result
 buffer.
\layout Standard

In general, this call will wrap the input in whatever framing bytes are
 necessary (usually including the packet length, since packets do not contain
 their own length), send the packet over the wire, wait for a response,
 and unpack the response into 'output'.
 Return DSK_ERR_TIMEOUT if the connection timed out (the 'serial' driver
 waits 30 seconds) and DSK_ERR_ABORT if the user deliberately broke the
 connection.
\layout Section
\start_of_appendix 

\begin_inset LatexCommand \label{sec: dqk}

\end_inset 

DQK Files 
\layout Standard

A DQK file is a .DSK file compressed using Richard Greenlaw's Squeeze file
 format (originally from CP/M as SQ.COM, and later built in to NSWP.COM; versions
 also exist for DOS and UNIX).
 SQ was used in preference to more efficient compressors such as gzip because
 it can be readily decoded on 8-bit and 16-bit computers.
\layout Standard

The original reason for DQK files was software distribution.
 A disc image of a 180k disc won't fit on a 180k disc, owing to various
 overheads.
 However, the compressed DQK version may fit onto such a disc, and leave
 room for a tool to write the DQK back out as well.
 
\layout Standard

Such a tool has been included in the 
\begin_inset Quotes eld
\end_inset 

dskwrite
\begin_inset Quotes erd
\end_inset 

 directory in this distribution.
 It contains the following files:
\layout Itemize

dskwrite.com: Program to write .DSK or .DQK files out to a real disc.
 The .COM file works on PCs, Amstrad PCWs and Sinclair Spectrum +3s.
 
\layout Itemize

dskwrite.txt: Documentation for dskwrite.
 
\layout Itemize

dskwrite.z80: Z80 source for the CP/M version.
 
\layout Itemize

dskwrite.asm: 8086 source for the DOS version.
 
\layout Itemize

dskwrsea.com: The dskwrite distribution file - a self-extracting archive.
 It will self-extract under CP/M or DOS.
\layout Standard

Note that the files in the 
\begin_inset Quotes eld
\end_inset 

dskwrite
\begin_inset Quotes erd
\end_inset 

 directory are not GPLed or LGPLed.
 They are public domain.
 You may do whatsoever you please with them.
\layout Standard

LibDsk has been given .DQK support (use the 
\begin_inset Quotes eld
\end_inset 

dsk
\begin_inset Quotes erd
\end_inset 

 driver with 
\begin_inset Quotes eld
\end_inset 

sq
\begin_inset Quotes erd
\end_inset 

 compression) so that .DQK files don't have to be created and compressed
 in a two-state process.
 
\layout Section

LibDsk with cpmtools
\layout Standard

cpmtools v1.9 and later <http://www.moria.de/~michael/cpmtools/> can be configured
 to use LibDsk for all disc access, thus allowing CP/M discs and emulator
 disc images to be read and written.
 
\layout Standard

The myz80 and nanowasp drivers use a fixed disk format; here are diskdefs
 entries which can be used to read them (these are for the old diskdefs
 format with one line per entry):
\layout LyX-Code

myz80    1024 64 128 4096 1024 1 0 3 
\layout LyX-Code

microbee  512 80  10 2048 128  1 2 2.2
\layout Section

DSK / EDSK recording mode extension
\layout Standard

This extension was proposed by me on the comp.sys.sinclair and comp.sys.amstrad.8bit
 newsgroups on 10 January 2004.
 It was subsequently released in ANNE 2.1.4 and added to the formal EDSK format
 definition at <
\begin_inset LatexCommand \url[http://andercheran.aiind.upv.es/~amstrad/docs/extdsk.html]{http://andercheran.aiind.upv.es/~amstrad/docs/extdsk.html}

\end_inset 

>.
\layout Standard

DSK/EDSK originate on the Amstrad CPC, which ordinarily writes all its diskettes
 in MFM recording mode and at the Double Density rate.
 However, ANNE emulates the PcW16, which also supports the High Density
 rate; and the system software depends on DD discs not being readable at
 the HD rate.
\layout Standard

The extension gives meanings to two unused bytes of the DSK/EDSK 
\begin_inset Quotes eld
\end_inset 

Track-Info
\begin_inset Quotes erd
\end_inset 

 block:
\layout Paragraph*

Byte 12h: Data rate.
 
\layout Description

0 Unknown 
\layout Description

1 Single or Double Density (180k, 720k, etc.) 
\layout Description

2 High Density (1.2M, 1.4M, etc.) 
\layout Description

3 Extended Density (2.8M)
\layout Paragraph*

Byte 13h: Recording mode.
 
\layout Description

0 Unknown 
\layout Description

1 FM
\layout Description

2 MFM
\layout Standard

Existing files should have zeroes in these bytes; hence the use of 0 for
 Unknown.
 LibDsk will guess the values in if the ones in the file are zero.
\the_end