00001
00002
00003
00004
00005
00006
00007
00008
00009
00019 #include "config.h"
00020
00021 #include <windows.h>
00022 #include <vddsvc.h>
00023
00024 #include "arch.h"
00025
00027 #define DBG_USERMODE
00028
00030 #define DBG_PROGNAME "OPENCBMVDD.DLL"
00031
00032 #include "debug.h"
00033
00034 #include "vdd.h"
00035 #include "opencbm.h"
00036
00037
00038 #define NEW_IMPLEMENTATION_WITH_SETRELEASE
00039
00040
00041
00042
00043 static PVOID
00044 get_vdm_address(WORD Offset, WORD Length)
00045 {
00046 PBYTE buffer;
00047 ULONG addressInVdm;
00048
00049 addressInVdm = (ULONG) (getES()<<16 | Offset);
00050
00051 buffer = GetVDMPointer (addressInVdm, Length, FALSE);
00052
00053 return buffer;
00054 }
00055
00056 static VOID
00057 release_vdm_address(WORD Offset, WORD Length, PVOID Buffer)
00058 {
00059 ULONG addressInVdm;
00060
00061 addressInVdm = (ULONG) (getES()<<16 | Offset);
00062
00063 FreeVDMPointer(addressInVdm, Length, Length, FALSE);
00064 }
00065
00066
00067 #define retAX( _x_ ) setAX((WORD) _x_)
00068
00069 #define FUNC_CHECKEDBUFFERACCESS(_offset_, _length_) \
00070 \
00071 BOOLEAN error; \
00072 PVOID buffer; \
00073 WORD length; \
00074 WORD offset; \
00075 \
00076 FUNC_ENTER(); \
00077 \
00078 offset = _offset_; \
00079 length = _length_;
00080
00081 #define CHECKEDBUFFERACCESS_PROLOG() \
00082 \
00083 buffer = get_vdm_address(offset, length); \
00084 \
00085 if (!buffer) \
00086 { \
00087 error = TRUE; \
00088 } \
00089 else \
00090 { \
00091 int ret; \
00092 \
00093 error = FALSE;
00094
00095 #define CHECKEDBUFFERACCESS_EPILOG() \
00096 release_vdm_address(offset, length, buffer); \
00097 \
00098 retAX(ret); \
00099 } \
00100 FUNC_LEAVE_BOOLEAN(error);
00101
00102 #define CHECKEDBUFFERACCESS(_func_) \
00103 CHECKEDBUFFERACCESS_PROLOG(); \
00104 ret = _func_; \
00105 CHECKEDBUFFERACCESS_EPILOG();
00106
00107
00108
00109
00110
00129 BOOLEAN
00130 vdd_driver_open(VOID)
00131 {
00132 CBM_FILE cbmfile;
00133 USHORT translatedhandle;
00134 int retValue;
00135
00136 FUNC_ENTER();
00137
00138 retValue = cbm_driver_open(&cbmfile, getDH());
00139
00140 if (retValue == 0)
00141 {
00142 translatedhandle = vdd_cbmfile_store(cbmfile);
00143 if (translatedhandle == (WORD) -1)
00144 {
00145 cbm_driver_close(cbmfile);
00146 translatedhandle = -1;
00147 }
00148 }
00149 else
00150 {
00151 translatedhandle = -1;
00152 }
00153
00154 setBX(translatedhandle);
00155 retAX(retValue ? 1 : 0);
00156
00157 FUNC_LEAVE_BOOLEAN(FALSE);
00158 }
00159
00174 BOOLEAN
00175 vdd_driver_close(CBM_FILE HandleDevice)
00176 {
00177 FUNC_ENTER();
00178
00179 cbm_driver_close(HandleDevice);
00180
00181 FUNC_LEAVE_BOOLEAN(FALSE);
00182 }
00183
00184
00208 BOOLEAN
00209 vdd_get_driver_name(VOID)
00210 {
00211 const char *returned_string;
00212
00213 FUNC_CHECKEDBUFFERACCESS(getSI(), getCX());
00214
00215 CHECKEDBUFFERACCESS_PROLOG();
00216
00217 returned_string = cbm_get_driver_name(getDH());
00218
00219 strncpy(buffer, returned_string, length);
00220
00221 ret = FALSE;
00222
00223 CHECKEDBUFFERACCESS_EPILOG();
00224 }
00225
00226
00227
00228
00229
00254 BOOLEAN
00255 vdd_raw_write(CBM_FILE HandleDevice)
00256 {
00257 FUNC_CHECKEDBUFFERACCESS(getSI(), getCX());
00258
00259 CHECKEDBUFFERACCESS(cbm_raw_write(HandleDevice, buffer, length));
00260 }
00261
00262
00286 BOOLEAN
00287 vdd_raw_read(CBM_FILE HandleDevice)
00288 {
00289 FUNC_CHECKEDBUFFERACCESS(getSI(), getCX());
00290
00291 CHECKEDBUFFERACCESS(cbm_raw_read(HandleDevice, buffer, length));
00292 }
00293
00317 BOOLEAN
00318 vdd_listen(CBM_FILE HandleDevice)
00319 {
00320 FUNC_ENTER();
00321
00322 retAX(cbm_listen(HandleDevice, getCH(), getCL()));
00323
00324 FUNC_LEAVE_BOOLEAN(FALSE);
00325 }
00326
00350 BOOLEAN
00351 vdd_talk(CBM_FILE HandleDevice)
00352 {
00353 FUNC_ENTER();
00354
00355 retAX(cbm_talk(HandleDevice, getCH(), getCL()));
00356
00357 FUNC_LEAVE_BOOLEAN(FALSE);
00358 }
00359
00388 BOOLEAN
00389 vdd_open(CBM_FILE HandleDevice)
00390 {
00391 FUNC_CHECKEDBUFFERACCESS(getSI(), getDI());
00392
00393 CHECKEDBUFFERACCESS(cbm_open(HandleDevice, getCH(), getCL(), buffer, length));
00394 }
00395
00417 BOOLEAN
00418 vdd_close(CBM_FILE HandleDevice)
00419 {
00420 FUNC_ENTER();
00421
00422 retAX(cbm_close(HandleDevice, getCH(), getCL()));
00423
00424 FUNC_LEAVE_BOOLEAN(FALSE);
00425 }
00426
00447 BOOLEAN
00448 vdd_unlisten(CBM_FILE HandleDevice)
00449 {
00450 FUNC_ENTER();
00451
00452 retAX(cbm_unlisten(HandleDevice));
00453
00454 FUNC_LEAVE_BOOLEAN(FALSE);
00455 }
00456
00477 BOOLEAN
00478 vdd_untalk(CBM_FILE HandleDevice)
00479 {
00480 FUNC_ENTER();
00481
00482 retAX(cbm_untalk(HandleDevice));
00483
00484 FUNC_LEAVE_BOOLEAN(FALSE);
00485 }
00486
00487
00508 BOOLEAN
00509 vdd_get_eoi(CBM_FILE HandleDevice)
00510 {
00511 FUNC_ENTER();
00512
00513 retAX(cbm_get_eoi(HandleDevice));
00514
00515 FUNC_LEAVE_BOOLEAN(FALSE);
00516 }
00517
00533 BOOLEAN
00534 vdd_clear_eoi(CBM_FILE HandleDevice)
00535 {
00536 FUNC_ENTER();
00537
00538 retAX(cbm_clear_eoi(HandleDevice));
00539
00540 FUNC_LEAVE_BOOLEAN(FALSE);
00541 }
00542
00564 BOOLEAN
00565 vdd_reset(CBM_FILE HandleDevice)
00566 {
00567 FUNC_ENTER();
00568
00569 retAX(cbm_reset(HandleDevice));
00570
00571 FUNC_LEAVE_BOOLEAN(FALSE);
00572 }
00573
00574
00575
00576
00577
00600 BOOLEAN
00601 vdd_pp_read(CBM_FILE HandleDevice)
00602 {
00603 FUNC_ENTER();
00604
00605 setAX(cbm_pp_read(HandleDevice));
00606
00607 FUNC_LEAVE_BOOLEAN(FALSE);
00608 }
00609
00631 BOOLEAN
00632 vdd_pp_write(CBM_FILE HandleDevice)
00633 {
00634 FUNC_ENTER();
00635
00636 cbm_pp_write(HandleDevice, getCL());
00637
00638 FUNC_LEAVE_BOOLEAN(FALSE);
00639 }
00640
00662 BOOLEAN
00663 vdd_iec_poll(CBM_FILE HandleDevice)
00664 {
00665 FUNC_ENTER();
00666
00667 retAX(cbm_iec_poll(HandleDevice));
00668
00669 FUNC_LEAVE_BOOLEAN(FALSE);
00670 }
00671
00672
00691 BOOLEAN
00692 vdd_iec_set(CBM_FILE HandleDevice)
00693 {
00694 FUNC_ENTER();
00695
00696 cbm_iec_set(HandleDevice, getCL());
00697
00698 FUNC_LEAVE_BOOLEAN(FALSE);
00699 }
00700
00719 BOOLEAN
00720 vdd_iec_release(CBM_FILE HandleDevice)
00721 {
00722 FUNC_ENTER();
00723
00724 cbm_iec_release(HandleDevice, getCL());
00725
00726 FUNC_LEAVE_BOOLEAN(FALSE);
00727 }
00728
00756 BOOLEAN
00757 vdd_iec_setrelease(CBM_FILE HandleDevice)
00758 {
00759 FUNC_ENTER();
00760
00761 cbm_iec_setrelease(HandleDevice, getCH(), getCL());
00762
00763 FUNC_LEAVE_BOOLEAN(FALSE);
00764 }
00765
00792 BOOLEAN
00793 vdd_iec_wait(CBM_FILE HandleDevice)
00794 {
00795 FUNC_ENTER();
00796
00797 retAX(cbm_iec_wait(HandleDevice, getCL(), getCH()));
00798
00799 FUNC_LEAVE_BOOLEAN(FALSE);
00800 }
00801
00823 BOOLEAN
00824 vdd_iec_get(CBM_FILE HandleDevice)
00825 {
00826 FUNC_ENTER();
00827
00828 retAX(cbm_iec_get(HandleDevice, getCL()));
00829
00830 FUNC_LEAVE_BOOLEAN(FALSE);
00831 }
00832
00833
00834
00835
00836
00837
00869 BOOLEAN
00870 vdd_upload(CBM_FILE HandleDevice)
00871 {
00872 FUNC_CHECKEDBUFFERACCESS(getSI(), getCX());
00873
00874 CHECKEDBUFFERACCESS(cbm_upload(HandleDevice, getDH(), getDI(), buffer, length));
00875 }
00876
00912 BOOLEAN
00913 vdd_device_status(CBM_FILE HandleDevice)
00914 {
00915 FUNC_CHECKEDBUFFERACCESS(getSI(), getCX());
00916
00917 CHECKEDBUFFERACCESS(cbm_device_status(HandleDevice, getDH(), buffer, length));
00918 }
00919
00945 BOOLEAN
00946 vdd_exec_command(CBM_FILE HandleDevice)
00947 {
00948 FUNC_CHECKEDBUFFERACCESS(getSI(), getCX());
00949
00950 CHECKEDBUFFERACCESS(cbm_exec_command(HandleDevice, getDH(), buffer, length));
00951 }
00952
00983 BOOLEAN
00984 vdd_identify(CBM_FILE HandleDevice)
00985 {
00986 enum cbm_devicetype_e devicetype;
00987 char *string;
00988
00989 FUNC_CHECKEDBUFFERACCESS(getSI(), getCX());
00990
00991 CHECKEDBUFFERACCESS_PROLOG();
00992
00993 ret = cbm_identify(HandleDevice, getDH(), &devicetype, &string);
00994
00995 setDI(devicetype);
00996 strncpy(buffer, string, length);
00997
00998 CHECKEDBUFFERACCESS_EPILOG();
00999 }
01000
01029 BOOLEAN
01030 vdd_identify_xp1541(CBM_FILE HandleDevice)
01031 {
01032 BOOLEAN error;
01033 enum cbm_devicetype_e devicetype = getDI();
01034 enum cbm_cabletype_e cabletype;
01035
01036 FUNC_ENTER();
01037
01038 devicetype = getDI();
01039 error = cbm_identify_xp1541(HandleDevice, getDH(),
01040 devicetype >= 0 ? &devicetype : NULL,
01041 &cabletype) ? TRUE : FALSE;
01042
01043 setDI(devicetype);
01044 retAX(error);
01045
01046 FUNC_LEAVE_BOOLEAN(error);
01047 }
01048
01049
01050
01051
01052 static CBM_FILE VddCbmFileForIoHook;
01053
01054 static BOOLEAN VddIoHookInstalled = FALSE;
01055 static VDD_IO_PORTRANGE VddIoPortRange;
01056 static VDD_IO_HANDLERS VddIoPortHandlers;
01057
01058 static BYTE vdd_iohook_lastwrittencontrolregister = 0xFF;
01059
01060
01061
01062 #define PP_XE_ATN_OUT 0x01
01063 #define PP_XE_CLK_OUT 0x02
01064 #define PP_XE_RESET_OUT 0x04
01065 #define PP_XE_DATA_OUT 0x08
01066 #define PP_XE_OUTEOR 0x00
01067
01068
01069 #define PP_XE_ATN_IN 0x10
01070 #define PP_XE_CLK_IN 0x20
01071 #define PP_XE_RESET_IN 0x40
01072 #define PP_XE_DATA_IN 0x80
01073
01074
01075
01076 #define PP_XM_ATN_OUT PP_XE_ATN_OUT
01077 #define PP_XM_CLK_OUT PP_XE_CLK_OUT
01078 #define PP_XM_DATA_OUT PP_XE_RESET_OUT
01079 #define PP_XM_RESET_OUT PP_XE_DATA_OUT
01080 #define PP_XM_OUTEOR 0x00
01081
01082
01083 #define PP_XM_ATN_IN PP_XE_ATN_IN
01084 #define PP_XM_CLK_IN PP_XE_CLK_IN
01085 #define PP_XM_DATA_IN PP_XE_RESET_IN
01086 #define PP_XM_RESET_IN PP_XE_DATA_IN
01087
01088
01089
01090 #define PP_XA_ATN_OUT PP_XM_ATN_OUT
01091 #define PP_XA_CLK_OUT PP_XM_CLK_OUT
01092 #define PP_XA_DATA_OUT PP_XM_DATA_OUT
01093 #define PP_XA_RESET_OUT PP_XM_RESET_OUT
01094 #define PP_XA_OUTEOR 0x0F
01095
01096
01097 #define PP_XA_ATN_IN PP_XM_ATN_IN
01098 #define PP_XA_CLK_IN PP_XM_CLK_IN
01099 #define PP_XA_DATA_IN PP_XM_DATA_IN
01100 #define PP_XA_RESET_IN PP_XM_RESET_IN
01101
01102
01103 static unsigned char pp_atn_out;
01104 static unsigned char pp_clk_out;
01105 static unsigned char pp_data_out;
01106 static unsigned char pp_reset_out;
01107 static unsigned char pp_outeor;
01108
01109 static unsigned char pp_atn_in;
01110 static unsigned char pp_clk_in;
01111 static unsigned char pp_data_in;
01112 static unsigned char pp_reset_in;
01113
01114
01115
01116
01117
01118
01119
01120
01121 static VOID
01122 vdd_iohook_inb(WORD iport,BYTE *data)
01123 {
01124 if (iport == VddIoPortRange.First)
01125 {
01126
01127 *data = cbm_pp_read(VddCbmFileForIoHook);
01128 }
01129 else if (iport == VddIoPortRange.First + 1)
01130 {
01131 UINT value;
01132 BYTE ret;
01133
01134
01135 value = cbm_iec_poll(VddCbmFileForIoHook);
01136
01137 ret = 0;
01138
01139 if (value & IEC_DATA)
01140 {
01141 ret |= pp_data_in;
01142 }
01143 if (value & IEC_CLOCK)
01144 {
01145 ret |= pp_clk_in;
01146 }
01147 if (value & IEC_ATN)
01148 {
01149 ret |= pp_atn_in;
01150 }
01151
01152
01153 *data = ret ^ 0x04;
01154 }
01155 else if (iport == VddIoPortRange.First + 2)
01156 {
01157
01158 *data = vdd_iohook_lastwrittencontrolregister & 0xDF | 0xC0;
01159 }
01160 else DBG_ERROR((DBG_PREFIX "Access to unknown address %08x", iport));
01161 }
01162
01163 static VOID
01164 vdd_iohook_outb(WORD iport,BYTE data)
01165 {
01166 if (iport == VddIoPortRange.First)
01167 {
01168
01169 cbm_pp_write(VddCbmFileForIoHook, data);
01170 }
01171 else if (iport == VddIoPortRange.First + 1)
01172 {
01173 DBG_ERROR((DBG_PREFIX "Writing the status register: UNSUPPORTED!"));
01174 }
01175 else if (iport == VddIoPortRange.First + 2)
01176 {
01177
01178
01179 #ifdef NEW_IMPLEMENTATION_WITH_SETRELEASE
01180
01181 BYTE release = IEC_ATN | IEC_CLOCK | IEC_DATA | IEC_RESET;
01182 BYTE set = 0;
01183
01184 vdd_iohook_lastwrittencontrolregister = data;
01185
01186 data ^= 0x04 ^ pp_outeor;
01187
01188 if (data & pp_atn_out) { set |= IEC_ATN; release &= ~IEC_ATN; }
01189 if (data & pp_data_out) { set |= IEC_DATA; release &= ~IEC_DATA; }
01190 if (data & pp_clk_out) { set |= IEC_CLOCK; release &= ~IEC_CLOCK; }
01191 if (data & pp_reset_out) { set |= IEC_RESET; release &= ~IEC_RESET; }
01192
01193 #ifdef TEST_BIDIR
01194
01195 if (data & 0x10)
01196 {
01197 set |= 0x10;
01198 }
01199 else
01200 {
01201 release |= 0x10;
01202 }
01203
01204 #endif // #ifdef TEST_BIDIR
01205
01206 cbm_iec_setrelease(VddCbmFileForIoHook, set, release);
01207
01208 #else // #ifdef NEW_IMPLEMENTATION_WITH_SETRELEASE
01209
01210 BYTE ret = data ^ vdd_iohook_lastwrittencontrolregister;
01211
01212 vdd_iohook_lastwrittencontrolregister = data;
01213
01214 data ^= 0x04 ^ pp_outeor;
01215
01216 if (ret & pp_atn_out)
01217 {
01218
01219 ((data & pp_atn_out) ? cbm_iec_set : cbm_iec_release)
01220 (VddCbmFileForIoHook, IEC_ATN);
01221 }
01222 if (ret & pp_clk_out)
01223 {
01224
01225 ((data & pp_clk_out) ? cbm_iec_set : cbm_iec_release)
01226 (VddCbmFileForIoHook, IEC_CLOCK);
01227 }
01228 if (ret & pp_data_out)
01229 {
01230
01231 ((data & pp_data_out) ? cbm_iec_set : cbm_iec_release)
01232 (VddCbmFileForIoHook, IEC_DATA);
01233 }
01234 if (ret & pp_reset_out)
01235 {
01236
01237 if (data & pp_reset_out)
01238 {
01239 cbm_reset(VddCbmFileForIoHook);
01240 }
01241 }
01242
01243 #endif // #ifdef NEW_IMPLEMENTATION_WITH_SETRELEASE
01244
01245 }
01246 else DBG_ERROR((DBG_PREFIX "Access to unknown address %08x", iport));
01247 }
01248
01249
01273 BOOLEAN
01274 vdd_install_iohook(CBM_FILE HandleDevice)
01275 {
01276 BOOLEAN error;
01277
01278 FUNC_ENTER();
01279
01280 error = FALSE;
01281
01282
01283
01284
01285 setAX(0);
01286
01287 if (!VddIoHookInstalled)
01288 {
01289 VddIoPortRange.First = getCX();
01290 VddIoPortRange.Last = VddIoPortRange.First + 2;
01291
01292 RtlZeroMemory(&VddIoPortHandlers, sizeof(VddIoPortHandlers));
01293 VddIoPortHandlers.inb_handler = vdd_iohook_inb;
01294 VddIoPortHandlers.outb_handler = vdd_iohook_outb;
01295
01296 if (VDDInstallIOHook(vdd_handle, 1, &VddIoPortRange, &VddIoPortHandlers))
01297 {
01298
01299 VddIoHookInstalled = TRUE;
01300 setAX(VddIoPortRange.First);
01301
01302 VddCbmFileForIoHook = HandleDevice;
01303
01304
01305
01306 switch (getDH())
01307 {
01308 case 1:
01309 pp_atn_out = PP_XE_ATN_OUT;
01310 pp_clk_out = PP_XE_CLK_OUT;
01311 pp_data_out = PP_XE_DATA_OUT;
01312 pp_reset_out = PP_XE_RESET_OUT;
01313 pp_outeor = PP_XE_OUTEOR;
01314 pp_atn_in = PP_XE_ATN_IN;
01315 pp_clk_in = PP_XE_CLK_IN;
01316 pp_data_in = PP_XE_DATA_IN;
01317 pp_reset_in = PP_XE_RESET_IN;
01318 break;
01319
01320 case 2:
01321 pp_atn_out = PP_XM_ATN_OUT;
01322 pp_clk_out = PP_XM_CLK_OUT;
01323 pp_data_out = PP_XM_DATA_OUT;
01324 pp_reset_out = PP_XM_RESET_OUT;
01325 pp_outeor = PP_XM_OUTEOR;
01326 pp_atn_in = PP_XM_ATN_IN;
01327 pp_clk_in = PP_XM_CLK_IN;
01328 pp_data_in = PP_XM_DATA_IN;
01329 pp_reset_in = PP_XM_RESET_IN;
01330 break;
01331
01332 case 3:
01333 pp_atn_out = PP_XA_ATN_OUT;
01334 pp_clk_out = PP_XA_CLK_OUT;
01335 pp_data_out = PP_XA_DATA_OUT;
01336 pp_reset_out = PP_XA_RESET_OUT;
01337 pp_outeor = PP_XA_OUTEOR;
01338 pp_atn_in = PP_XA_ATN_IN;
01339 pp_clk_in = PP_XA_CLK_IN;
01340 pp_data_in = PP_XA_DATA_IN;
01341 pp_reset_in = PP_XA_RESET_IN;
01342 break;
01343
01344 default:
01345 error = TRUE;
01346 break;
01347 }
01348 }
01349 }
01350
01351 FUNC_LEAVE_BOOLEAN(error);
01352 }
01353
01371 USHORT
01372 vdd_uninstall_iohook_internal(VOID)
01373 {
01374 USHORT ret;
01375
01376 FUNC_ENTER();
01377
01378 if (VddIoHookInstalled)
01379 {
01380 VDDDeInstallIOHook(vdd_handle, 1, &VddIoPortRange);
01381
01382 VddIoHookInstalled = FALSE;
01383 ret = VddIoPortRange.First;
01384 }
01385 else
01386 {
01387 ret = 0;
01388 }
01389
01390 FUNC_LEAVE_USHORT(ret);
01391 }
01392
01410 BOOLEAN
01411 vdd_uninstall_iohook(CBM_FILE HandleDevice)
01412 {
01413 FUNC_ENTER();
01414
01415 DBG_PRINT((DBG_PREFIX "Entering vdd_uninstall_iohook"));
01416
01417 setAX(vdd_uninstall_iohook_internal());
01418
01419 FUNC_LEAVE_BOOLEAN(FALSE);
01420 }
01421
01435 BOOLEAN
01436 vdd_usleep(VOID)
01437 {
01438 FUNC_ENTER();
01439
01440 arch_usleep(getCX());
01441
01442 FUNC_LEAVE_BOOLEAN(FALSE);
01443 }