The source code of the central PCMCIA unit of DeskWork.de has been donated for DOS development (by the author, in 2004). However, he asked me to move my version (English comments, original version used German comments, plus explanations about how the unit interacts with other parts of DeskWork) out of reach for Google in 1/2005. If you want to do some experiments with PCMCIA and DOS, please contact me by mail: eric $ coli.uni-sb.de (replace the $ by @ to get the actual address). Eric --- excerpts from the file / notes --- DeskWork uses a 35 Hz time stamp counter. You have to map the CIS config data (max 4k, often less than 1k) and the bridge 64k address space to an uncached high area which is not used by any UMB. The ISA-PnP base port has to be known. States: 0 not present, 1 empty, 2 booting, 3 card, 4 nopower Classes: 0 none, 1 ethernet, 2 eide, 3 memstick, 4 harddisk, 5 serial Voltage codes used: 0xbf, 0x91 Each slot has class, status, IRQ, voltage, vendor-id/device-id, I/O base, name string, boot timestamp. Used DeskWork units (you have to write replacements for those to make the unit happy - obvious) are: Kernel (Window, Input, FrameBtn, Views, VGA driver, GDI), Boot, Ethernet, ISA, EIDE, ExtFS, MMSound, SerPorts. Kernel functions: FillChar, LTrim, RTrim (trivial string stuff) Boot functions: BootText (shows a message / boot log) Ethernet: AddPort (register ports and IRQ), InitCard, RemovePort ISA functions: RegionFree (tests if a port range is in use) EIDE functions: CheckInterface (test if an IDE controller is present at a given I/O port, and if drives are connected... for PCMCIA, at most 1 drive is connected for each controller) AddPort (as above: usually 2 ranges, distance 0x206, no IRQ), RemovePort (as above), FirstIDE (variable: linked disk list) ExtFS functions: AddPort, RemovePort (as above) MMSound: only VocIRQ value needed, to avoid IRQ clashes SerPorts functions: for modems - AddPort, RemovePort, and the SetSPortDevice initialization / configuration function which uses the SPorts array { Init functions (do port config, init device) implemented below include: } { EnableEIDEAutoSize EnableShiningEIDE EnableEIDENormal EnableNinjaEIDE } { EnableClik EnableMemstick EnableModem EnableNE2000 } { PCMCIA bridge programming: indexed register, 4 slots * 64 registers } function InCard(Slot,Index: Byte): Byte; assembler; "out_byte(base,(slot&3)<<6 + index); return in_byte(base+1);" procedure OutCard(Slot,Index,Wert: Byte); assembler; "out_byte(base,(slot&3)<<6 + index); out_byte(base+1, wert);" { PCMCIA bridge registers (base: 0/64/128/192 for slot 0..3) -> } { 0 "always 82..8f", 1 card presence / powerok, 2 power config..., } { 3 IRQ config / reset, 0x16/0x2f "used during reset", 6/7 config, } { 8 + (N*4) I/O window config, 16 + (N*8) memory window config } { I/O windows: startL, startH, endL, endH } { memory windows: startL, startH, endL, endH, offsL, offsH/attr } { You could also use int 1a.80 ... 1a.af, but that is an extra TSR } { -> nice(?) PCMCIA (and CardBus) services, IF you have the TSR... } function CardPresent(Slot: Byte): Boolean; begin CardPresent := (InCard(Slot,1) and $C) = $C; end; procedure DisableINT(Slot: Byte); begin OutCard(Slot,3, InCard(Slot,3) and not $1F ); end; procedure EnableINT(Slot,IRQ: Byte); begin CPort.Slots[Slot].IRQ := IRQ; OutCard(Slot,3, InCard(Slot,3) or $10 or (IRQ and 15) ); end; procedure DisableIOWindow(Slot,Window: Byte); var Ctrl: Byte; begin CPort.Slots[Slot].IRQ := 0; Ctrl := InCard(Slot,6); OutCard(Slot,6, (Ctrl and not ($40 shl (Window and 1))) ); end; procedure EnableIOWindow(Slot,Window: Byte; Start,Ende: Word; Autosize: Boolean); var Ctrl,Ofs: Byte; begin Window:=Window and 1; { disable window } Ctrl := InCard(Slot,6) or 32; OutCard(Slot,6,(Ctrl and not ($40 shl Window))); { new window configuration } Ofs := Window*4+8; OutCard(Slot,Ofs,Lo(Start)); OutCard(Slot,Ofs+1,Hi(Start)); OutCard(Slot,Ofs+2,Lo(Ende)); OutCard(Slot,Ofs+3,Hi(Ende)); { set parameters } Ctrl := InCard(Slot,7); if Window=0 then begin Ctrl := (Ctrl and $F0) or $09; if AutoSize=True then Ctrl := Ctrl or $02; end else begin Ctrl := (Ctrl and $0F) or $90; if AutoSize=True then Ctrl := Ctrl or $20; end; OutCard(Slot,7,Ctrl); { enable window } Ctrl := InCard(Slot,6); OutCard(Slot,6,(Ctrl or ($40 shl Window))); end; procedure DisableMemoryWindow(Slot,Window: Byte); var Ctrl: Byte; begin Ctrl := InCard(Slot,6); OutCard(Slot,6, (Ctrl and not (1 shl (Window and 3))) ); end; procedure EnableMemoryWindow(Slot,Window: Byte; SystemStart,SystemEnde,CardOffs: Word; Attr: Boolean); var Ctrl,Ofs,B: Byte; begin Window:=Window and 3; { disable window } Ctrl := InCard(Slot,6) or 32; OutCard(Slot,6,(Ctrl and not (1 shl Window))); { new window configuration } Ofs := Window*8+16; OutCard(Slot,Ofs,Lo(SystemStart)); OutCard(Slot,Ofs+1,Hi(SystemStart)); OutCard(Slot,Ofs+2,Lo(SystemEnde)); OutCard(Slot,Ofs+3,Hi(SystemEnde)); OutCard(Slot,Ofs+4,Lo(CardOffs)); OutCard(Slot,Ofs+5,Hi(CardOffs) or ($40*Byte(Attr))); { enable window } OutCard(Slot,6,(Ctrl or (1 shl Window))); end; procedure SkipMove(var Src,Dest; Size: Word); assembler; "read string of WORDs (must use lodsw!) and store only the low BYTEs" procedure EnableModem(Socket: Byte); available on request procedure EnableNE2000(Socket: Byte); available on request procedure EnableShiningEIDE(Socket: Byte); available on request procedure EnableNinjaEIDE(Socket: Byte); available on request procedure EnableMemstick(Socket: Byte); available on request procedure EnableClik(Socket: Byte); available on request procedure EnableEIDENormal(Socket: Byte); available on request... Selects IOBase based on RegionFree output as 190, 180 or 1a0, then: EnableIOWindow(Socket,0,IOBase,IOBase+7,False); EnableIOWindow(Socket,1,IOBase+$206,IOBase+$207,False); DisableINT(Socket); Mem[Sel:512]:=1; { enable True ATA } PortNo:=EIDE.AddPort(IOBase,IOBase+$206,0,1,False,False,Name); ... if PortNo<>0 then if EIDE.CheckInterface(PortNo)<>0 then begin P:=EIDE.FirstIDE; while P<>nil do begin with P^ do if (P^.Controller=PortNo) and (P^.Typ=typGenericATA) then begin ExtFS.AddPort(ExtFS.pcmciaHD1 shl Socket); Class:=clsHarddisk; goto Fertig; end; P:=P^.NextIDE; end; Fertig: ... procedure EnableEIDEAutosize(Socket: Byte); available on request procedure AddPort(_BasePort: Word); { ISA-PnP: check for PCMCIA bridge } begin Port[_BasePort]:=0; if (Port[_BasePort+1] in [$82..$8F])=False then exit; CPort.BasePort:=_BasePort; end; function HotplugPCMCIA(Mount: Boolean): Boolean; available on request... If CPort.BasePort is nonzero, check all four slots for possible status changes... If card inserted, start driver boot process for it, using a timeout. If card removed, stop drivers and deregister ports and IRQ. ... pcmciaBooting: begin OutCard(A,3,$20); { Reset } OutCard(A,$16,3); OutCard(A,$2F,0); OutCard(A,3,$60); { Reset completed } NextPowerConfig: Inc(Power,1); if Power>High(PowerConfig) then Status := NoPower else begin OutCard(A,2,PowerConfig[Power]); { power supply } GetTimer35(Ti,2); { from Timer unit } repeat until Timer35LaterThan(Ti); { from Timer unit } if (InCard(A,1) and 64)=0 then goto NextPowerConfig; GetTimer35(BootTime,75); { from Timer unit } end; end; pcmciaCard: begin GetTimer35(Ti,5); { from Timer unit } repeat until Timer35LaterThan(Ti)=True; { from Timer unit } EnableMemoryWindow(A, 0, MemWindowBase shr 8,MemWindowBase shr 8, 16180, True); GetTimer35(Ti,2); { from Timer unit } repeat until Timer35LaterThan(Ti)=True; { from Timer unit } SkipMove(Ptr(Sel,0)^,CIS,SizeOf(CIS)); { defined in this unit } { CIS is at most 2k bytes, but accessed as 2k words } Name := 'incompatible device'; Offset := 0; Func := 0; Done := False; repeat begin Ende := Offset+CIS[Offset+1]+1; case CIS[Offset] of $15: begin Inc(Offset,4); Name := ''; while (CIS[Offset]<>0) and (Offset0) and (Offset0) and (Offset=SizeOf(CIS)); { mount special devices } if LeftStr(Name,9)='NinjaATA-' then EnableNinjaEIDE(A) else { Ninja ATA } { Pascal function: LeftStr(string,size) } case Func of 2: case Vendor of $0115: if Device=$3330 then EnableModem(A); end; 4: if (Vendor=$000A) and (Device=$0000) then EnableMemStick(A) else { Noname MemoryStick } if (Vendor=$00F1) and (Device=$0000) then EnableMemStick(A) else { Sony MemoryStick } if (Vendor=$FFFF) and (Device=$0003) then EnableClik(A) else { iOMEGA Clik } if Vendor=$5241 then EnableEIDEAutosize(A) else { Generic ATA Autosize } if LeftStr(Name,17)='Shining PMIDE-ASC' then EnableShiningEIDE(A) else { Shing Technology EIDE Adaptor } EnableEIDENormal(A); { Generic ATA, if none of the special ones } { Pascal function: LeftStr(string,size) } 6: EnableNE2000(A); { Generic NE2000, just assume all LAN cards are NE2000 } end; { release window again } DisableMemoryWindow(A,0); end; end; end; end; end; procedure DetectPCMCIA; available on request... try BasePort 0x3e0... use 4k window at 0xcc00:0... if not all 4k contain 0xff, do HotplugPCMCIA(True), and do for all 4 slots (except those which are in "driver booting" state)...: show BasePort and (if card present) card name string. Increment search pointer by 0x400:0 (stop at 0xf000:0) to find other devices. procedure DonePCMCIA; var A: Byte; begin if CPort.BasePort=0 then exit; for A := 0 to 3 do with CPort.Slots[A] do if (IRQ<>0) and (Status=pcmciaCard) then DisableINT(A); end; { "main()" of this unit } begin FillChar(CPort,SizeOf(CPort),0); Sel := 0; end.