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