Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1679 lines
47 KiB

  1. //**************************************************************************
  2. //
  3. // SW3DPRO.C -- Xena Gaming Project
  4. //
  5. // Version 3.XX
  6. //
  7. // Copyright (c) 1997 Microsoft Corporation. All rights reserved.
  8. //
  9. // @doc
  10. // @module SW3DPRO.C | Gameport mini-driver for Sidewinder Pro
  11. //**************************************************************************
  12. #ifndef SAITEK
  13. #include "msgame.h"
  14. //---------------------------------------------------------------------------
  15. // Definitions
  16. //---------------------------------------------------------------------------
  17. #define DEVICENAME "SW3DPRO"
  18. #define DEVICE_PID 0x0f1f
  19. #define HARDWARE_ID L"Gameport\\SideWinder3DPro\0\0"
  20. //
  21. // Packet Constants
  22. //
  23. #define GAME_PACKET_SIZE 8
  24. #define GAME_PACKET_BUTTONS 8
  25. #define GAME_PACKET_AXIS 4
  26. #define GAME_PHASE_BYTE 0 // Packet[0] bits
  27. #define GAME_PHASE_BIT 0x80
  28. #define GAME_H3_BYTE 0
  29. #define GAME_H3_BITS 0x40
  30. #define GAME_X7_X9_BYTE 0
  31. #define GAME_X7_X9_BITS 0x38
  32. #define GAME_Y7_Y9_BYTE 0
  33. #define GAME_Y7_Y9_BITS 0x07
  34. #define GAME_B0_B6_BYTE 1 // Packet[1] bits
  35. #define GAME_B0_B6_BITS 0x7f
  36. #define GAME_X0_X6_BYTE 2 // Packet[2] bits
  37. #define GAME_X0_X6_BITS 0x7f
  38. #define GAME_Y0_Y6_BYTE 3 // Packet[3] bits
  39. #define GAME_Y0_Y6_BITS 0x7f
  40. #define GAME_B7_BYTE 4 // Packet[4] bits
  41. #define GAME_B7_BITS 0x40
  42. #define TM_MODE_BYTE 4
  43. #define TM_MODE_BITS 0x20
  44. #define GAME_R7_R8_BYTE 4
  45. #define GAME_R7_R8_BITS 0x18
  46. #define GAME_T7_T9_BYTE 4
  47. #define GAME_T7_T9_BITS 0x07
  48. #define GAME_R0_R6_BYTE 5 // Packet[5] bits
  49. #define GAME_R0_R6_BITS 0x7f
  50. #define GAME_T0_T6_BYTE 6 // Packet[6] bits
  51. #define GAME_T0_T6_BITS 0x7f
  52. #define GAME_H0_H2_BYTE 7 // Packet[7] bits
  53. #define GAME_H0_H2_BITS 0x70
  54. #define GAME_C0_C3_BYTE 7
  55. #define GAME_C0_C3_BITS 0x0f
  56. #define ENH_CLOCK_MIDPACKET 0x00000400
  57. #define ENH_CLOCK_COMPLETE 0x00200000
  58. //
  59. // Id Definitions
  60. //
  61. #define GAME_ID_CLOCKS 32
  62. #define GAME_ID_STRING "(\1\x24P"
  63. //
  64. // Timing Constants
  65. //
  66. #define PACKET_START_TIMEOUT 500
  67. #define PACKET_LOWHIGH_TIMEOUT 75
  68. #define PACKET_HIGHLOW_TIMEOUT 150
  69. #define PACKET_INTERRUPT_DELAY 30
  70. #define ID_START_TIMEOUT 500
  71. #define ID_LOWHIGH_TIMEOUT 75
  72. #define ID_HIGHLOW_TIMEOUT 150
  73. #define MAX_CLOCK_DUTY_CYCLE 50
  74. #define GODIGITAL_ATTEMPTS 10
  75. #define RECALIBRATE_FAIL_COUNT (GODIGITAL_ATTEMPTS/2)
  76. //
  77. // Joystick Extents
  78. //
  79. #define EXTENTS_X_MIN 0
  80. #define EXTENTS_X_MAX 0xff
  81. #define EXTENTS_Y_MIN 0
  82. #define EXTENTS_Y_MAX 0xff
  83. #define EXTENTS_T_MIN 0
  84. #define EXTENTS_T_MAX 0xff
  85. #define EXTENTS_R_MIN 0
  86. #define EXTENTS_R_MAX 0x3f
  87. //---------------------------------------------------------------------------
  88. // Types
  89. //---------------------------------------------------------------------------
  90. typedef struct
  91. { // @struct SW3DPRO_ID | Sidwinder Pro Id String
  92. #pragma pack(1)
  93. UCHAR EnumId[3]; // @field Enumerated Id
  94. UCHAR EisaId[8]; // @field Eisa bus Id
  95. UCHAR Devices; // @field Number of devices
  96. USHORT Version[7]; // @field Firmware version
  97. UCHAR EndOfStr; // @field ID string terminator
  98. #pragma pack()
  99. } SW3DPRO_ID, *PSW3DPRO_ID;
  100. //---------------------------------------------------------------------------
  101. // Macros
  102. //---------------------------------------------------------------------------
  103. #define LOW_NIBBLE(c) ((c)&GAME_C0_C3_BITS)
  104. #define HIGH_NIBBLE(c) (((c)&(GAME_C0_C3_BITS<<4))>>4)
  105. //---------------------------------------------------------------------------
  106. // Procedures
  107. //---------------------------------------------------------------------------
  108. static VOID SW3DPRO_Calibrate (PGAMEPORT PortInfo);
  109. static BOOLEAN SW3DPRO_ResetDevice (PGAMEPORT PortInfo);
  110. static BOOLEAN SW3DPRO_GoDigital (PPACKETINFO IdPacket, ULONG Sequence[]);
  111. static LONG SW3DPRO_InterruptPacket (PGAMEPORT PortInfo);
  112. static BOOLEAN SW3DPRO_ReadId (PPACKETINFO IdPacket);
  113. static BOOLEAN SW3DPRO_GetId (PPACKETINFO IdPacket);
  114. static NTSTATUS SW3DPRO_ReadData (PPACKETINFO DataPacket);
  115. static BOOLEAN SW3DPRO_Read1Wide (PPACKETINFO DataPacket);
  116. static BOOLEAN SW3DPRO_Read3Wide (PPACKETINFO DataPacket);
  117. static BOOLEAN SW3DPRO_ValidateData (PUCHAR Packet);
  118. static VOID SW3DPRO_ProcessData (UCHAR Data[], PDEVICE_PACKET Report);
  119. //---------------------------------------------------------------------------
  120. // Services
  121. //---------------------------------------------------------------------------
  122. static NTSTATUS SW3DPRO_DriverEntry (VOID);
  123. static NTSTATUS SW3DPRO_ConnectDevice (PGAMEPORT PortInfo);
  124. static NTSTATUS SW3DPRO_StartDevice (PGAMEPORT PortInfo);
  125. static NTSTATUS SW3DPRO_ReadReport (PGAMEPORT PortInfo, PDEVICE_PACKET Report);
  126. static NTSTATUS SW3DPRO_StopDevice (PGAMEPORT PortInfo, BOOLEAN TouchHardware);
  127. //---------------------------------------------------------------------------
  128. // Alloc_text pragma to specify routines that can be paged out.
  129. //---------------------------------------------------------------------------
  130. #ifdef ALLOC_PRAGMA
  131. #pragma alloc_text (INIT, SW3DPRO_DriverEntry)
  132. #endif
  133. //---------------------------------------------------------------------------
  134. // Private Data
  135. //---------------------------------------------------------------------------
  136. //
  137. // HID Descriptors
  138. //
  139. static UCHAR ReportDescriptor[] =
  140. {
  141. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_GENERIC, // USAGE_PAGE (Generic Desktop)
  142. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  143. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_APP, // COLLECTION (Application)
  144. //id
  145. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  146. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  147. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  148. //do_other
  149. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  150. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  151. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  152. //dwX / dwY
  153. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_POINTER, // USAGE (Pointer)
  154. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Linked)
  155. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  156. HIDP_GLOBAL_LOG_MAX_4, 0xFF, 0x03, 0x00, 0x00, // LOGICAL_MAXIMUM (1023)
  157. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  158. HIDP_GLOBAL_PHY_MAX_4, 0xFF, 0x03, 0x00, 0x00, // PHYSICAL_MAXIMUM (1023)
  159. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  160. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  161. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  162. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_X, // USAGE (X)
  163. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  164. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_Y, // USAGE (X)
  165. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  166. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  167. //dwZ
  168. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_SIMULATION, // USAGE_PAGE (Simulation Controls)
  169. HIDP_LOCAL_USAGE_1, HID_USAGE_SIMULATION_THROTTLE,// USAGE (Throttle)
  170. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  171. HIDP_GLOBAL_LOG_MAX_4, 0xFF, 0x03, 0x00, 0x00, // LOGICAL_MAXIMUM (1023)
  172. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  173. HIDP_GLOBAL_PHY_MAX_4, 0xFF, 0x03, 0x00, 0x00, // PHYSICAL_MAXIMUM (1023)
  174. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  175. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  176. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  177. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  178. //dwR
  179. HIDP_LOCAL_USAGE_1, HID_USAGE_SIMULATION_RUDDER, // USAGE (Rudder)
  180. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  181. HIDP_GLOBAL_LOG_MAX_4, 0xFF, 0x01, 0x00, 0x00, // LOGICAL_MAXIMUM (511)
  182. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  183. HIDP_GLOBAL_PHY_MAX_4, 0xFF, 0x01, 0x00, 0x00, // PHYSICAL_MAXIMUM (511)
  184. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  185. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  186. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  187. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  188. //dwU
  189. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  190. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  191. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  192. //dwV
  193. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  194. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  195. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  196. //dwPOV
  197. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_GENERIC, // USAGE_PAGE (Generic Desktop)
  198. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_HATSWITCH, // USAGE (Hat switch)
  199. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  200. HIDP_GLOBAL_LOG_MAX_4, 0x9F, 0x8C, 0x00, 0x00, // LOGICAL_MAXIMUM (35999)
  201. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  202. HIDP_GLOBAL_PHY_MAX_4, 0x9f, 0x8C, 0x00, 0x00, // PHYSICAL_MAXIMUM (35999)
  203. HIDP_GLOBAL_UNIT_2, 0x14, 0x00, // Unit (English Rot:Angular Pos)
  204. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  205. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  206. HIDP_MAIN_INPUT_1, 0x42, // Input (Data,Var,Abs,Null)
  207. //dwButtons
  208. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_BUTTON, // USAGE_PAGE (Button)
  209. HIDP_LOCAL_USAGE_MIN_1, 0x01, // USAGE_MINIMUM (Button 1)
  210. HIDP_LOCAL_USAGE_MAX_1, 0x08, // USAGE_MAXIMUM (Button 8)
  211. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  212. HIDP_GLOBAL_LOG_MAX_1, 0x01, // LOGICAL_MAXIMUM (1)
  213. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  214. HIDP_GLOBAL_PHY_MAX_1, 0x01, // PHYSICAL_MAXIMUM (1)
  215. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  216. HIDP_GLOBAL_REPORT_SIZE, 0x01, // REPORT_SIZE (1)
  217. HIDP_GLOBAL_REPORT_COUNT_1,0x20, // REPORT_COUNT (32)
  218. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  219. //dwButtonNumber
  220. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  221. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  222. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  223. //END OF COLLECTION
  224. HIDP_MAIN_ENDCOLLECTION // END_COLLECTION
  225. };
  226. static HID_DESCRIPTOR DeviceDescriptor =
  227. {
  228. sizeof (HID_DESCRIPTOR),
  229. HID_HID_DESCRIPTOR_TYPE,
  230. MSGAME_HID_VERSION,
  231. MSGAME_HID_COUNTRY,
  232. MSGAME_HID_DESCRIPTORS,
  233. {HID_REPORT_DESCRIPTOR_TYPE,
  234. sizeof(ReportDescriptor)}
  235. };
  236. //
  237. // Raw Data Buffer
  238. //
  239. static UCHAR RawData[GAME_PACKET_SIZE] =
  240. { // no buttons; x, y, t and r centered
  241. GAME_PHASE_BIT|((GAME_X7_X9_BITS>>1)&GAME_X7_X9_BITS)|((GAME_Y7_Y9_BITS>>1)&GAME_Y7_Y9_BITS),
  242. GAME_B0_B6_BITS,
  243. GAME_X0_X6_BITS,
  244. GAME_Y0_Y6_BITS,
  245. ((GAME_R7_R8_BITS>>1)&GAME_R7_R8_BITS)|((GAME_T7_T9_BITS>>1)&GAME_T7_T9_BITS)|GAME_B7_BITS,
  246. GAME_R0_R6_BITS,
  247. GAME_T0_T6_BITS,
  248. 0
  249. };
  250. //
  251. // Raw Id Buffer
  252. //
  253. static SW3DPRO_ID RawId =
  254. {
  255. 0
  256. };
  257. //
  258. // Timing Variables
  259. //
  260. static DEVICE_VALUES Delays =
  261. {
  262. PACKET_START_TIMEOUT,
  263. PACKET_HIGHLOW_TIMEOUT,
  264. PACKET_LOWHIGH_TIMEOUT,
  265. ID_START_TIMEOUT,
  266. ID_HIGHLOW_TIMEOUT,
  267. ID_LOWHIGH_TIMEOUT,
  268. PACKET_INTERRUPT_DELAY,
  269. MAX_CLOCK_DUTY_CYCLE,
  270. 0,0,0,0 // No status packet used
  271. };
  272. //
  273. // Data Packet Info
  274. //
  275. static PACKETINFO DataInfo =
  276. {
  277. sizeof (PACKETINFO), // Size of structure
  278. DEVICENAME, // Name of device
  279. MSGAME_TRANSACT_NONE, // Transaction type
  280. IMODE_DIGITAL_STD, // Interface mode
  281. GAME_SPEED_100K, // Transmission speed
  282. ERROR_SUCCESS, // Last internal error result
  283. {0}, // Game port info
  284. 0, // Packet acquisition mode
  285. 1, // Number of packets received
  286. 0, // Last valid acquisition time stamp
  287. 0, // Number of clocks sampled
  288. 0, // Number of B4 line transitions (std mode only)
  289. 0, // Start timeout period (in samples)
  290. 0, // Clock High to Low timeout period (in samples)
  291. 0, // Clock Low to High timeout period (in samples)
  292. 0, // Interrupt Timeout period
  293. 0, // Maximum clock duty cycle
  294. 0, // Number of Packet Failures
  295. 0, // Number of Packet Attempts
  296. sizeof (RawData), // Size of raw data buffer
  297. RawData // Pointer to Raw data
  298. };
  299. //
  300. // ID Packet Info
  301. //
  302. static PACKETINFO IdInfo =
  303. {
  304. sizeof (PACKETINFO), // Size of structure
  305. DEVICENAME, // Name of device
  306. MSGAME_TRANSACT_NONE, // Transaction type
  307. IMODE_DIGITAL_STD, // Interface mode
  308. GAME_SPEED_100K, // Transmission speed
  309. ERROR_SUCCESS, // Last internal error result
  310. {0}, // Game port info
  311. 0, // Packet acquisition mode
  312. 1, // Number of packets received
  313. 0, // Last valid acquisition time stamp
  314. 0, // Number of clocks sampled
  315. 0, // Number of B4 line transitions (std mode only)
  316. 0, // Start timeout period (in samples)
  317. 0, // Clock High to Low timeout period (in samples)
  318. 0, // Clock Low to High timeout period (in samples)
  319. 0, // Interrupt Timeout period
  320. 0, // Maximum clock duty cycle
  321. 0, // Number of Packet Failures
  322. 0, // Number of Packet Attempts
  323. sizeof (RawId), // Size of raw id buffer
  324. &RawId // Pointer to Raw data
  325. };
  326. //
  327. // Services Table
  328. //
  329. static DRIVERSERVICES Services =
  330. {
  331. SW3DPRO_DriverEntry, // DriverEntry
  332. SW3DPRO_ConnectDevice, // ConnectDevice
  333. SW3DPRO_StartDevice, // StartDevice
  334. SW3DPRO_ReadReport, // ReadReport
  335. SW3DPRO_StopDevice, // StopDevice
  336. NULL // GetFeature
  337. };
  338. //
  339. // Last Valid Data
  340. //
  341. static UCHAR ValidData[GAME_PACKET_SIZE] =
  342. { // no buttons; x, y, t and r centered
  343. GAME_PHASE_BIT|((GAME_X7_X9_BITS>>1)&GAME_X7_X9_BITS)|((GAME_Y7_Y9_BITS>>1)&GAME_Y7_Y9_BITS),
  344. GAME_B0_B6_BITS,
  345. GAME_X0_X6_BITS,
  346. GAME_Y0_Y6_BITS,
  347. ((GAME_R7_R8_BITS>>1)&GAME_R7_R8_BITS)|((GAME_T7_T9_BITS>>1)&GAME_T7_T9_BITS)|GAME_B7_BITS,
  348. GAME_R0_R6_BITS,
  349. GAME_T0_T6_BITS,
  350. 0
  351. };
  352. //
  353. // Go Digital Timing Data
  354. //
  355. static ULONG GoDigitalFastTiming[] =
  356. {
  357. T1+60,
  358. T2+60,
  359. T3+60
  360. };
  361. static ULONG GoDigitalMediumTiming[] =
  362. {
  363. T1,
  364. T2,
  365. T3
  366. };
  367. static ULONG GoDigitalSlowTiming[] =
  368. {
  369. T1-20,
  370. T2-20,
  371. T3-20
  372. };
  373. static ULONG GoDigitalFails = 0;
  374. //
  375. // Hardware ID String
  376. //
  377. static WCHAR HardwareId[] = HARDWARE_ID;
  378. //---------------------------------------------------------------------------
  379. // Public Data
  380. //---------------------------------------------------------------------------
  381. public DEVICEINFO MidasInfo =
  382. {
  383. &Services, // Service table
  384. NULL, // Sibling device list
  385. &DeviceDescriptor, // Device descriptor data
  386. ReportDescriptor, // Report descriptor data
  387. sizeof(ReportDescriptor), // Report descriptor size
  388. 0, // Number of devices detected
  389. 0, // Number of devices started
  390. 0, // Number of devices pending
  391. DEVICENAME, // Name of device
  392. DETECT_NORMAL, // Detection order
  393. TRUE, // Analog device flag
  394. DEVICE_PID, // Hid device identifier
  395. HardwareId // PnP hardware identifier
  396. };
  397. //---------------------------------------------------------------------------
  398. // @func Reads registry timing values and calibrates them
  399. // @parm PGAMEPORT | PortInfo | Gameport parameters
  400. // @rdesc Returns nothing
  401. // @comm Private function
  402. //---------------------------------------------------------------------------
  403. VOID SW3DPRO_Calibrate (PGAMEPORT PortInfo)
  404. {
  405. MsGamePrint((DBG_INFORM,"SW3DPRO: SW3DPRO_Calibrate Enter\n"));
  406. //
  407. // Convert timing values to counts
  408. //
  409. DataInfo.StartTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketStartTimeout);
  410. MsGamePrint((DBG_VERBOSE, "SW3DPRO: DataInfo.StartTimeout = %ld\n", DataInfo.StartTimeout));
  411. DataInfo.LowHighTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketLowHighTimeout);
  412. MsGamePrint((DBG_VERBOSE, "SW3DPRO: DataInfo.LowHighTimeout = %ld\n", DataInfo.LowHighTimeout));
  413. DataInfo.HighLowTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketHighLowTimeout);
  414. MsGamePrint((DBG_VERBOSE, "SW3DPRO: DataInfo.HighLowTimeout = %ld\n", DataInfo.HighLowTimeout));
  415. IdInfo.StartTimeout = TIMER_CalibratePort (PortInfo, Delays.IdStartTimeout);
  416. MsGamePrint((DBG_VERBOSE, "SW3DPRO: IdInfo.StartTimeout = %ld\n", IdInfo.StartTimeout));
  417. IdInfo.LowHighTimeout = TIMER_CalibratePort (PortInfo, Delays.IdLowHighTimeout);
  418. MsGamePrint((DBG_VERBOSE, "SW3DPRO: IdInfo.LowHighTimeout=%ld\n", IdInfo.LowHighTimeout));
  419. IdInfo.HighLowTimeout = TIMER_CalibratePort (PortInfo, Delays.IdHighLowTimeout);
  420. MsGamePrint((DBG_VERBOSE, "SW3DPRO: IdInfo.HighLowTimeout=%ld\n", IdInfo.HighLowTimeout));
  421. DataInfo.ClockDutyCycle = TIMER_CalibratePort (PortInfo, Delays.MaxClockDutyCycle);
  422. MsGamePrint((DBG_VERBOSE, "SW3DPRO: DataInfo.ClockDutyCycle = %ld\n", DataInfo.ClockDutyCycle));
  423. IdInfo.ClockDutyCycle = TIMER_CalibratePort (PortInfo, Delays.MaxClockDutyCycle);
  424. MsGamePrint((DBG_VERBOSE, "SW3DPRO: IdInfo.ClockDutyCycle = %ld\n", IdInfo.ClockDutyCycle));
  425. DataInfo.InterruptDelay = Delays.InterruptDelay;
  426. MsGamePrint((DBG_VERBOSE, "SW3DPRO: DataInfo.InterruptDelay = %ld\n", DataInfo.InterruptDelay));
  427. IdInfo.InterruptDelay = Delays.InterruptDelay;
  428. MsGamePrint((DBG_VERBOSE, "SW3DPRO: IdInfo.InterruptDelay = %ld\n", IdInfo.InterruptDelay));
  429. }
  430. //---------------------------------------------------------------------------
  431. // @func Resets device to known state
  432. // @parm PGAMEPORT | PortInfo | Gameport parameters
  433. // @rdesc True if successful, False otherwise
  434. // @comm Private function
  435. //---------------------------------------------------------------------------
  436. BOOLEAN SW3DPRO_ResetDevice (PGAMEPORT PortInfo)
  437. {
  438. LONG Result;
  439. MsGamePrint ((DBG_INFORM, "SW3DPRO_ResetDevice enter\n"));
  440. if (!PORTIO_AcquirePort (PortInfo))
  441. return (FALSE);
  442. PORTIO_MaskInterrupts ();
  443. DataInfo.Mode = IdInfo.Mode = IMODE_ANALOG;
  444. PORTIO_Write (PortInfo, 0);
  445. Result = SW3DPRO_InterruptPacket (PortInfo);
  446. if (Result == ERROR_SUCCESS)
  447. Result = SW3DPRO_InterruptPacket (PortInfo);
  448. if (Result != ERROR_SUCCESS)
  449. MsGamePrint ((DBG_SEVERE, "SW3DPRO_ResetDevice - InterruptPacket failed\n"));
  450. DataInfo.LastError = Result;
  451. DataInfo.Transaction = MSGAME_TRANSACT_RESET;
  452. PORTIO_UnMaskInterrupts ();
  453. PORTIO_ReleasePort (PortInfo);
  454. MSGAME_PostTransaction (&DataInfo);
  455. return (!Result);
  456. }
  457. //---------------------------------------------------------------------------
  458. // @func Interrupts device during packet transfer
  459. // @parm PGAMEPORT | PortInfo | Gameport parameters
  460. // @rdesc Internal result
  461. // @comm Private function
  462. //---------------------------------------------------------------------------
  463. LONG SW3DPRO_InterruptPacket (PGAMEPORT PortInfo)
  464. {
  465. LONG Clks;
  466. LONG Result;
  467. __asm
  468. {
  469. push edi
  470. push esi
  471. lea edx, IdInfo.PortInfo ; load gameport adddress
  472. mov ebx, 64 ; Standard Mode = 64 clks.
  473. Int_CheckState:
  474. push edx ; read byte from gameport
  475. call PORTIO_Read
  476. test al, CLOCK_BIT_MASK ; Q: Clock = 0 ?
  477. jz Int_ClockRise ; Y: jump
  478. ;Int_ClockFall:
  479. mov ecx, TIMEOUT
  480. Int_ClockFall_1:
  481. test al, CLOCK_BIT_MASK ; Q: clock = 0
  482. jz Int_ClockRise ; Y: jump - look for rising edge
  483. push edx ; read byte from gameport
  484. call PORTIO_Read
  485. dec ecx
  486. jnz Int_ClockFall_1 ; else see if we timed out
  487. mov eax, ERROR_CLOCKFALLING
  488. jmp IntPacketComplete ; Time out error.
  489. Int_ClockRise:
  490. mov ecx, TIMEOUT
  491. Int_ClockRise_1:
  492. test al, CLOCK_BIT_MASK ; Q: clock high ?
  493. jnz Int_Transition ; Y: jump. (transition)
  494. push edx ; read byte from gameport
  495. call PORTIO_Read
  496. dec ecx
  497. jnz Int_ClockRise_1 ; else see if we timed out
  498. mov eax, ERROR_CLOCKRISING
  499. jmp IntPacketComplete ; Time out error.
  500. Int_Transition:
  501. cmp bl, 14 ; Q: 14 clocks left ?
  502. jne Int_Transition_1 ; N: jump.
  503. push 0 ; write byte to gameport
  504. push edx
  505. call PORTIO_Write
  506. Int_Transition_1:
  507. dec bl
  508. jnz Int_CheckState
  509. mov eax, ERROR_SUCCESS
  510. IntPacketComplete:
  511. mov Result, eax
  512. mov Clks, ebx
  513. pop esi
  514. pop edi
  515. }
  516. #if (DBG==1)
  517. switch (Result)
  518. {
  519. case ERROR_CLOCKFALLING:
  520. MsGamePrint ((DBG_SEVERE, "SW3DPRO_InterruptPacket - TimeOut@ClockFalling, Clk=%ld\n", Clks));
  521. break;
  522. case ERROR_CLOCKRISING:
  523. MsGamePrint ((DBG_SEVERE, "SW3DPRO_InterruptPacket - TimeOut@ClockRising, Clk=%ld\n", Clks));
  524. break;
  525. }
  526. #endif
  527. return (Result);
  528. }
  529. //---------------------------------------------------------------------------
  530. // @func Puts device into digital mode
  531. // @parm PPACKETINFO | IdPacket | ID Packet parameters
  532. // @rdesc True if successful, False otherwise
  533. // @comm Private function
  534. //---------------------------------------------------------------------------
  535. BOOLEAN SW3DPRO_GoDigital (PPACKETINFO IdPacket, ULONG Sequence[])
  536. {
  537. LONG i;
  538. ULONG ThreeMilliSecs;
  539. ULONG GoDigitalTiming[3];
  540. LONG Result = ERROR_SUCCESS;
  541. ULONG Attempts = MAX_CONNECT_ATTEMPTS;
  542. PGAMEPORT PortInfo = &IdPacket->PortInfo;
  543. MsGamePrint ((DBG_INFORM, "SW3DPRO_GoDigital enter\n"));
  544. do
  545. {
  546. for (i = 0; i < 3; i++)
  547. GoDigitalTiming[i] = TIMER_GetDelay (Sequence[i]);
  548. ThreeMilliSecs = TIMER_GetDelay (THREE_MILLI_SECS);
  549. if (GoDigitalFails > RECALIBRATE_FAIL_COUNT)
  550. TIMER_Calibrate ();
  551. if (!PORTIO_AcquirePort (PortInfo))
  552. continue;
  553. PORTIO_MaskInterrupts ();
  554. PORTIO_Write (PortInfo, 0);
  555. __asm
  556. {
  557. push edi
  558. push esi
  559. mov edx, PortInfo ; load gameport adddress
  560. mov ecx, MAX_XA_TIMEOUT
  561. xor ebx, ebx
  562. WaitXA:
  563. push edx ; read byte from gameport
  564. call PORTIO_Read
  565. test al, INTXA_BIT_MASK ; Q: X axis low ?
  566. jz XA_Done ; Y: jump. (complete)
  567. xor bh, al ; Q: Clock transition ?
  568. test bh, CLOCK_BIT_MASK
  569. jz WaitXA_1 ; N: jump.
  570. inc bl ; inc. clock transition count.
  571. WaitXA_1:
  572. mov bh, al
  573. dec ecx
  574. jnz WaitXA
  575. jmp DigitalSwitchFail
  576. XA_Done:
  577. cmp bl, 3 ; Q: Already in Digital mode ?
  578. ja DigitalSwitchDone ; Y: jump.
  579. xor edi, edi
  580. mov esi, edx
  581. DigitalSwitchLoop:
  582. push GoDigitalTiming[edi]
  583. add edi, 4 ; inc loop counter & index
  584. call TIMER_DelayMicroSecs
  585. mov edx, esi
  586. push 0 ; write byte to gameport
  587. push edx
  588. call PORTIO_Write
  589. push edx
  590. call PORTIO_WaitXA_HighLow ; Wait for XA to transition
  591. or al, al
  592. je DigitalSwitchFail ; if Timeout then fail.
  593. cmp edi, 12
  594. jl DigitalSwitchLoop
  595. push ThreeMilliSecs
  596. call TIMER_DelayMicroSecs ; Delay so Firmware can update
  597. jmp DigitalSwitchDone
  598. DigitalSwitchFail:
  599. mov Result, ERROR_XA_TIMEOUT
  600. DigitalSwitchDone:
  601. pop esi
  602. pop edi
  603. }
  604. IdPacket->TimeStamp = TIMER_GetTickCount ();
  605. IdPacket->LastError = Result;
  606. IdPacket->Transaction = MSGAME_TRANSACT_GODIGITAL;
  607. PORTIO_UnMaskInterrupts ();
  608. PORTIO_ReleasePort (PortInfo);
  609. if (Result == ERROR_SUCCESS)
  610. {
  611. GoDigitalFails = 0;
  612. break;
  613. }
  614. else GoDigitalFails++;
  615. if (Result == ERROR_XA_TIMEOUT)
  616. MsGamePrint ((DBG_SEVERE, "SW3DPRO_GoDigital - TimeOut@XAHighLow\n"));
  617. } while(--Attempts);
  618. MSGAME_PostTransaction (IdPacket);
  619. return (!Result);
  620. }
  621. //---------------------------------------------------------------------------
  622. // @func Reads device id string from port
  623. // @parm PPACKETINFO | IdPacket | ID Packet parameters
  624. // @rdesc True if successful, False otherwise
  625. // @comm Private function
  626. //---------------------------------------------------------------------------
  627. BOOLEAN SW3DPRO_ReadId (PPACKETINFO IdPacket)
  628. {
  629. ULONG B4 = 0L;
  630. ULONG Data = 0L;
  631. ULONG Clks = GAME_ID_CLOCKS;
  632. LONG Result = ERROR_SUCCESS;
  633. PGAMEPORT PortInfo = &IdPacket->PortInfo;
  634. MsGamePrint ((DBG_INFORM, "SW3DPRO_ReadId enter\n"));
  635. if (!PORTIO_AcquirePort (PortInfo))
  636. return (FALSE);
  637. PORTIO_MaskInterrupts ();
  638. PORTIO_Write (PortInfo, 0);
  639. Result = SW3DPRO_InterruptPacket (PortInfo);
  640. if (Result != ERROR_SUCCESS)
  641. goto ReadIdExit;
  642. __asm
  643. {
  644. push edi
  645. push esi
  646. mov edx, PortInfo ; load gameport adddress
  647. xor eax, eax ; edx = port address
  648. mov ebx, GAME_ID_CLOCKS ; BL = no of clocks to receive.
  649. xor edi, edi ; clear B4 transition counter
  650. xor esi, esi ; clear data accumulator
  651. ID_ClockCheck:
  652. push edx ; read byte from gameport
  653. call PORTIO_Read
  654. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  655. jz ID_ClockRise ; N: jump
  656. ; ID_ClockFall:
  657. mov ecx, IdInfo.HighLowTimeout
  658. ID_ClockFall_1:
  659. test al, CLOCK_BIT_MASK ; Q: clock = 0
  660. jz ID_ClockRise ; Y: jump - look for rising edge
  661. push edx ; read byte from gameport
  662. call PORTIO_Read
  663. dec ecx
  664. jnz ID_ClockFall_1 ; else see if we timed out
  665. mov eax, ERROR_CLOCKFALLING
  666. jmp ID_Error ; Time out error.
  667. ID_ClockRise:
  668. mov ecx, IdInfo.LowHighTimeout
  669. ID_ClockRise_1:
  670. test al, CLOCK_BIT_MASK ; Q: clock high ?
  671. jnz ID_Data ; Y: jump. (get data)
  672. push edx ; read byte from gameport
  673. call PORTIO_Read
  674. dec ecx
  675. jnz ID_ClockRise_1 ; else see if we timed out
  676. mov eax, ERROR_CLOCKRISING
  677. jmp ID_Error ; Time out error.
  678. ID_Data:
  679. xor ah, al
  680. test ah, DATA2_BIT_MASK
  681. jz ID_Data_1
  682. inc edi ; increment Data 1 counter
  683. ID_Data_1:
  684. mov ah, al
  685. shr al, 6 ; put data into carry
  686. rcr esi, 1 ; and then in data counter
  687. dec bl ; decrement clk counter.
  688. jnz ID_ClockCheck ; if != 0 then loop
  689. ; ID_Success:
  690. mov eax, ERROR_SUCCESS
  691. mov IdInfo.Mode, IMODE_DIGITAL_STD
  692. cmp edi, 4
  693. jl ID_Success_1
  694. mov IdInfo.Mode, IMODE_DIGITAL_ENH
  695. ID_Success_1:
  696. mov IdInfo.B4Transitions, edi
  697. mov edx, IdInfo.Data
  698. mov [edx], esi
  699. jmp ID_Complete
  700. ID_Error:
  701. mov IdInfo.B4Transitions, edi
  702. mov edx, IdInfo.Data
  703. mov [edx], dword ptr 0
  704. ID_Complete:
  705. mov Result, eax
  706. mov Data, esi
  707. mov B4, edi
  708. mov Clks, ebx
  709. pop esi
  710. pop edi
  711. }
  712. // ----------------
  713. ReadIdExit:
  714. // ----------------
  715. IdPacket->TimeStamp = TIMER_GetTickCount ();
  716. IdPacket->ClocksSampled = GAME_ID_CLOCKS - Clks;
  717. IdPacket->LastError = Result;
  718. IdPacket->Transaction = MSGAME_TRANSACT_ID;
  719. PORTIO_UnMaskInterrupts ();
  720. PORTIO_ReleasePort (PortInfo);
  721. #if (DBG==1)
  722. switch (Result)
  723. {
  724. case ERROR_SUCCESS:
  725. MsGamePrint ((DBG_INFORM, "SW3DPRO_ReadId - SUCCEEDED, Data=%ld,B4=%ld,Clk=%ld\n", Data,B4,IdPacket->ClocksSampled));
  726. break;
  727. case ERROR_CLOCKFALLING:
  728. MsGamePrint ((DBG_SEVERE, "SW3DPRO_ReadId - TimeOut@ClockFalling, Data=%ld,B4=%ld,Clk=%ld\n", Data,B4,IdPacket->ClocksSampled));
  729. break;
  730. case ERROR_CLOCKRISING:
  731. MsGamePrint ((DBG_SEVERE, "SW3DPRO_ReadId - TimeOut@ClockRising, Data=%ld,B4=%ld,Clk=%ld\n", Data,B4,IdPacket->ClocksSampled));
  732. break;
  733. }
  734. #endif
  735. MSGAME_PostTransaction (IdPacket);
  736. return (!Result);
  737. }
  738. //---------------------------------------------------------------------------
  739. // @func Reads and validates device id string
  740. // @parm PPACKETINFO | IdPacket | ID Packet parameters
  741. // @rdesc True if successful, False otherwise
  742. // @comm Private function
  743. //---------------------------------------------------------------------------
  744. BOOLEAN SW3DPRO_GetId (PPACKETINFO IdPacket)
  745. {
  746. BOOLEAN Result;
  747. MsGamePrint ((DBG_INFORM, "SW3DPRO_GetId enter\n"));
  748. if(DataInfo.B4Transitions > 4)
  749. DataInfo.Mode = IMODE_DIGITAL_ENH;
  750. else DataInfo.Mode = IMODE_DIGITAL_STD;
  751. IdPacket->Attempts++;
  752. Result = SW3DPRO_ReadId (IdPacket);
  753. if (Result)
  754. {
  755. if (!strncmp (IdPacket->Data, GAME_ID_STRING, strlen(GAME_ID_STRING)))
  756. {
  757. //
  758. // Do AZTECH test here
  759. //
  760. if (IdPacket->B4Transitions > 3)
  761. {
  762. MsGamePrint ((DBG_CONTROL, "SW3DPRO_GetId - had B4 transitions\n"));
  763. IdPacket->Mode = DataInfo.Mode = IMODE_DIGITAL_ENH;
  764. }
  765. else
  766. {
  767. //
  768. // An AZTECH card was detected OR this card didn't seem to support
  769. // Enhanced mode correctly. Lets reset by going Analog then going
  770. // digital this should place the device into Standard mode.
  771. //
  772. MsGamePrint ((DBG_CONTROL, "SW3DPRO_GetId - 1 Wide Only type card detected\n"));
  773. SW3DPRO_ResetDevice (&IdPacket->PortInfo);
  774. SW3DPRO_GoDigital (IdPacket, GoDigitalMediumTiming);
  775. IdPacket->Mode = DataInfo.Mode = IMODE_DIGITAL_STD;
  776. }
  777. }
  778. else
  779. {
  780. MsGamePrint ((DBG_SEVERE, "SW3DPRO_GetId - Id string did not match = 0x%X\n", (ULONG)(*(PULONG)IdPacket->Data)));
  781. Result = FALSE;
  782. }
  783. }
  784. if (!Result)
  785. IdPacket->Failures++;
  786. TIMER_DelayMicroSecs (TIMER_GetDelay (ONE_MILLI_SEC+200));
  787. return (Result);
  788. }
  789. //---------------------------------------------------------------------------
  790. // @func Reads 1 wide data packet from gameport
  791. // @parm PPACKETINFO | DataPacket| Data packet parameters
  792. // @rdesc True if successful, False otherwise
  793. // @comm Private function
  794. //---------------------------------------------------------------------------
  795. BOOLEAN SW3DPRO_Read1Wide (PPACKETINFO DataPacket)
  796. {
  797. ULONG Clks = 0x2002;
  798. LONG Result;
  799. MsGamePrint ((DBG_VERBOSE, "SW3DPRO_Read1Wide enter\n"));
  800. PORTIO_Write (&DataInfo.PortInfo, 0);
  801. __asm
  802. {
  803. push edi
  804. push esi
  805. mov esi, DataInfo.Data
  806. lea edx, DataInfo.PortInfo ; load gameport adddress
  807. xor edi, edi
  808. mov ebx, 2002h
  809. xor eax, eax
  810. ; make sure clock is "high" before sampling clocks...
  811. mov ecx, DataInfo.StartTimeout
  812. Std_ClockStartState:
  813. push edx ; read byte from gameport
  814. call PORTIO_Read
  815. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  816. jnz Std_ClockStartFall
  817. loop Std_ClockStartState ; else keep looping
  818. mov eax, ERROR_LOWCLOCKSTART
  819. jmp PacketComplete ; Time out error.
  820. Std_CheckClkState:
  821. push edx ; read byte from gameport
  822. call PORTIO_Read
  823. test al, CLOCK_BIT_MASK
  824. jz Std_ClockStartRise
  825. Std_ClockStartFall:
  826. mov ecx, DataInfo.HighLowTimeout
  827. Std_ClockFalling:
  828. test al, CLOCK_BIT_MASK ; Q: clock = 0
  829. jz Std_ClockStartRise ; Y: jump - look for rising edge
  830. push edx ; read byte from gameport
  831. call PORTIO_Read
  832. loop Std_ClockFalling ; else see if we timed out
  833. mov eax, ERROR_CLOCKFALLING
  834. jmp PacketComplete ; Time out error.
  835. Std_ClockStartRise:
  836. mov ecx, DataInfo.LowHighTimeout
  837. Std_ClockRising:
  838. test al, CLOCK_BIT_MASK ; Q: clock high ?
  839. jnz CollectData ; Y: jump. (get data)
  840. push edx ; read byte from gameport
  841. call PORTIO_Read
  842. loop Std_ClockRising ; else see if we timed out
  843. mov eax, ERROR_CLOCKRISING
  844. jmp PacketComplete ; Time out error.
  845. CollectData:
  846. xor ah, al
  847. test ah, DATA1_BIT_MASK ; Q: Data 1 is toggled ?
  848. jnz CollectData_1 ; N: jump.
  849. inc edi ; Y: increment Data 1 count.
  850. CollectData_1:
  851. mov ah, al
  852. shr al, 6 ; put data into carry
  853. rcr DWORD PTR [esi], 1 ; and then in data counter
  854. dec bh ; Q: 32 bits received ?
  855. jnz Std_CheckClkState ; N: continue.
  856. dec bl ; dec dword count.
  857. jz PacketSuccess ; if dword count = 0 then exit.
  858. add esi, 4 ; else advance packet pointer
  859. mov bh, 32 ; set bit counter = 32+32=64.
  860. jmp Std_CheckClkState ; stay in receive loop.
  861. PacketSuccess:
  862. mov eax, ERROR_SUCCESS
  863. PacketComplete:
  864. mov Result, eax
  865. mov Clks, ebx
  866. mov DataInfo.B4Transitions, edi
  867. pop esi
  868. pop edi
  869. }
  870. switch (Clks & 0xFF)
  871. {
  872. case 0:
  873. DataPacket->ClocksSampled = 64;
  874. break;
  875. case 1:
  876. DataPacket->ClocksSampled = 32 + (32-(Clks>>8));
  877. break;
  878. case 2:
  879. DataPacket->ClocksSampled = 32 - (Clks>>8);
  880. break;
  881. }
  882. DataPacket->LastError = Result;
  883. #if (DBG==1)
  884. switch (Result)
  885. {
  886. case ERROR_LOWCLOCKSTART:
  887. MsGamePrint ((DBG_SEVERE, "SW3DPRO_Read1Wide - TimeOut@LowClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  888. break;
  889. case ERROR_HIGHCLOCKSTART:
  890. MsGamePrint ((DBG_SEVERE, "SW3DPRO_Read1Wide - TimeOut@HighClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  891. break;
  892. case ERROR_CLOCKFALLING:
  893. MsGamePrint ((DBG_SEVERE, "SW3DPRO_Read1Wide - TimeOut@ClockFalling, Clk=%ld\n", DataPacket->ClocksSampled));
  894. break;
  895. case ERROR_CLOCKRISING:
  896. MsGamePrint ((DBG_SEVERE, "SW3DPRO_Read1Wide - TimeOut@ClockRising, Clk=%ld\n", DataPacket->ClocksSampled));
  897. break;
  898. }
  899. #endif
  900. return (!Result);
  901. }
  902. //---------------------------------------------------------------------------
  903. // @func Reads 3 wide data packet from gameport
  904. // @parm PPACKETINFO | DataPacket| Data packet parameters
  905. // @rdesc True if successful, False otherwise
  906. // @comm Private function
  907. //---------------------------------------------------------------------------
  908. BOOLEAN SW3DPRO_Read3Wide (PPACKETINFO DataPacket)
  909. {
  910. LONG Clks = 1L;
  911. LONG Result;
  912. MsGamePrint ((DBG_VERBOSE, "SW3DPRO_Read3Wide enter\n"));
  913. PORTIO_Write (&DataInfo.PortInfo, 0);
  914. __asm
  915. {
  916. push edi
  917. push esi
  918. mov esi, DataInfo.Data
  919. lea edx, DataInfo.PortInfo ; load gameport adddress
  920. ; make sure clock is "high" before sampling clocks...
  921. mov ecx, DataInfo.StartTimeout
  922. mov ebx, 1
  923. Enh_ClockStartState:
  924. push edx ; read byte from gameport
  925. call PORTIO_Read
  926. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  927. jnz Enh_ClockStartFall ; Y: jump
  928. loop Enh_ClockStartState ; else keep looping
  929. mov eax, ERROR_LOWCLOCKSTART
  930. jmp Enh_Complete ; Time out error.
  931. Enh_CheckClkState:
  932. push edx ; read byte from gameport
  933. call PORTIO_Read
  934. test al, CLOCK_BIT_MASK
  935. jz Enh_ClockStartRise
  936. Enh_ClockStartFall:
  937. mov ecx, DataInfo.HighLowTimeout
  938. Enh_ClockFalling:
  939. test al, CLOCK_BIT_MASK ; Q: Clock Low ?
  940. jz Enh_ClockStartRise ; Y: jump.
  941. push edx ; read byte from gameport
  942. call PORTIO_Read
  943. dec ecx ; Q: Timeout ?
  944. jnz Enh_ClockFalling ; N: continue looping.
  945. mov eax, ERROR_CLOCKFALLING
  946. jmp Enh_Complete ; Time out error.
  947. Enh_ClockStartRise:
  948. mov ecx, DataInfo.LowHighTimeout
  949. Enh_ClockRising:
  950. test al, CLOCK_BIT_MASK ; Q: Clock = 1 ?
  951. jnz Enh_CollectData ; Y: jump.
  952. push edx ; read byte from gameport
  953. call PORTIO_Read
  954. dec ecx ; Q: Timeout ?
  955. jnz Enh_ClockRising ; N: continue looping.
  956. mov eax, ERROR_CLOCKRISING
  957. jmp Enh_Complete ; Time out error.
  958. Enh_CollectData:
  959. shr al, 5 ; move data to lower 3 bits
  960. test ebx, ENH_CLOCK_MIDPACKET ; Q: in mid-packet ?
  961. jnz Enh_MidPacket ; Y: jump.
  962. test ebx, ENH_CLOCK_COMPLETE ; Q: is packet complete ?
  963. jnz Enh_Success ; Y: jump.
  964. shrd edi, eax, 3 ; shift data into edi.
  965. shl ebx, 1 ; advance clock counter.
  966. jmp Enh_CheckClkState
  967. ;---------------------------------------------------------------------;
  968. ; This section of code compensates for when the clock cycle count is ;
  969. ; on a ULONG boundary. This happens on the 11th clock cycle. Two bits ;
  970. ; of data belong in the 1st ULONG and one bit belong in the 2nd ULONG ;
  971. ;---------------------------------------------------------------------;
  972. Enh_MidPacket:
  973. shrd edi, eax, 2 ; put 2 bits in 1st ULONG.
  974. mov [esi], edi ; Save 1st ULONG in packet ptr.
  975. xor edi, edi ; zero out edi.
  976. shr al, 2 ; move 3rd bit over.
  977. shrd edi, eax, 1 ; put 3rd bit in 2nd ULONG.
  978. shl ebx, 1 ; advance clock counter.
  979. jmp Enh_CheckClkState
  980. Enh_Success:
  981. shrd edi, eax, 1 ; shift data into edi.
  982. mov [esi+4], edi
  983. mov eax, ERROR_SUCCESS
  984. Enh_Complete:
  985. mov Result, eax
  986. mov Clks, ebx
  987. pop esi
  988. pop edi
  989. }
  990. for (DataPacket->ClocksSampled = 0; Clks >> (DataPacket->ClocksSampled+1); DataPacket->ClocksSampled++)
  991. ;
  992. DataPacket->LastError = Result;
  993. #if (DBG==1)
  994. switch (Result)
  995. {
  996. case ERROR_LOWCLOCKSTART:
  997. MsGamePrint ((DBG_SEVERE, "SW3DPRO_Read3Wide - TimeOut@LowClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  998. break;
  999. case ERROR_HIGHCLOCKSTART:
  1000. MsGamePrint ((DBG_SEVERE, "SW3DPRO_Read3Wide - TimeOut@HighClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  1001. break;
  1002. case ERROR_CLOCKFALLING:
  1003. MsGamePrint ((DBG_SEVERE, "SW3DPRO_Read3Wide - TimeOut@ClockFalling, Clk=%ld\n", DataPacket->ClocksSampled));
  1004. break;
  1005. case ERROR_CLOCKRISING:
  1006. MsGamePrint ((DBG_SEVERE, "SW3DPRO_Read3Wide - TimeOut@ClockRising, Clk=%ld\n", DataPacket->ClocksSampled));
  1007. break;
  1008. }
  1009. #endif
  1010. return (!Result);
  1011. }
  1012. //---------------------------------------------------------------------------
  1013. // @func Reads data packet from gameport depending on mode
  1014. // @parm PPACKETINFO | DataPacket| Data packet parameters
  1015. // @rdesc Returns NT status code
  1016. // @comm Private function
  1017. //---------------------------------------------------------------------------
  1018. NTSTATUS SW3DPRO_ReadData (PPACKETINFO DataPacket)
  1019. {
  1020. BOOLEAN Result = FALSE;
  1021. PGAMEPORT PortInfo = &DataPacket->PortInfo;
  1022. MsGamePrint ((DBG_VERBOSE, "SW3DPRO_ReadData enter\n"));
  1023. if (!PORTIO_AcquirePort (PortInfo))
  1024. return (STATUS_DEVICE_BUSY);
  1025. PORTIO_MaskInterrupts ();
  1026. DataPacket->ClocksSampled = 0;
  1027. DataPacket->B4Transitions = 0;
  1028. switch (DataPacket->Mode)
  1029. {
  1030. case IMODE_DIGITAL_STD:
  1031. Result = SW3DPRO_Read1Wide (DataPacket);
  1032. break;
  1033. case IMODE_DIGITAL_ENH:
  1034. Result = SW3DPRO_Read3Wide (DataPacket);
  1035. break;
  1036. default:
  1037. MsGamePrint ((DBG_SEVERE, "SW3DPRO_ReadData - unknown interface\n"));
  1038. break;
  1039. }
  1040. DataPacket->TimeStamp = TIMER_GetTickCount ();
  1041. DataPacket->Transaction = MSGAME_TRANSACT_DATA;
  1042. PORTIO_UnMaskInterrupts ();
  1043. PORTIO_ReleasePort (PortInfo);
  1044. MSGAME_PostTransaction (DataPacket);
  1045. if (!Result)
  1046. return (STATUS_DEVICE_NOT_CONNECTED);
  1047. return (STATUS_SUCCESS);
  1048. }
  1049. //---------------------------------------------------------------------------
  1050. // @func Validates raw packet information
  1051. // @parm PUCHAR | RawData | Pointer to raw packet data
  1052. // @rdesc True if successful, False otherwise
  1053. // @comm Private function
  1054. //---------------------------------------------------------------------------
  1055. BOOLEAN SW3DPRO_ValidateData (PUCHAR RawData)
  1056. {
  1057. LONG i = 0;
  1058. LONG Check = 0;
  1059. PULONG Phase = (PULONG)RawData;
  1060. LONG Result = ERROR_SUCCESS;
  1061. MsGamePrint ((DBG_VERBOSE, "SW3DPRO_ValidateData enter\n"));
  1062. if (((*Phase & 0x80808080L) != 0x80L) || (*(Phase+1) & 0x80808080L))
  1063. {
  1064. MsGamePrint ((DBG_SEVERE, "SW3DPRO_ValidateData - Phase bits non-zero: %X:%X\n", *(Phase+1), *Phase));
  1065. Result = ERROR_PHASEBITS;
  1066. }
  1067. else
  1068. {
  1069. for (i = 0; i < GAME_PACKET_SIZE; i++)
  1070. {
  1071. Check += LOW_NIBBLE(RawData[i]);
  1072. Check += HIGH_NIBBLE(RawData[i]);
  1073. }
  1074. if (LOW_NIBBLE(Check))
  1075. {
  1076. MsGamePrint ((DBG_SEVERE, "SW3DPRO_ValidateData - Checksum failed: %X:%X\n", *(Phase+1), *Phase));
  1077. Result = ERROR_CHECKSUM;
  1078. }
  1079. }
  1080. return (!Result);
  1081. }
  1082. //---------------------------------------------------------------------------
  1083. // @func Converts raw packet information to HID report
  1084. // @parm UCHAR[] | Data | Pointer to raw data buffer
  1085. // @parm PDEVICE_PACKET | Report | Pointer to device packet
  1086. // @rdesc Returns nothing
  1087. // @comm Private function
  1088. //---------------------------------------------------------------------------
  1089. VOID SW3DPRO_ProcessData (UCHAR Data[], PDEVICE_PACKET Report)
  1090. {
  1091. ULONG B1, B2;
  1092. MsGamePrint ((DBG_VERBOSE, "SW3DPRO_ProcessData enter\n"));
  1093. //
  1094. // Process X Axis
  1095. //
  1096. Report->dwX = Data[GAME_X7_X9_BYTE] & GAME_X7_X9_BITS;
  1097. Report->dwX <<= 4;
  1098. Report->dwX |= Data[GAME_X0_X6_BYTE] & GAME_X0_X6_BITS;
  1099. //
  1100. // Process Y Axis
  1101. //
  1102. Report->dwY = Data[GAME_Y7_Y9_BYTE] & GAME_Y7_Y9_BITS;
  1103. Report->dwY <<= 7;
  1104. Report->dwY |= Data[GAME_Y0_Y6_BYTE] & GAME_Y0_Y6_BITS;
  1105. //
  1106. // Process R Axis
  1107. //
  1108. Report->dwR = Data[GAME_R7_R8_BYTE] & GAME_R7_R8_BITS;
  1109. Report->dwR <<= 4;
  1110. Report->dwR |= Data[GAME_R0_R6_BYTE] & GAME_R0_R6_BITS;
  1111. //
  1112. // Process Z Axis
  1113. //
  1114. Report->dwZ = Data[GAME_T7_T9_BYTE] & GAME_T7_T9_BITS;
  1115. Report->dwZ <<= 7;
  1116. Report->dwZ |= Data[GAME_T0_T6_BYTE] & GAME_T0_T6_BITS;
  1117. //
  1118. // Process Buttons
  1119. //
  1120. B1 = (~Data[GAME_B7_BYTE] & GAME_B7_BITS) << 1;
  1121. B2 = ~Data[GAME_B0_B6_BYTE] & GAME_B0_B6_BITS;
  1122. Report->dwButtons = (B2 | B1) & ((1L << GAME_PACKET_BUTTONS) - 1);
  1123. Report->dwButtonNumber = 0;
  1124. for (B1 = 1; B1 <= GAME_PACKET_BUTTONS; B1++)
  1125. if (Report->dwButtons & (1L << (B1-1)))
  1126. {
  1127. Report->dwButtonNumber = B1;
  1128. break;
  1129. }
  1130. //
  1131. // Process Hatswitch
  1132. //
  1133. Report->dwPOV = (Data[GAME_H0_H2_BYTE] & GAME_H0_H2_BITS)>>4;
  1134. Report->dwPOV |= (Data[GAME_H3_BYTE] & GAME_H3_BITS)>>3;
  1135. Report->dwPOV = POV_Values[Report->dwPOV];
  1136. }
  1137. //---------------------------------------------------------------------------
  1138. // @func Driver entry point for device
  1139. // @rdesc Returns NT status code
  1140. // @comm Private function
  1141. //---------------------------------------------------------------------------
  1142. NTSTATUS SW3DPRO_DriverEntry (VOID)
  1143. {
  1144. MsGamePrint((DBG_INFORM,"SW3DPRO: SW3DPRO_DriverEntry Enter\n"));
  1145. //
  1146. // Read timing values from registry
  1147. //
  1148. MSGAME_ReadRegistry (DEVICENAME, &Delays);
  1149. return (STATUS_SUCCESS);
  1150. }
  1151. //---------------------------------------------------------------------------
  1152. // @func Establishes connection to device by detection
  1153. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1154. // @rdesc Returns NT Status code
  1155. // @comm Private function
  1156. //---------------------------------------------------------------------------
  1157. NTSTATUS SW3DPRO_ConnectDevice (PGAMEPORT PortInfo)
  1158. {
  1159. NTSTATUS ntStatus;
  1160. ULONG i = MAX_CONNECT_ATTEMPTS;
  1161. MsGamePrint ((DBG_INFORM, "SW3DPRO_ConnectDevice enter\n"));
  1162. DataInfo.PortInfo = IdInfo.PortInfo = *PortInfo;
  1163. //
  1164. // Convert registry timing values
  1165. //
  1166. SW3DPRO_Calibrate (PortInfo);
  1167. //
  1168. // SW3DPRO Connection method (try these steps twice)
  1169. //
  1170. do
  1171. {
  1172. //
  1173. // 1. Reset to "known" state
  1174. //
  1175. MsGamePrint ((DBG_CONTROL, "SW3DPRO_ConnectDevice - resetting device\n"));
  1176. SW3DPRO_ResetDevice (&DataInfo.PortInfo);
  1177. DataInfo.Mode = IdInfo.Mode = IMODE_DIGITAL_STD;
  1178. //
  1179. // 2. Delay 1 millisecond.
  1180. //
  1181. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  1182. //
  1183. // 3. Put into digital mode
  1184. //
  1185. MsGamePrint ((DBG_CONTROL, "SW3DPRO_ConnectDevice - going digital\n"));
  1186. SW3DPRO_GoDigital (&DataInfo, GoDigitalMediumTiming);
  1187. //
  1188. // 4. Delay 1 millisecond.
  1189. //
  1190. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC+500));
  1191. //
  1192. // 5. Get the ID string.
  1193. //
  1194. MsGamePrint ((DBG_CONTROL, "SW3DPRO_ConnectDevice - getting ID string\n"));
  1195. if (!SW3DPRO_GetId (&IdInfo))
  1196. {
  1197. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  1198. continue;
  1199. }
  1200. //
  1201. // 6. Mark device found and return
  1202. //
  1203. MidasInfo.NumDevices = 1;
  1204. return (STATUS_SUCCESS);
  1205. } while (--i);
  1206. //
  1207. // Return error
  1208. //
  1209. MidasInfo.NumDevices = 0;
  1210. return (STATUS_DEVICE_NOT_CONNECTED);
  1211. }
  1212. //---------------------------------------------------------------------------
  1213. // @func Reads and converts HID packet for this device
  1214. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1215. // @parm PUCHAR | Report | Output buffer for report
  1216. // @parm ULONG | MaxSize | Size of buffer for report
  1217. // @parm PULONG | Copied | Bytes copied to buffer for report
  1218. // @rdesc Returns Returns NT status code
  1219. // @comm Private function
  1220. //---------------------------------------------------------------------------
  1221. NTSTATUS SW3DPRO_ReadReport (PGAMEPORT PortInfo, PDEVICE_PACKET Report)
  1222. {
  1223. NTSTATUS ntStatus = STATUS_SUCCESS;
  1224. MsGamePrint ((DBG_VERBOSE, "SW3DPRO_ReadReport enter\n"));
  1225. //
  1226. // Log number of attempts
  1227. //
  1228. DataInfo.Attempts++;
  1229. //
  1230. // Set up default data to process
  1231. //
  1232. memcpy (DataInfo.Data, ValidData, sizeof (ValidData));
  1233. //
  1234. // Check for collision
  1235. //
  1236. if (DEVICE_IsCollision (&DataInfo))
  1237. {
  1238. MsGamePrint ((DBG_INFORM, "SW3DPRO_ReadReport - port collision\n"));
  1239. ntStatus = STATUS_DEVICE_BUSY;
  1240. goto ReadReportExit;
  1241. }
  1242. //
  1243. // Get a packet and check for errors
  1244. //
  1245. ntStatus = SW3DPRO_ReadData (&DataInfo);
  1246. if (NT_SUCCESS(ntStatus) && SW3DPRO_ValidateData (DataInfo.Data))
  1247. {
  1248. memcpy (ValidData, DataInfo.Data, sizeof (ValidData));
  1249. }
  1250. else if (ntStatus != STATUS_DEVICE_BUSY)
  1251. {
  1252. DataInfo.Failures++;
  1253. ntStatus = STATUS_DEVICE_NOT_CONNECTED;
  1254. MsGamePrint ((DBG_SEVERE, "SW3DPRO_ReadReport - Invalid packet\n"));
  1255. }
  1256. else
  1257. {
  1258. MsGamePrint ((DBG_CONTROL, "SW3DPRO_ReadReport - Port busy or in use\n"));
  1259. }
  1260. // ---------------
  1261. ReadReportExit:
  1262. // ---------------
  1263. SW3DPRO_ProcessData (ValidData, Report);
  1264. return (ntStatus);
  1265. }
  1266. //---------------------------------------------------------------------------
  1267. // @func Device handler for Pnp Start Device
  1268. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1269. // @rdesc Returns NT status code
  1270. // @comm Private function
  1271. //---------------------------------------------------------------------------
  1272. NTSTATUS SW3DPRO_StartDevice (PGAMEPORT PortInfo)
  1273. {
  1274. MsGamePrint ((DBG_INFORM, "SW3DPRO_StartDevice enter\n"));
  1275. UNREFERENCED_PARAMETER (PortInfo);
  1276. return (STATUS_SUCCESS);
  1277. }
  1278. //---------------------------------------------------------------------------
  1279. // @func Device handler for Pnp Stop Device
  1280. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1281. // @rdesc Returns NT status code
  1282. // @comm Private function
  1283. //---------------------------------------------------------------------------
  1284. NTSTATUS SW3DPRO_StopDevice (PGAMEPORT PortInfo, BOOLEAN TouchHardware)
  1285. {
  1286. MsGamePrint ((DBG_INFORM, "SW3DPRO_StopDevice enter\n"));
  1287. if (TouchHardware)
  1288. SW3DPRO_ResetDevice (PortInfo);
  1289. return (STATUS_SUCCESS);
  1290. }
  1291. //**************************************************************************
  1292. #endif // SAITEK
  1293. //**************************************************************************