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.

1797 lines
50 KiB

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