DOSBox-X
|
00001 #include <string.h> 00002 #include "dosbox.h" 00003 #include "inout.h" 00004 #include "pic.h" 00005 #include "setup.h" 00006 #include "control.h" 00007 00008 /* 00009 00010 This is DosBox handler of 93c46 copy-protection dongle connected to LPT port. 00011 At least Rainbow Sentinel Cplus and MicroPhar are 93c46-based dongles. 00012 00013 93c46 memory chip contain 64*16 words. More on it: 00014 http://www.atmel.com/dyn/resources/prod_documents/doc0172.pdf 00015 00016 Few notes: 00017 00018 * It is unable to detect dongle presence on software side, so, software 00019 usually reading some cell (often 0x3F) and check magic value. 00020 00021 * Wiring scheme may differ from dongle to dongle, but usually, 00022 DI (data input), SK (clock), CS (chip select) and power lines are 00023 taken from D0..D7 in some order. 00024 00025 * DO (data output) may be connected to ACK or BUSY printer lines. 00026 00027 Add this file to DosBox project, patch dosbox.cpp patch and add to dosbox.conf 00028 "dongle=true" under "[speaker]" section. 00029 00030 More information: http://blogs.conus.info/node/56 00031 00032 -- dennis@conus.info 00033 00034 */ 00035 00036 #define DONGLE_BASE 0x0378 00037 00038 #define IS_SET(flag, bit) ((flag) & (bit)) 00039 00040 static bool queue_filling=false; 00041 static bool queue_filled=false; 00042 static int queue_idx=0; 00043 static int queue[3+6]; 00044 static int out_idx; 00045 00046 static int last_SK=0; 00047 static bool ackbit=false; 00048 00049 static int ADR; 00050 00051 static unsigned short MEMORY[0x40]= 00052 { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0 00053 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 8 00054 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 10 00055 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 18 00056 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 20 00057 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 28 00058 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 30 00059 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; // 38 00060 00061 //#include <windows.h> 00062 00063 static void dongle_write(Bitu port,Bitu val,Bitu iolen) { 00064 (void)iolen;//UNUSED 00065 (void)port;//UNUSED 00066 static int DI, SK; 00067 /* 00068 LOG(LOG_MISC,LOG_NORMAL)("write dongle port=%x val=%d%d%d%d%d%d%d%d\n", 00069 port, 00070 IS_SET (val, 1<<7) ? 1 : 0, 00071 IS_SET (val, 1<<6) ? 1 : 0, 00072 IS_SET (val, 1<<5) ? 1 : 0, 00073 IS_SET (val, 1<<4) ? 1 : 0, 00074 IS_SET (val, 1<<3) ? 1 : 0, 00075 IS_SET (val, 1<<2) ? 1 : 0, 00076 IS_SET (val, 1<<1) ? 1 : 0, 00077 IS_SET (val, 1<<0) ? 1 : 0); 00078 */ 00079 DI=IS_SET (val, 1<<7) ? 1 : 0; 00080 SK=IS_SET (val, 1<<6) ? 1 : 0; 00081 00082 if (last_SK==0 && SK==1) // posedge 00083 { 00084 if (queue_filled) 00085 { 00086 if (((MEMORY[ADR]>>out_idx)&1)==1) 00087 ackbit=false; // swap it if ACK is negated... 00088 else 00089 ackbit=true; 00090 00091 if (out_idx==0) 00092 queue_filled=false; 00093 else 00094 out_idx--; 00095 } 00096 00097 if (queue_filling==false && DI==1) // start bit 00098 { 00099 //got start bit 00100 queue_filling=true; 00101 queue_filled=false; 00102 queue_idx=0; 00103 } 00104 00105 if (queue_filling) 00106 { 00107 queue[queue_idx]=DI; 00108 if (queue_idx==8) 00109 { // last bit filled 00110 00111 int OP1=queue[1]; 00112 int OP2=queue[2]; 00113 00114 ADR=(queue[3]<<5) | (queue[4]<<4) | (queue[5]<<3) | (queue[6]<<2) | (queue[7]<<1) | (queue[8]); 00115 00116 if (OP1==1 && OP2==0) // read 00117 { 00118 LOG(LOG_MISC,LOG_NORMAL)("93c46 dongle: trying to read at address 0x%x", ADR); 00119 00120 queue_filling=false; 00121 queue_filled=true; 00122 out_idx=15; 00123 } 00124 else 00125 LOG(LOG_MISC,LOG_NORMAL)("93c46 dongle: OP1=%d; OP2=%d: this command is not handled yet", OP1, OP2); 00126 } 00127 else 00128 queue_idx++; 00129 } 00130 } 00131 00132 last_SK=SK; 00133 } 00134 00135 static Bitu dongle_read(Bitu port,Bitu iolen) { 00136 (void)iolen;//UNUSED 00137 (void)port;//UNUSED 00138 Bitu retval; 00139 switch (port-DONGLE_BASE) 00140 { 00141 case 0: /* Data Port */ 00142 return 0; 00143 break; 00144 00145 case 1: /* Status Port */ 00146 if (ackbit==true) 00147 retval=0x40; 00148 else 00149 retval=0; 00150 00151 return retval; 00152 break; 00153 00154 case 2: /* Control Port */ 00155 return 0; 00156 break; 00157 } 00158 return 0xff; 00159 } 00160 00161 class DONGLE: public Module_base { 00162 private: 00163 IO_ReadHandleObject ReadHandler; 00164 IO_WriteHandleObject WriteHandler; 00165 public: 00166 DONGLE(Section* configuration):Module_base(configuration) 00167 { 00168 Section_prop * section=static_cast<Section_prop *>(configuration); 00169 if(!section->Get_bool("dongle")) return; 00170 00171 WriteHandler.Install(DONGLE_BASE,dongle_write,IO_MB,3); 00172 ReadHandler.Install(DONGLE_BASE,dongle_read,IO_MB,3); 00173 } 00174 ~DONGLE(){ 00175 } 00176 }; 00177 00178 static DONGLE* test = NULL; 00179 00180 static void DONGLE_ShutDown(Section* sec){ 00181 (void)sec;//UNUSED 00182 if (test) { 00183 delete test; 00184 test = NULL; 00185 } 00186 } 00187 00188 void DONGLE_OnReset(Section* sec) { 00189 (void)sec;//UNUSED 00190 if (test == NULL && !IS_PC98_ARCH) { 00191 LOG(LOG_MISC,LOG_DEBUG)("Allocating parallel dongle emulation"); 00192 test = new DONGLE(control->GetSection("parallel")); 00193 } 00194 } 00195 00196 void DONGLE_Init() { 00197 LOG(LOG_MISC,LOG_DEBUG)("Initializing dongle emulation"); 00198 00199 AddExitFunction(AddExitFunctionFuncPair(DONGLE_ShutDown),true); 00200 AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(DONGLE_OnReset)); 00201 }