/* fixchg.c */
/* Inoperative changelines frequenly cause problems when switching between */
/* 1.44Mb diskettes and 1.68Mb DMF diskettes. FixChangeline() tries to */
/* assure that drives A: and B: will not depend upon proper operation of */
/* the drive's changeline. If these efforts fail, it's no big deal; we */
/* do this without even knowing whether the changeline works or not. */
#include "fixchg.h" /* prototype verification */
/* --- definitions -------------------------------------------------------- */
/* See Microsoft MS-DOS Programmer's Reference V6.0, p.38, 312, 319 */
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
#pragma pack (1)
typedef struct
{
WORD tklSectorNum; /* this physical position's sector number */
WORD tklSectorSize; /* size of this sector in bytes */
} NUMSIZE;
typedef struct
{
WORD tklSectors; /* number of sectors in the layout */
NUMSIZE tklNumSize[1]; /* don't need much of this, not used here */
} TRACKLAYOUT;
typedef struct
{
WORD dpBytesPerSec; /* bytes per sector */
BYTE dpSecPerClust; /* sectors per cluster */
WORD dpResSectors; /* reserved sectors */
BYTE dpFATs; /* number of copies of the FAT */
WORD dpRootDirEnts; /* number of entries in the root directory */
WORD dpSectors; /* total # of sectors, 0->more than 64k */
BYTE dpMedia; /* media descriptor byte */
WORD dpFATsecs; /* sectors per copy of the FAT */
WORD dpSecPerTrack; /* sectors per track */
WORD dpHeads; /* number of heads */
DWORD dpHiddenSecs; /* sectors hidden before boot sector */
DWORD dpHugeSectors; /* number of sectors if > 64k sectors */
WORD reserved[3];
} BPB;
typedef struct
{
BYTE dpSpecFunc; /* special functions */
BYTE dpDevType; /* device type, 7=1.44Mb, 9=2.88Mb, etc. */
WORD dpDevAttr; /* device's attributes */
WORD dpCylinders; /* number of cylinders */
BYTE dpMediaType; /* media type, more like density code */
BPB dpBPB; /* the BPB (default or current) */
TRACKLAYOUT dpTrackLayout; /* track layout field appended for set call */
} DEVICEPARAMS, far *PFDEVICEPARAMS;
#pragma pack()
#define SPECIAL_GET_DEFAULT 0 /* get information for default media */
#define SPECIAL_SET_DEFAULT 4 /* set default media, good track layout */
#define ATTR_NONREMOVABLE 1 /* attr bit for non-removable device */
#define ATTR_CHANGELINE 2 /* attr bit for changeline supported */
/* --- FixChangelines() --------------------------------------------------- */
#pragma warning(disable:4704) /* no in-line balking */
void FixChangelines(void)
{
WORD dosVersion;
DEVICEPARAMS dp;
PFDEVICEPARAMS pfDp;
WORD drive;
WORD owner;
_asm mov ah,30h ; get DOS version
_asm int 21h
_asm xchg ah,al
_asm mov dosVersion,ax
/* these IoCtls were new to MS-DOS 3.2. (But then, 1.44Mb drives */
/* weren't supported until 3.3, so needing this is pretty unlikely.) */
if (dosVersion < (0x300 + 20))
{
return; /* prior versions don't need help */
}
pfDp = &dp; /* make a far pointer to DEVICEPARAMS structure */
for (drive = 1; drive <= 2; drive++) /* do A: and B: */
{
/* get drive owner so we can restore it */
_asm mov owner,0 ; assume not shared
_asm mov ax,440Eh ; Get Logical Drive Map
_asm mov bx,drive ; drive number
_asm int 21h ; execute DOS request
_asm jc no_owner ; if failed
_asm mov owner,ax ; save owner (AL)
/* set drive owner to suppress "Insert diskette for drive..." */
_asm mov ax,440Fh ; Set Logical Drive Map
_asm mov bx,drive ; drive number
_asm int 21h ; execute DOS request
/* MS-DOS 5.0 added query Ioctl, to see if the calls we need are */
/* supported. This is highly unlikely to fail. */
no_owner:
if (dosVersion >= 0x500)
{
_asm mov ax,4411h ; Query Ioctl device
_asm mov bx,drive ; drive number
_asm mov cx,0840h ; check on SET DEVICE PARAMETERS
_asm int 21h ; execute DOS request
_asm jc failed ; if not supported
_asm mov ax,4411h ; Query Ioctl device
_asm mov bx,drive ; drive number
_asm mov cx,0860h ; check on GET DEVICE PARAMETERS
_asm int 21h ; execute DOS request
_asm jc failed ; if not supported
}
/* get information about this physical device */
dp.dpSpecFunc = SPECIAL_GET_DEFAULT;
_asm push ds ; preserve data selector
_asm mov ax,440Dh ; generic IoCtl
_asm mov bx,drive ; drive number 1=A: 2=B:
_asm mov cx,0860h ; DISK / GET DEVICE PARAMETERS
_asm lds dx,pfDp ; pointer to DEVICEPARAMS structure
_asm int 21h ; execute DOS request
_asm pop ds ; restore data selector
_asm jc failed ; if error
/* is this device is removable and claims changeline is supported? */
if ((dp.dpDevAttr & (ATTR_NONREMOVABLE | ATTR_CHANGELINE)) ==
ATTR_CHANGELINE) /* if removable with changeline: */
{
/* modify device to "changeline not supported" */
dp.dpSpecFunc = SPECIAL_SET_DEFAULT;
dp.dpDevAttr &= ~ATTR_CHANGELINE; /* disable changeline */
dp.dpTrackLayout.tklSectors = 0; /* no layout being sent */
dp.dpBPB.reserved[0] = 0;
dp.dpBPB.reserved[1] = 0;
dp.dpBPB.reserved[2] = 0;
_asm push ds ; preserve data selector
_asm mov ax,440Dh ; generic IoCtl
_asm mov bx,drive ; drive number 1=A: 2=B:
_asm mov cx,0840h ; DISK / SET DEVICE PARAMETERS
_asm lds dx,pfDp ; pointer to DEVICEPARAMS structure
_asm int 21h ; execute DOS request
_asm pop ds ; restore data selector
}
failed:
/* restore initial drive owner */
_asm mov ax,440Fh ; Set Logical Drive Map
_asm mov bx,owner ; drive number
_asm or bx,bx ; is it shared?
_asm jz nextdrive ; if not shared
_asm int 21h ; execute DOS request
nextdrive:
continue; /* C labels require some statement */
}
return;
}
/* --- stand-alone test stub ---------------------------------------------- */
#ifdef STANDALONE
void main(void)
{
FixChangelines();
}
#endif
/* ------------------------------------------------------------------------ */