|
|
/* 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
/* ------------------------------------------------------------------------ */
|