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.

1769 lines
50 KiB

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