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.

2072 lines
64 KiB

  1. //**************************************************************************
  2. //
  3. // SW3DFF.C -- Xena Gaming Project
  4. //
  5. // Version 3.XX
  6. //
  7. // Copyright (c) 1997 Microsoft Corporation. All rights reserved.
  8. //
  9. // @doc
  10. // @module SW3DFF.C | Gameport mini-driver for Sidewinder Pro Force Feedback
  11. //**************************************************************************
  12. #ifndef SAITEK
  13. #include "msgame.h"
  14. #include "swforce.h"
  15. //---------------------------------------------------------------------------
  16. // Definitions
  17. //---------------------------------------------------------------------------
  18. #define DEVICENAME "SW3DFF"
  19. #define DEVICE_PID 0x0006
  20. #define HARDWARE_ID L"Gameport\\SideWinderForceFeedbackPro\0\0"
  21. //
  22. // Packet Constants
  23. //
  24. #define GAME_PACKET_SIZE 6
  25. #define GAME_PACKET_BUTTONS (9+1)
  26. #define GAME_PACKET_AXIS 4
  27. #define GAME_B0_B7_BYTE 0 // Packet[0] bits
  28. #define GAME_B0_B7_BITS 0xff
  29. #define GAME_B8_BYTE 1 // Packet[1] bits
  30. #define GAME_B8_BITS 0x01
  31. #define GAME_X0_X6_BYTE 1
  32. #define GAME_X0_X6_BITS 0xfe
  33. #define GAME_X7_X9_BYTE 2 // Packet[2] bits
  34. #define GAME_X7_X9_BITS 0x07
  35. #define GAME_Y0_Y4_BYTE 2
  36. #define GAME_Y0_Y4_BITS 0xf8
  37. #define GAME_Y5_Y9_BYTE 3 // Packet[3] bits
  38. #define GAME_Y5_Y9_BITS 0x1f
  39. #define GAME_T0_T2_BYTE 3
  40. #define GAME_T0_T2_BITS 0xe0
  41. #define GAME_T3_T6_BYTE 4 // Packet[4] bits
  42. #define GAME_T3_T6_BITS 0x0f
  43. #define GAME_R0_R3_BYTE 4
  44. #define GAME_R0_R3_BITS 0xf0
  45. #define GAME_R4_R5_BYTE 5 // Packet[5] bits
  46. #define GAME_R4_R5_BITS 0x3
  47. #define GAME_H0_H3_BYTE 5
  48. #define GAME_H0_H3_BITS 0x3c
  49. #define GAME_ERR_BYTE 5
  50. #define GAME_ERR_BITS 0x40
  51. #define GAME_PPO_BYTE 5
  52. #define GAME_PPO_BITS 0x80
  53. #define ENH_CLOCK_MIDPACKET 0x0400
  54. #define ENH_CLOCK_COMPLETE 0x8000
  55. //
  56. // ID Constants
  57. //
  58. #define GAME_PRODUCT_ID 6
  59. #define GAME_ID_CLOCKS 8
  60. //
  61. // Status Constants
  62. //
  63. #define STATUS_CLOCK_COMPLETE 0x2000
  64. //
  65. // Timing Constants
  66. //
  67. #define PACKET_START_TIMEOUT 500
  68. #define PACKET_LOWHIGH_TIMEOUT 75
  69. #define PACKET_HIGHLOW_TIMEOUT 150
  70. #define ID_START_TIMEOUT 500
  71. #define ID_LOWHIGH_TIMEOUT 75
  72. #define ID_HIGHLOW_TIMEOUT 150
  73. #define MAX_CLOCK_DUTY_CYCLE 50
  74. #define STATUS_START_TIMEOUT 500
  75. #define STATUS_LOWHIGH_TIMEOUT 75
  76. #define STATUS_HIGHLOW_TIMEOUT 150
  77. #define STATUS_GATE_TIMEOUT 3000
  78. //
  79. // Joystick Extents
  80. //
  81. #define EXTENTS_X_MIN 0
  82. #define EXTENTS_X_MAX 0x3ff
  83. #define EXTENTS_Y_MIN 0
  84. #define EXTENTS_Y_MAX 0x3ff
  85. #define EXTENTS_T_MIN 0
  86. #define EXTENTS_T_MAX 0x7f
  87. #define EXTENTS_R_MIN 0
  88. #define EXTENTS_R_MAX 0x3f
  89. //
  90. // Throttle Smoothing
  91. //
  92. #define THROTTLE_JITTER_TIMEOUT 100 // in milliseconds
  93. #define THROTTLE_QUEUE_SIZE 4
  94. //---------------------------------------------------------------------------
  95. // Types
  96. //---------------------------------------------------------------------------
  97. typedef struct
  98. { // @struct SW3DFF_ID | Sidwinder Pro FF Id String
  99. #pragma pack(1)
  100. ULONG ProductId:16; // @field Device identifier
  101. ULONG Version:7; // @field Firmware version
  102. ULONG OddParity:1; // @field Packet parity
  103. ULONG Unused:8; // @field Unused
  104. #pragma pack()
  105. } SW3DFF_ID, *PSW3DFF_ID;
  106. typedef struct
  107. { // @struct SW3DFF_STATUS | Sidwinder Pro FF Status
  108. #pragma pack(1)
  109. UCHAR xVelocity; // @field X axis velocity
  110. UCHAR yVelocity; // @field Y axis velocity
  111. UCHAR xAccel; // @field X axis acceleration
  112. UCHAR yAccel; // @field Y axis acceleration
  113. USHORT Status; // @field Status word (bit fields)
  114. #pragma pack()
  115. } SW3DFF_STATUS, *PSW3DFF_STATUS;
  116. typedef struct
  117. { // @struct THROTTLE_QUEUE | Sidwinder Pro FF Throttle
  118. ULONG dwZ; // @field Z axis position
  119. ULONG TimeStamp; // @field timestamp for entry
  120. } THROTTLE_QUEUE, *PTHROTTLE_QUEUE;
  121. //---------------------------------------------------------------------------
  122. // Procedures
  123. //---------------------------------------------------------------------------
  124. static VOID SW3DFF_Calibrate (PGAMEPORT PortInfo);
  125. static BOOLEAN SW3DFF_ResetDevice (PGAMEPORT PortInfo);
  126. static BOOLEAN SW3DFF_ReadId (PPACKETINFO IdPacket);
  127. static BOOLEAN SW3DFF_GetId (PPACKETINFO IdPacket);
  128. static BOOLEAN SW3DFF_ReadStatus (PPACKETINFO StatusPacket);
  129. static BOOLEAN SW3DFF_GetStatus (PPACKETINFO StatusPacket);
  130. static NTSTATUS SW3DFF_ReadData (PPACKETINFO DataPacket);
  131. static VOID SW3DFF_ProcessData (UCHAR Data[], PDEVICE_PACKET Report);
  132. static VOID SW3DFF_AdjustThrottle (PDEVICE_PACKET Report);
  133. static NTSTATUS SW3DFF_ForceReset (PGAMEPORT PortInfo);
  134. static NTSTATUS SW3DFF_ForceId (PGAMEPORT PortInfo, PVOID IdString);
  135. static NTSTATUS SW3DFF_ForceStatus (PGAMEPORT PortInfo, PVOID Status);
  136. static NTSTATUS SW3DFF_ForceAckNak (PGAMEPORT PortInfo, PULONG AckNak);
  137. static NTSTATUS SW3DFF_ForceNakAck (PGAMEPORT PortInfo, PULONG NakAck);
  138. static NTSTATUS SW3DFF_ForceSync (PGAMEPORT PortInfo, PULONG Sync);
  139. //---------------------------------------------------------------------------
  140. // Services
  141. //---------------------------------------------------------------------------
  142. static NTSTATUS SW3DFF_DriverEntry (VOID);
  143. static NTSTATUS SW3DFF_ConnectDevice (PGAMEPORT PortInfo);
  144. static NTSTATUS SW3DFF_StartDevice (PGAMEPORT PortInfo);
  145. static NTSTATUS SW3DFF_ReadReport (PGAMEPORT PortInfo, PDEVICE_PACKET Report);
  146. static NTSTATUS SW3DFF_StopDevice (PGAMEPORT PortInfo, BOOLEAN TouchHardware);
  147. static NTSTATUS SW3DFF_GetFeature (PGAMEPORT PortInfo, HID_REPORT_ID ReportId, PVOID ReportBuffer, ULONG ReportSize, PULONG Returned);
  148. //---------------------------------------------------------------------------
  149. // Alloc_text pragma to specify routines that can be paged out.
  150. //---------------------------------------------------------------------------
  151. #ifdef ALLOC_PRAGMA
  152. #pragma alloc_text (INIT, SW3DFF_DriverEntry)
  153. #endif
  154. //---------------------------------------------------------------------------
  155. // Private Data
  156. //---------------------------------------------------------------------------
  157. //
  158. // HID Descriptors
  159. //
  160. static UCHAR ReportDescriptor[] =
  161. {
  162. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_GENERIC, // USAGE_PAGE (Generic Desktop)
  163. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  164. //---------------------------------------------------------------------------
  165. // JOYINFOEX
  166. //---------------------------------------------------------------------------
  167. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_APP, // COLLECTION (Application)
  168. HIDP_REPORT_ID_1, MSGAME_INPUT_JOYINFOEX,
  169. // id
  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. // do_other
  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. // dwX / dwY
  178. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_POINTER, // USAGE (Pointer)
  179. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Linked)
  180. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  181. HIDP_GLOBAL_LOG_MAX_4, 0xFF, 0x03, 0x00, 0x00, // LOGICAL_MAXIMUM (1023)
  182. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  183. HIDP_GLOBAL_PHY_MAX_4, 0xFF, 0x03, 0x00, 0x00, // PHYSICAL_MAXIMUM (1023)
  184. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  185. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  186. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  187. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_X, // USAGE (X)
  188. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  189. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_Y, // USAGE (Y)
  190. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  191. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  192. // dwZ
  193. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_SIMULATION, // USAGE_PAGE (Simulation Controls)
  194. HIDP_LOCAL_USAGE_1, HID_USAGE_SIMULATION_THROTTLE,// USAGE (Throttle)
  195. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  196. HIDP_GLOBAL_LOG_MAX_4, 0x7F, 0x00, 0x00, 0x00, // LOGICAL_MAXIMUM (127)
  197. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  198. HIDP_GLOBAL_PHY_MAX_4, 0x7F, 0x00, 0x00, 0x00, // PHYSICAL_MAXIMUM (127)
  199. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  200. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  201. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  202. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  203. // dwR
  204. HIDP_LOCAL_USAGE_1, HID_USAGE_SIMULATION_RUDDER, // USAGE (Rudder)
  205. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  206. HIDP_GLOBAL_LOG_MAX_4, 0x3F, 0x00, 0x00, 0x00, // LOGICAL_MAXIMUM (63)
  207. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  208. HIDP_GLOBAL_PHY_MAX_4, 0x3F, 0x00, 0x00, 0x00, // PHYSICAL_MAXIMUM (63)
  209. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  210. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  211. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  212. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  213. // dwU
  214. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  215. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  216. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  217. // dwV
  218. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  219. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  220. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  221. // dwPOV
  222. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_GENERIC, // USAGE_PAGE (Generic Desktop)
  223. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_HATSWITCH, // USAGE (Hat switch)
  224. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  225. HIDP_GLOBAL_LOG_MAX_4, 0x9F, 0x8C, 0x00, 0x00, // LOGICAL_MAXIMUM (35999)
  226. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  227. HIDP_GLOBAL_PHY_MAX_4, 0x9F, 0x8C, 0x00, 0x00, // PHYSICAL_MAXIMUM (35999)
  228. HIDP_GLOBAL_UNIT_2, 0x14, 0x00, // Unit (English Rot:Angular Pos)
  229. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  230. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  231. HIDP_MAIN_INPUT_1, 0x42, // Input (Data,Var,Abs,Null)
  232. // dwButtons
  233. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_BUTTON, // USAGE_PAGE (Button)
  234. HIDP_LOCAL_USAGE_MIN_1, 0x01, // USAGE_MINIMUM (Button 1)
  235. HIDP_LOCAL_USAGE_MAX_1, 0x0A, // USAGE_MAXIMUM (Button 10)
  236. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  237. HIDP_GLOBAL_LOG_MAX_1, 0x01, // LOGICAL_MAXIMUM (1)
  238. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  239. HIDP_GLOBAL_PHY_MAX_1, 0x01, // PHYSICAL_MAXIMUM (1)
  240. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  241. HIDP_GLOBAL_REPORT_SIZE, 0x01, // REPORT_SIZE (1)
  242. HIDP_GLOBAL_REPORT_COUNT_1,0x20, // REPORT_COUNT (32)
  243. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  244. // dwButtonNumber
  245. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  246. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  247. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  248. //---------------------------------------------------------------------------
  249. // GetID
  250. //---------------------------------------------------------------------------
  251. HIDP_GLOBAL_USAGE_PAGE_2, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
  252. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  253. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Link)
  254. HIDP_REPORT_ID_1, MSGAME_FEATURE_GETID,
  255. // cBytes
  256. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  257. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  258. HIDP_LOCAL_USAGE_1, 0x00, // USAGE (Vendor Defined1)
  259. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  260. // dwProductID
  261. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  262. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  263. HIDP_LOCAL_USAGE_1, 0x01, // USAGE (Vendor Defined1)
  264. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  265. // dwFWVersion
  266. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  267. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  268. HIDP_LOCAL_USAGE_1, 0x02, // USAGE (Vendor Defined1)
  269. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  270. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  271. //---------------------------------------------------------------------------
  272. // GetStatus
  273. //---------------------------------------------------------------------------
  274. HIDP_GLOBAL_USAGE_PAGE_2, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
  275. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  276. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Link)
  277. HIDP_REPORT_ID_1, MSGAME_FEATURE_GETSTATUS,
  278. // cBytes
  279. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  280. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  281. HIDP_LOCAL_USAGE_1, 0x03, // USAGE (Vendor Defined1)
  282. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  283. // dwXVel
  284. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  285. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  286. HIDP_LOCAL_USAGE_1, 0x04, // USAGE (Vendor Defined1)
  287. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  288. // dwYVel
  289. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  290. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  291. HIDP_LOCAL_USAGE_1, 0x05, // USAGE (Vendor Defined1)
  292. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  293. // dwXAccel
  294. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  295. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  296. HIDP_LOCAL_USAGE_1, 0x06, // USAGE (Vendor Defined1)
  297. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  298. // dwYAccel
  299. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  300. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  301. HIDP_LOCAL_USAGE_1, 0x07, // USAGE (Vendor Defined1)
  302. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  303. // dwEffect
  304. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  305. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  306. HIDP_LOCAL_USAGE_1, 0x08, // USAGE (Vendor Defined1)
  307. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  308. // dwDeviceStatus
  309. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  310. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  311. HIDP_LOCAL_USAGE_1, 0x09, // USAGE (Vendor Defined1)
  312. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  313. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  314. //---------------------------------------------------------------------------
  315. // GetAckNak
  316. //---------------------------------------------------------------------------
  317. HIDP_GLOBAL_USAGE_PAGE_2, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
  318. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  319. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Link)
  320. HIDP_REPORT_ID_1, MSGAME_FEATURE_GETACKNAK,
  321. // ULONG
  322. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  323. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  324. HIDP_LOCAL_USAGE_1, 0x0A, // USAGE (Vendor Defined1)
  325. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  326. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  327. //---------------------------------------------------------------------------
  328. // GetNakAck
  329. //---------------------------------------------------------------------------
  330. HIDP_GLOBAL_USAGE_PAGE_2, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
  331. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  332. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Link)
  333. HIDP_REPORT_ID_1, MSGAME_FEATURE_GETNAKACK,
  334. // ULONG
  335. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  336. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  337. HIDP_LOCAL_USAGE_1, 0x0B, // USAGE (Vendor Defined1)
  338. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  339. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  340. //---------------------------------------------------------------------------
  341. // GetSync
  342. //---------------------------------------------------------------------------
  343. HIDP_GLOBAL_USAGE_PAGE_2, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
  344. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  345. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Link)
  346. HIDP_REPORT_ID_1, MSGAME_FEATURE_GETSYNC,
  347. // ULONG
  348. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  349. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  350. HIDP_LOCAL_USAGE_1, 0x0C, // USAGE (Vendor Defined1)
  351. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  352. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  353. //---------------------------------------------------------------------------
  354. // DoReset
  355. //---------------------------------------------------------------------------
  356. HIDP_GLOBAL_USAGE_PAGE_2, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
  357. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  358. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Link)
  359. HIDP_REPORT_ID_1, MSGAME_FEATURE_RESET,
  360. // ULONG
  361. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  362. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  363. HIDP_LOCAL_USAGE_1, 0x0D, // USAGE (Vendor Defined1)
  364. HIDP_MAIN_FEATURE_1, 0x03, // FEATURE (Cnst,Var,Abs)
  365. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  366. //---------------------------------------------------------------------------
  367. // GetVersion
  368. //---------------------------------------------------------------------------
  369. HIDP_GLOBAL_USAGE_PAGE_2, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
  370. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK, // USAGE (Joystick)
  371. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Link)
  372. HIDP_REPORT_ID_1, MSGAME_FEATURE_GETVERSION,
  373. // ULONG
  374. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  375. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  376. HIDP_LOCAL_USAGE_1, 0x0E, // USAGE (Vendor Defined1)
  377. HIDP_MAIN_FEATURE_1, 0x02, // FEATURE (Data,Var,Abs)
  378. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  379. HIDP_MAIN_ENDCOLLECTION // END_COLLECTION
  380. };
  381. static HID_DESCRIPTOR DeviceDescriptor =
  382. {
  383. sizeof (HID_DESCRIPTOR),
  384. HID_HID_DESCRIPTOR_TYPE,
  385. MSGAME_HID_VERSION,
  386. MSGAME_HID_COUNTRY,
  387. MSGAME_HID_DESCRIPTORS,
  388. {HID_REPORT_DESCRIPTOR_TYPE,
  389. sizeof(ReportDescriptor)}
  390. };
  391. //
  392. // Raw Data Buffer
  393. //
  394. static UCHAR RawData[GAME_PACKET_SIZE] =
  395. {
  396. 0, // no buttons; x, y, t and r centered
  397. GAME_X0_X6_BITS,
  398. ((GAME_X7_X9_BITS>>1)&GAME_X7_X9_BITS)|GAME_Y0_Y4_BITS,
  399. ((GAME_Y5_Y9_BITS>>1)&GAME_Y5_Y9_BITS)|GAME_T0_T2_BITS,
  400. ((GAME_T3_T6_BITS>>1)&GAME_T3_T6_BITS)|GAME_R0_R3_BITS,
  401. ((GAME_R4_R5_BITS>>1)&GAME_R4_R5_BITS)|GAME_PPO_BITS
  402. };
  403. //
  404. // Raw Id Buffer
  405. //
  406. static SW3DFF_ID RawId =
  407. {
  408. 0
  409. };
  410. //
  411. // Raw Status Buffer
  412. //
  413. static SW3DFF_STATUS RawStatus =
  414. {
  415. 0
  416. };
  417. //
  418. // Timing Variables
  419. //
  420. static DEVICE_VALUES Delays =
  421. {
  422. PACKET_START_TIMEOUT,
  423. PACKET_HIGHLOW_TIMEOUT,
  424. PACKET_LOWHIGH_TIMEOUT,
  425. ID_START_TIMEOUT,
  426. ID_HIGHLOW_TIMEOUT,
  427. ID_LOWHIGH_TIMEOUT,
  428. 0, // No interrupt delay used
  429. MAX_CLOCK_DUTY_CYCLE,
  430. STATUS_START_TIMEOUT,
  431. STATUS_HIGHLOW_TIMEOUT,
  432. STATUS_LOWHIGH_TIMEOUT,
  433. STATUS_GATE_TIMEOUT
  434. };
  435. static ULONG StatusGateTimeout;
  436. //
  437. // Data Packet Info
  438. //
  439. static PACKETINFO DataInfo =
  440. {
  441. sizeof (PACKETINFO), // Size of structure
  442. DEVICENAME, // Name of device
  443. MSGAME_TRANSACT_NONE, // Transaction type
  444. IMODE_DIGITAL_ENH, // Interface mode
  445. GAME_SPEED_66K, // Transmission speed
  446. ERROR_SUCCESS, // Last internal error result
  447. {0}, // Game port info
  448. 0, // Packet acquisition mode
  449. 1, // Number of packets received
  450. 0, // Last valid acquisition time stamp
  451. 0, // Number of clocks sampled
  452. 0, // Number of B4 line transitions (std mode only)
  453. 0, // Start timeout period (in samples)
  454. 0, // Clock High to Low timeout period (in samples)
  455. 0, // Clock Low to High timeout period (in samples)
  456. 0, // Interrupt Timeout period
  457. 0, // Maximum clock duty cycle
  458. 0, // Number of Packet Failures
  459. 0, // Number of Packet Attempts
  460. sizeof (RawData), // Size of raw data buffer
  461. RawData // Pointer to Raw data
  462. };
  463. //
  464. // ID Packet Info
  465. //
  466. static PACKETINFO IdInfo =
  467. {
  468. sizeof (PACKETINFO), // Size of structure
  469. DEVICENAME, // Name of device
  470. MSGAME_TRANSACT_NONE, // Transaction type
  471. IMODE_DIGITAL_ENH, // Interface mode
  472. GAME_SPEED_66K, // Transmission speed
  473. ERROR_SUCCESS, // Last internal error result
  474. {0}, // Game port info
  475. 0, // Packet acquisition mode
  476. 1, // Number of packets received
  477. 0, // Last valid acquisition time stamp
  478. 0, // Number of clocks sampled
  479. 0, // Number of B4 line transitions (std mode only)
  480. 0, // Start timeout period (in samples)
  481. 0, // Clock High to Low timeout period (in samples)
  482. 0, // Clock Low to High timeout period (in samples)
  483. 0, // Interrupt Timeout period
  484. 0, // Maximum clock duty cycle
  485. 0, // Number of Packet Failures
  486. 0, // Number of Packet Attempts
  487. sizeof (RawId), // Size of raw id buffer
  488. &RawId // Pointer to Raw data
  489. };
  490. //
  491. // Status Packet Info
  492. //
  493. static PACKETINFO StatusInfo =
  494. {
  495. sizeof (PACKETINFO), // Size of structure
  496. DEVICENAME, // Name of device
  497. MSGAME_TRANSACT_NONE, // Transaction type
  498. IMODE_DIGITAL_ENH, // Interface mode
  499. GAME_SPEED_66K, // Transmission speed
  500. ERROR_SUCCESS, // Last internal error result
  501. {0}, // Game port info
  502. 0, // Packet acquisition mode
  503. 1, // Number of packets received
  504. 0, // Last valid acquisition time stamp
  505. 0, // Number of clocks sampled
  506. 0, // Number of B4 line transitions (std mode only)
  507. 0, // Start timeout period (in samples)
  508. 0, // Clock High to Low timeout period (in samples)
  509. 0, // Clock Low to High timeout period (in samples)
  510. 0, // Interrupt Timeout period
  511. 0, // Maximum clock duty cycle
  512. 0, // Number of Packet Failures
  513. 0, // Number of Packet Attempts
  514. sizeof (RawStatus), // Size of raw status buffer
  515. &RawStatus // Pointer to Raw data
  516. };
  517. //
  518. // Services Table
  519. //
  520. static DRIVERSERVICES Services =
  521. {
  522. SW3DFF_DriverEntry, // DriverEntry
  523. SW3DFF_ConnectDevice, // ConnectDevice
  524. SW3DFF_StartDevice, // StartDevice
  525. SW3DFF_ReadReport, // ReadReport
  526. SW3DFF_StopDevice, // StopDevice
  527. SW3DFF_GetFeature // GetFeature
  528. };
  529. //
  530. // Last Valid Data
  531. //
  532. static UCHAR ValidData[GAME_PACKET_SIZE] =
  533. {
  534. GAME_B0_B7_BITS, // no buttons; x, y, t and r centered
  535. GAME_X0_X6_BITS|GAME_B8_BITS,
  536. ((GAME_X7_X9_BITS>>1)&GAME_X7_X9_BITS)|GAME_Y0_Y4_BITS,
  537. ((GAME_Y5_Y9_BITS>>1)&GAME_Y5_Y9_BITS)|GAME_T0_T2_BITS,
  538. ((GAME_T3_T6_BITS>>1)&GAME_T3_T6_BITS)|GAME_R0_R3_BITS,
  539. ((GAME_R4_R5_BITS>>1)&GAME_R4_R5_BITS)|GAME_PPO_BITS
  540. };
  541. //
  542. // Rotation Filter Table
  543. //
  544. static UCHAR RotationFilter[EXTENTS_R_MAX+1] =
  545. {
  546. 0, 1, 3, 4, 5, 6, 8, 9,10,12,13,14,15,17,18,19,
  547. 20,22,23,24,26,27,28,29,31,32,32,32,32,32,32,32,
  548. 32,32,32,32,32,32,32,33,34,36,37,38,39,41,42,43,
  549. 44,46,47,48,49,50,52,53,54,55,57,58,59,60,62,63
  550. };
  551. //
  552. // Throttle Queue
  553. //
  554. static THROTTLE_QUEUE ThrottleQueue [THROTTLE_QUEUE_SIZE] =
  555. {
  556. {0x40,0},
  557. {0x40,0},
  558. {0x40,0},
  559. {0x40,0}
  560. };
  561. //
  562. // Reset Flag
  563. //
  564. static BOOLEAN ResetComplete = FALSE;
  565. //
  566. // Hardware ID String
  567. //
  568. static WCHAR HardwareId[] = HARDWARE_ID;
  569. //---------------------------------------------------------------------------
  570. // Public Data
  571. //---------------------------------------------------------------------------
  572. public DEVICEINFO JoltInfo =
  573. {
  574. &Services, // Service table
  575. NULL, // Sibling device list
  576. &DeviceDescriptor, // Device descriptor data
  577. ReportDescriptor, // Report descriptor data
  578. sizeof(ReportDescriptor), // Report descriptor size
  579. 0, // Number of devices detected
  580. 0, // Number of devices started
  581. 0, // Number of devices pending
  582. DEVICENAME, // Name of device
  583. DETECT_FIRST, // Detection order
  584. FALSE, // Analog device flag
  585. DEVICE_PID, // Hid device identifier
  586. HardwareId // PnP hardware identifier
  587. };
  588. //---------------------------------------------------------------------------
  589. // @func Reads registry timing values and calibrates them
  590. // @parm PGAMEPORT | PortInfo | Gameport parameters
  591. // @rdesc Returns nothing
  592. // @comm Private function
  593. //---------------------------------------------------------------------------
  594. VOID SW3DFF_Calibrate (PGAMEPORT PortInfo)
  595. {
  596. MsGamePrint((DBG_INFORM,"SW3DFF: SW3DFF_Calibrate Enter\n"));
  597. //
  598. // Convert timing values to counts
  599. //
  600. DataInfo.StartTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketStartTimeout);
  601. MsGamePrint((DBG_VERBOSE, "SW3DFF: DataInfo.StartTimeout = %ld\n", DataInfo.StartTimeout));
  602. DataInfo.LowHighTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketLowHighTimeout);
  603. MsGamePrint((DBG_VERBOSE, "SW3DFF: DataInfo.LowHighTimeout = %ld\n", DataInfo.LowHighTimeout));
  604. DataInfo.HighLowTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketHighLowTimeout);
  605. MsGamePrint((DBG_VERBOSE, "SW3DFF: DataInfo.HighLowTimeout = %ld\n", DataInfo.HighLowTimeout));
  606. IdInfo.StartTimeout = TIMER_CalibratePort (PortInfo, Delays.IdStartTimeout);
  607. MsGamePrint((DBG_VERBOSE, "SW3DFF: IdInfo.StartTimeout = %ld\n", IdInfo.StartTimeout));
  608. IdInfo.LowHighTimeout = TIMER_CalibratePort (PortInfo, Delays.IdLowHighTimeout);
  609. MsGamePrint((DBG_VERBOSE, "SW3DFF: IdInfo.LowHighTimeout=%ld\n", IdInfo.LowHighTimeout));
  610. IdInfo.HighLowTimeout = TIMER_CalibratePort (PortInfo, Delays.IdHighLowTimeout);
  611. MsGamePrint((DBG_VERBOSE, "SW3DFF: IdInfo.HighLowTimeout=%ld\n", IdInfo.HighLowTimeout));
  612. DataInfo.ClockDutyCycle = TIMER_CalibratePort (PortInfo, Delays.MaxClockDutyCycle);
  613. MsGamePrint((DBG_VERBOSE, "SW3DFF: DataInfo.ClockDutyCycle = %ld\n", DataInfo.ClockDutyCycle));
  614. IdInfo.ClockDutyCycle = TIMER_CalibratePort (PortInfo, Delays.MaxClockDutyCycle);
  615. MsGamePrint((DBG_VERBOSE, "SW3DFF: IdInfo.ClockDutyCycle = %ld\n", IdInfo.ClockDutyCycle));
  616. StatusInfo.ClockDutyCycle = TIMER_CalibratePort (PortInfo, Delays.MaxClockDutyCycle);
  617. MsGamePrint((DBG_VERBOSE, "SW3DFF: StatusInfo.ClockDutyCycle = %ld\n", StatusInfo.ClockDutyCycle));
  618. StatusInfo.StartTimeout = TIMER_CalibratePort (PortInfo, Delays.StatusStartTimeout);
  619. MsGamePrint((DBG_VERBOSE, "SW3DFF: StatusInfo.StartTimeout = %ld\n", StatusInfo.StartTimeout));
  620. StatusInfo.LowHighTimeout = TIMER_CalibratePort (PortInfo, Delays.StatusLowHighTimeout);
  621. MsGamePrint((DBG_VERBOSE, "SW3DFF: StatusInfo.LowHighTimeout=%ld\n", StatusInfo.LowHighTimeout));
  622. StatusInfo.HighLowTimeout = TIMER_CalibratePort (PortInfo, Delays.StatusHighLowTimeout);
  623. MsGamePrint((DBG_VERBOSE, "SW3DFF: StatusInfo.HighLowTimeout=%ld\n", StatusInfo.HighLowTimeout));
  624. StatusGateTimeout = TIMER_CalibratePort (PortInfo, Delays.StatusGateTimeout);
  625. MsGamePrint((DBG_VERBOSE, "SW3DFF: StatusGateTimeout=%ld\n", StatusGateTimeout));
  626. }
  627. //---------------------------------------------------------------------------
  628. // @func Resets device to known state
  629. // @parm PGAMEPORT | PortInfo | Gameport parameters
  630. // @rdesc True if successful, False otherwise
  631. // @comm Private function
  632. //---------------------------------------------------------------------------
  633. BOOLEAN SW3DFF_ResetDevice (PGAMEPORT PortInfo)
  634. {
  635. BOOLEAN Result = FALSE;
  636. MsGamePrint ((DBG_INFORM, "SW3DFF_ResetDevice enter\n"));
  637. if (!PORTIO_AcquirePort (PortInfo))
  638. return (FALSE);
  639. PORTIO_MaskInterrupts ();
  640. if (PORTIO_PulseAndWaitForIdleHandshake (PortInfo, DataInfo.ClockDutyCycle, 3))
  641. {
  642. PORTIO_Write (PortInfo, 0);
  643. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  644. DataInfo.LastError = ERROR_SUCCESS;
  645. Result = TRUE;
  646. }
  647. else
  648. {
  649. DataInfo.LastError = ERROR_HANDSHAKING;
  650. MsGamePrint ((DBG_SEVERE, "SW3DFF_ResetDevice - PulseAndWaitForHandshake failed\n"));
  651. }
  652. DataInfo.Transaction = MSGAME_TRANSACT_RESET;
  653. PORTIO_UnMaskInterrupts ();
  654. PORTIO_ReleasePort (PortInfo);
  655. if (!Result)
  656. MsGamePrint ((DBG_SEVERE, "SW3DFF_ResetDevice - PulseAndWaitForIdleHandshake failed\n"));
  657. MSGAME_PostTransaction (&DataInfo);
  658. return (Result);
  659. }
  660. //---------------------------------------------------------------------------
  661. // @func Reads device id string from port
  662. // @parm PPACKETINFO | IdPacket | ID Packet parameters
  663. // @rdesc True if successful, False otherwise
  664. // @comm Private function
  665. //---------------------------------------------------------------------------
  666. BOOLEAN SW3DFF_ReadId (PPACKETINFO IdPacket)
  667. {
  668. ULONG Data = 0L;
  669. ULONG Clks = GAME_ID_CLOCKS;
  670. LONG Result = ERROR_HANDSHAKING;
  671. PGAMEPORT PortInfo = &IdPacket->PortInfo;
  672. MsGamePrint ((DBG_INFORM, "SW3DFF_ReadId enter\n"));
  673. if (!PORTIO_AcquirePort (PortInfo))
  674. return (FALSE);
  675. PORTIO_MaskInterrupts ();
  676. IdPacket->B4Transitions = 0;
  677. if (!PORTIO_PulseAndWaitForIdleHandshake (PortInfo, IdInfo.ClockDutyCycle, 2))
  678. goto ReadIdExit;
  679. PORTIO_Write (PortInfo, 0);
  680. __asm
  681. {
  682. push edi
  683. push esi
  684. mov edx, PortInfo ; load gameport adddress
  685. xor eax, eax ; edx = port address
  686. mov ebx, GAME_ID_CLOCKS ; BL = # of clocks to receive.
  687. xor edi, edi ; clear B4 transition counter
  688. xor esi, esi ; clear data accumulator
  689. ; make sure clock is "high" before sampling clocks...
  690. mov ecx, IdInfo.StartTimeout
  691. ID_ClockStart:
  692. push edx ; read byte from gameport
  693. call PORTIO_Read
  694. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  695. jz ID_ClockStart_1 ; N: jump
  696. loop ID_ClockStart ; else keep looping
  697. mov eax, ERROR_LOWCLOCKSTART
  698. jmp ID_Error ; Time out error.
  699. ID_ClockStart_1:
  700. push edx ; read byte from gameport
  701. call PORTIO_Read
  702. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  703. jnz ID_Data ; Y: jump
  704. loop ID_ClockStart_1 ; else keep looping
  705. mov eax, ERROR_HIGHCLOCKSTART
  706. jmp ID_Error ; Time out error.
  707. ID_ClockCheck:
  708. push edx ; read byte from gameport
  709. call PORTIO_Read
  710. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  711. jz ID_ClockRise ; N: jump
  712. ; ID_ClockFall:
  713. mov ecx, IdInfo.HighLowTimeout
  714. ID_ClockFall_1:
  715. test al, CLOCK_BIT_MASK ; Q: clock = 0
  716. jz ID_ClockRise ; Y: jump - look for rising edge
  717. push edx ; read byte from gameport
  718. call PORTIO_Read
  719. dec ecx
  720. jnz ID_ClockFall_1 ; else see if we timed out
  721. mov eax, ERROR_CLOCKFALLING
  722. jmp ID_Error ; Time out error.
  723. ID_ClockRise:
  724. mov ecx, IdInfo.LowHighTimeout
  725. ID_ClockRise_1:
  726. test al, CLOCK_BIT_MASK ; Q: clock high ?
  727. jnz ID_Data ; Y: jump. (get data)
  728. push edx ; read byte from gameport
  729. call PORTIO_Read
  730. dec ecx
  731. jnz ID_ClockRise_1 ; else see if we timed out
  732. mov eax, ERROR_CLOCKRISING
  733. jmp ID_Error ; Time out error.
  734. ID_Data:
  735. xor ah, al
  736. test ah, DATA2_BIT_MASK
  737. jz ID_Data_1
  738. inc edi ; increment Data 1 counter
  739. ID_Data_1:
  740. mov ah, al
  741. shr al, 5
  742. shrd esi, eax,3
  743. dec ebx
  744. jne ID_ClockCheck
  745. shr esi, 8 ; only 24 bits
  746. ; ID_Success:
  747. mov IdInfo.B4Transitions, edi
  748. mov eax, ERROR_SUCCESS
  749. mov edx, IdInfo.Data
  750. mov [edx], esi
  751. jmp ID_Complete
  752. ID_Error:
  753. mov edx, IdInfo.Data
  754. mov [edx], dword ptr 0
  755. ID_Complete:
  756. mov Result, eax
  757. mov Data, esi
  758. mov Clks, ebx
  759. pop esi
  760. pop edi
  761. }
  762. // ----------------
  763. ReadIdExit:
  764. // ----------------
  765. IdPacket->TimeStamp = TIMER_GetTickCount ();
  766. IdPacket->ClocksSampled = GAME_ID_CLOCKS - Clks;
  767. IdPacket->LastError = Result;
  768. IdPacket->Transaction = MSGAME_TRANSACT_ID;
  769. PORTIO_UnMaskInterrupts ();
  770. PORTIO_ReleasePort (PortInfo);
  771. #if (DBG==1)
  772. switch (Result)
  773. {
  774. case ERROR_SUCCESS:
  775. MsGamePrint ((DBG_INFORM, "SW3DFF_ReadId - SUCCEEDED, Data=%ld\n", Data));
  776. break;
  777. case ERROR_HANDSHAKING:
  778. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadId - TimeOut@Handshaking\n"));
  779. break;
  780. case ERROR_LOWCLOCKSTART:
  781. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadId - TimeOut@LowClockStart, Data=%ld,Clk=%ld\n", Data,IdPacket->ClocksSampled));
  782. break;
  783. case ERROR_HIGHCLOCKSTART:
  784. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadId - TimeOut@HighClockStart, Data=%ld,Clk=%ld\n", Data,IdPacket->ClocksSampled));
  785. break;
  786. case ERROR_CLOCKFALLING:
  787. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadId - TimeOut@ClockFalling, Data=%ld,Clk=%ld\n", Data,IdPacket->ClocksSampled));
  788. break;
  789. case ERROR_CLOCKRISING:
  790. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadId - TimeOut@ClockRising, Data=%ld,Clk=%ld\n", Data,IdPacket->ClocksSampled));
  791. break;
  792. }
  793. #endif
  794. MSGAME_PostTransaction (IdPacket);
  795. return (!Result);
  796. }
  797. //---------------------------------------------------------------------------
  798. // @func Reads and validates device id string
  799. // @parm PPACKETINFO | IdPacket | ID Packet parameters
  800. // @rdesc True if successful, False otherwise
  801. // @comm Private function
  802. //---------------------------------------------------------------------------
  803. BOOLEAN SW3DFF_GetId (PPACKETINFO IdPacket)
  804. {
  805. BOOLEAN Result;
  806. PSW3DFF_ID Pnp;
  807. MsGamePrint ((DBG_INFORM, "SW3DFF_GetId enter\n"));
  808. IdPacket->Attempts++;
  809. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  810. Result = SW3DFF_ReadId (IdPacket);
  811. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  812. if (Result)
  813. {
  814. Pnp = (PSW3DFF_ID)IdPacket->Data;
  815. if ((Pnp->ProductId != GAME_PRODUCT_ID) || !DEVICE_IsOddParity (Pnp, sizeof(SW3DFF_ID)))
  816. {
  817. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetId - Id did not match or parity error\n"));
  818. Result = FALSE;
  819. }
  820. }
  821. if (!Result)
  822. IdPacket->Failures++;
  823. if (PORTIO_IsClockActive (&IdPacket->PortInfo, IdInfo.ClockDutyCycle))
  824. TIMER_DelayMicroSecs (TIMER_GetDelay (ONE_MILLI_SEC));
  825. return (Result);
  826. }
  827. //---------------------------------------------------------------------------
  828. // @func Reads data packet from gameport
  829. // @parm PPACKETINFO | DataPacket| Data packet parameters
  830. // @rdesc Returns NT status code
  831. // @comm Private function
  832. //---------------------------------------------------------------------------
  833. NTSTATUS SW3DFF_ReadData (PPACKETINFO DataPacket)
  834. {
  835. LONG Result;
  836. LONG Clks = 1L;
  837. PGAMEPORT PortInfo = &DataPacket->PortInfo;
  838. MsGamePrint ((DBG_VERBOSE, "SW3DFF_ReadData enter\n"));
  839. if (!PORTIO_AcquirePort (PortInfo))
  840. return (STATUS_DEVICE_BUSY);
  841. PORTIO_MaskInterrupts ();
  842. PORTIO_Write (PortInfo, 0);
  843. __asm
  844. {
  845. push edi
  846. push esi
  847. mov edx, PortInfo ; load gameport adddress
  848. mov esi, DataInfo.Data
  849. mov ebx, 1
  850. ; make sure clock is "high" before sampling clocks...
  851. mov ecx, DataInfo.StartTimeout
  852. Enh_ClockStartState:
  853. push edx ; read byte from gameport
  854. call PORTIO_Read
  855. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  856. jz Enh_ClockStartState_1 ; N: jump
  857. loop Enh_ClockStartState ; else keep looping
  858. mov eax, ERROR_LOWCLOCKSTART
  859. jmp Enh_Complete ; Time out error.
  860. Enh_ClockStartState_1:
  861. push edx ; read byte from gameport
  862. call PORTIO_Read
  863. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  864. jnz Enh_CollectData ; Y: jump
  865. loop Enh_ClockStartState_1 ; else keep looping
  866. mov eax, ERROR_HIGHCLOCKSTART
  867. jmp Enh_Complete ; Time out error.
  868. Enh_CheckClkState:
  869. push edx ; read byte from gameport
  870. call PORTIO_Read
  871. test al, CLOCK_BIT_MASK
  872. jz Enh_ClockStartRise
  873. ;Enh_ClockStartFall:
  874. mov ecx, DataInfo.HighLowTimeout
  875. Enh_ClockFalling:
  876. test al,CLOCK_BIT_MASK ; Q: Clock Low ?
  877. jz Enh_ClockStartRise ; Y: jump.
  878. push edx ; read byte from gameport
  879. call PORTIO_Read
  880. dec ecx ; Q: Timeout ?
  881. jnz Enh_ClockFalling ; N: continue looping.
  882. mov eax, ERROR_CLOCKFALLING
  883. jmp Enh_Complete ; Time out error.
  884. Enh_ClockStartRise:
  885. mov ecx, DataInfo.LowHighTimeout
  886. Enh_ClockRising:
  887. test al, CLOCK_BIT_MASK ; Q: Clock = 1 ?
  888. jnz Enh_CollectData ; Y: jump.
  889. push edx ; read byte from gameport
  890. call PORTIO_Read
  891. dec ecx ; Q: Timeout ?
  892. jnz Enh_ClockRising ; N: continue looping.
  893. mov eax, ERROR_CLOCKRISING
  894. jmp Enh_Complete ; Time out error.
  895. Enh_CollectData:
  896. shr al, 5 ; move data to lower 3 bits
  897. test ebx, ENH_CLOCK_MIDPACKET ; Q: in mid-packet ?
  898. jnz Enh_MidPacket ; Y: jump.
  899. test ebx, ENH_CLOCK_COMPLETE ; Q: is packet complete ?
  900. jnz Enh_Success ; Y: jump.
  901. shrd edi, eax, 3 ; shift data into edi.
  902. shl ebx, 1 ; advance clock counter.
  903. jmp Enh_CheckClkState
  904. ;---------------------------------------------------------------------;
  905. ; This section of code compensates for when the clock cycle count is ;
  906. ; on a ULONG boundary. This happens on the 11th clock cycle. Two bits ;
  907. ; of data belong in the 1st ULONG and one bit belong in the 2nd ULONG ;
  908. ;---------------------------------------------------------------------;
  909. Enh_MidPacket:
  910. shrd edi, eax, 2 ; put 2 bits in 1st ULONG.
  911. mov [esi], edi ; Save 1st ULONG in packet ptr.
  912. xor edi, edi ; zero out edi.
  913. shr al, 2 ; move 3rd bit over.
  914. shrd edi, eax, 1 ; put 3rd bit in 2nd ULONG.
  915. shl ebx, 1 ; advance clock counter.
  916. jmp Enh_CheckClkState
  917. Enh_Success:
  918. shrd edi, eax, 3 ; shift data into edi.
  919. shr edi, 16
  920. mov word ptr [esi+4], di
  921. mov eax, PortInfo ; wait for clock to settle
  922. push eax
  923. call PORTIO_WaitClockLow
  924. push DataInfo.ClockDutyCycle
  925. mov eax, PortInfo ; wait for clock to settle
  926. push eax
  927. call PORTIO_IsClockActive
  928. or al, al
  929. mov eax, ERROR_SUCCESS
  930. je Enh_Complete
  931. mov eax, ERROR_EXTRACLOCKS ; probably gamepads
  932. Enh_Complete:
  933. mov Result, eax
  934. mov Clks, ebx
  935. pop esi
  936. pop edi
  937. }
  938. for (DataPacket->ClocksSampled = 0; Clks >> (DataPacket->ClocksSampled+1); DataPacket->ClocksSampled++);
  939. DataPacket->TimeStamp = TIMER_GetTickCount ();
  940. DataPacket->LastError = Result;
  941. DataPacket->Transaction = MSGAME_TRANSACT_DATA;
  942. PORTIO_UnMaskInterrupts ();
  943. PORTIO_ReleasePort (PortInfo);
  944. #if (DBG==1)
  945. switch (Result)
  946. {
  947. case ERROR_LOWCLOCKSTART:
  948. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadData - TimeOut@LowClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  949. break;
  950. case ERROR_HIGHCLOCKSTART:
  951. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadData - TimeOut@HighClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  952. break;
  953. case ERROR_CLOCKFALLING:
  954. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadData - TimeOut@ClockFalling, Clk=%ld\n", DataPacket->ClocksSampled));
  955. break;
  956. case ERROR_CLOCKRISING:
  957. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadData - TimeOut@ClockRising, Clk=%ld\n", DataPacket->ClocksSampled));
  958. break;
  959. case ERROR_EXTRACLOCKS:
  960. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadData - Extra Clocks, Clk=%ld\n", DataPacket->ClocksSampled));
  961. break;
  962. }
  963. #endif
  964. MSGAME_PostTransaction (DataPacket);
  965. if (Result)
  966. return (STATUS_DEVICE_NOT_CONNECTED);
  967. return (STATUS_SUCCESS);
  968. }
  969. //---------------------------------------------------------------------------
  970. // @func Converts raw packet information to HID report
  971. // @parm UCHAR[] | Data | Pointer to raw data buffer
  972. // @parm PDEVICE_PACKET | Report | Pointer to device packet
  973. // @rdesc Returns nothing
  974. // @comm Private function
  975. //---------------------------------------------------------------------------
  976. VOID SW3DFF_ProcessData (UCHAR Data[], PDEVICE_PACKET Report)
  977. {
  978. ULONG B1, B2;
  979. MsGamePrint ((DBG_VERBOSE, "SW3DFF_ProcessData enter\n"));
  980. //
  981. // Process X Axis
  982. //
  983. Report->dwX = Data[GAME_X7_X9_BYTE] & GAME_X7_X9_BITS;
  984. Report->dwX <<= 7;
  985. Report->dwX |= (Data[GAME_X0_X6_BYTE] & GAME_X0_X6_BITS) >> 1;
  986. //
  987. // Process Y Axis
  988. //
  989. Report->dwY = Data[GAME_Y5_Y9_BYTE] & GAME_Y5_Y9_BITS;
  990. Report->dwY <<= 5;
  991. Report->dwY |= (Data[GAME_Y0_Y4_BYTE] & GAME_Y0_Y4_BITS) >> 3;
  992. //
  993. // Process R Axis
  994. //
  995. Report->dwR = Data[GAME_R4_R5_BYTE] & GAME_R4_R5_BITS;
  996. Report->dwR <<= 4;
  997. Report->dwR |= (Data[GAME_R0_R3_BYTE] & GAME_R0_R3_BITS) >> 4;
  998. // Rotation filter
  999. Report->dwR = RotationFilter[Report->dwR];
  1000. //
  1001. // Process Z Axis
  1002. //
  1003. Report->dwZ = Data[GAME_T3_T6_BYTE] & GAME_T3_T6_BITS;
  1004. Report->dwZ <<= 3;
  1005. Report->dwZ |= (Data[GAME_T0_T2_BYTE] & GAME_T0_T2_BITS) >> 5;
  1006. //
  1007. // Process Buttons
  1008. //
  1009. B1 = ~Data[GAME_B0_B7_BYTE] & GAME_B0_B7_BITS;
  1010. B2 = ~Data[GAME_B8_BYTE] & GAME_B8_BITS;
  1011. B2 <<= 9; // Move button nine to ten (shift key)
  1012. Report->dwButtons = (B2 | B1) & ((1L << GAME_PACKET_BUTTONS) - 1);
  1013. Report->dwButtonNumber = 0;
  1014. for (B1 = 1; B1 <= GAME_PACKET_BUTTONS; B1++)
  1015. if (Report->dwButtons & (1L << (B1-1)))
  1016. {
  1017. Report->dwButtonNumber = B1;
  1018. break;
  1019. }
  1020. //
  1021. // Process Hatswitch
  1022. //
  1023. Report->dwPOV = POV_Values[(Data[GAME_H0_H3_BYTE] & GAME_H0_H3_BITS)>>2];
  1024. }
  1025. //---------------------------------------------------------------------------
  1026. // @func Filters throttle packet information
  1027. // @parm PDEVICE_PACKET | Report | Pointer to device packet
  1028. // @rdesc Returns nothing
  1029. // @comm Private function
  1030. //---------------------------------------------------------------------------
  1031. VOID SW3DFF_AdjustThrottle (PDEVICE_PACKET Report)
  1032. {
  1033. ULONG i;
  1034. ULONG TimeStamp;
  1035. ULONG zTotal;
  1036. MsGamePrint ((DBG_VERBOSE, "SW3DFF_AdjustThrottle enter\n"));
  1037. zTotal = 0;
  1038. TimeStamp = TIMER_GetTickCount ();
  1039. //
  1040. // If current sample past que window then repopulate queue with current sample and time stamp
  1041. //
  1042. if ((ThrottleQueue[THROTTLE_QUEUE_SIZE-1].TimeStamp+THROTTLE_JITTER_TIMEOUT) < TimeStamp)
  1043. {
  1044. for (i = 0; i < THROTTLE_QUEUE_SIZE; i++)
  1045. {
  1046. ThrottleQueue[i].dwZ = Report->dwZ;
  1047. ThrottleQueue[i].TimeStamp = TimeStamp;
  1048. }
  1049. return;
  1050. }
  1051. //
  1052. // Move the whole queue down by one
  1053. //
  1054. memcpy (ThrottleQueue, &ThrottleQueue[1], sizeof(THROTTLE_QUEUE)*(THROTTLE_QUEUE_SIZE-1));
  1055. //
  1056. // Place new que member into last position
  1057. //
  1058. ThrottleQueue[THROTTLE_QUEUE_SIZE-1].dwZ = Report->dwZ;
  1059. ThrottleQueue[THROTTLE_QUEUE_SIZE-1].TimeStamp = TimeStamp;
  1060. //
  1061. // Now average all que positions
  1062. //
  1063. for (i = 0; i < THROTTLE_QUEUE_SIZE; i++)
  1064. zTotal += ThrottleQueue[i].dwZ;
  1065. Report->dwZ = zTotal / THROTTLE_QUEUE_SIZE;
  1066. }
  1067. //---------------------------------------------------------------------------
  1068. // @func Reads and validates device status
  1069. // @parm PPACKETINFO | StatusPacket | Status Packet parameters
  1070. // @rdesc True if successful, False otherwise
  1071. // @comm Private function
  1072. //---------------------------------------------------------------------------
  1073. BOOLEAN SW3DFF_GetStatus (PPACKETINFO StatusPacket)
  1074. {
  1075. BOOLEAN Result;
  1076. PSW3DFF_STATUS Status;
  1077. MsGamePrint ((DBG_INFORM, "SW3DFF_GetStatus Enter\n"));
  1078. StatusPacket->Attempts++;
  1079. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  1080. Result = SW3DFF_ReadStatus (StatusPacket);
  1081. if (Result)
  1082. {
  1083. Status = (PSW3DFF_STATUS)StatusPacket->Data;
  1084. if (!DEVICE_IsOddParity (Status, sizeof(SW3DFF_STATUS)))
  1085. {
  1086. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetStatus - Parity error\n"));
  1087. Result = FALSE;
  1088. }
  1089. else
  1090. {
  1091. MsGamePrint ((DBG_INFORM, "SW3DFF_GetStatus - X Velocity = %ld\n", (long)Status->xVelocity));
  1092. MsGamePrint ((DBG_INFORM, "SW3DFF_GetStatus - Y Velocity = %ld\n", (long)Status->yVelocity));
  1093. MsGamePrint ((DBG_INFORM, "SW3DFF_GetStatus - X Accel = %ld\n", (long)Status->xAccel));
  1094. MsGamePrint ((DBG_INFORM, "SW3DFF_GetStatus - Y Accel = %ld\n", (long)Status->xAccel));
  1095. MsGamePrint ((DBG_INFORM, "SW3DFF_GetStatus - Status = 0x%X\n", (long)Status->Status));
  1096. }
  1097. }
  1098. if (!Result)
  1099. StatusPacket->Failures++;
  1100. if (PORTIO_IsClockActive (&StatusPacket->PortInfo, StatusInfo.ClockDutyCycle))
  1101. TIMER_DelayMicroSecs (TIMER_GetDelay (ONE_MILLI_SEC));
  1102. return (Result);
  1103. }
  1104. //---------------------------------------------------------------------------
  1105. // @func Reads status packet from gameport
  1106. // @parm PPACKETINFO | StatusPacket| Status packet parameters
  1107. // @rdesc True if successful, False otherwise
  1108. // @comm Private function
  1109. //---------------------------------------------------------------------------
  1110. BOOLEAN SW3DFF_ReadStatus (PPACKETINFO StatusPacket)
  1111. {
  1112. USHORT Status[3];
  1113. LONG Clks = 1L;
  1114. LONG Result = ERROR_HANDSHAKING;
  1115. PGAMEPORT PortInfo = &StatusPacket->PortInfo;
  1116. MsGamePrint ((DBG_VERBOSE, "SW3DFF_ReadStatus enter\n"));
  1117. if (!PORTIO_AcquirePort (PortInfo))
  1118. return (FALSE);
  1119. PORTIO_MaskInterrupts ();
  1120. StatusPacket->ClocksSampled = 0;
  1121. StatusPacket->B4Transitions = 0;
  1122. if (!PORTIO_WaitDataLow (PortInfo))
  1123. goto ReadStatusExit;
  1124. if (!PORTIO_PulseAndWaitForIdleHandshake (PortInfo, StatusInfo.ClockDutyCycle, 1))
  1125. goto ReadStatusExit;
  1126. PORTIO_Write (PortInfo, 0);
  1127. __asm
  1128. {
  1129. push edi
  1130. push esi
  1131. mov edx, PortInfo ; load gameport adddress
  1132. mov esi, StatusInfo.Data
  1133. mov ebx, 1
  1134. ; make sure clock is "high" before sampling clocks...
  1135. mov ecx, StatusInfo.StartTimeout
  1136. Stat_ClockStartState:
  1137. push edx ; read byte from gameport
  1138. call PORTIO_Read
  1139. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  1140. jz Stat_ClockStartState_1 ; N: jump
  1141. loop Stat_ClockStartState ; else keep looping
  1142. mov eax, ERROR_LOWCLOCKSTART
  1143. jmp Stat_Complete ; Time out error.
  1144. Stat_ClockStartState_1:
  1145. push edx ; read byte from gameport
  1146. call PORTIO_Read
  1147. test al, CLOCK_BIT_MASK ; Q: Clock = 1
  1148. jnz Stat_CollectData ; Y: jump
  1149. loop Stat_ClockStartState_1 ; else keep looping
  1150. mov eax, ERROR_HIGHCLOCKSTART
  1151. jmp Stat_Complete ; Time out error.
  1152. Stat_CheckClkState:
  1153. push edx ; read byte from gameport
  1154. call PORTIO_Read
  1155. test al, CLOCK_BIT_MASK
  1156. jz Stat_ClockStartRise
  1157. ;Stat_ClockStartFall:
  1158. mov ecx, StatusInfo.HighLowTimeout
  1159. Stat_ClockFalling:
  1160. test al,CLOCK_BIT_MASK ; Q: Clock Low ?
  1161. jz Stat_ClockStartRise ; Y: jump.
  1162. push edx ; read byte from gameport
  1163. call PORTIO_Read
  1164. dec ecx ; Q: Timeout ?
  1165. jnz Stat_ClockFalling ; N: continue looping.
  1166. mov eax, ERROR_CLOCKFALLING
  1167. jmp Stat_Complete ; Time out error.
  1168. Stat_ClockStartRise:
  1169. mov ecx, StatusInfo.LowHighTimeout
  1170. Stat_ClockRising:
  1171. test al, CLOCK_BIT_MASK ; Q: Clock = 1 ?
  1172. jnz Stat_CollectData ; Y: jump.
  1173. push edx ; read byte from gameport
  1174. call PORTIO_Read
  1175. dec ecx ; Q: Timeout ?
  1176. jnz Stat_ClockRising ; N: continue looping.
  1177. mov eax, ERROR_CLOCKRISING
  1178. jmp Stat_Complete ; Time out error.
  1179. Stat_CollectData:
  1180. shr al, 5 ; move data to lower 3 bits
  1181. test ebx, ENH_CLOCK_MIDPACKET ; Q: in mid-packet ?
  1182. jnz Stat_MidPacket ; Y: jump.
  1183. test ebx, STATUS_CLOCK_COMPLETE ; Q: is packet complete ?
  1184. jnz Stat_Success ; Y: jump.
  1185. shrd edi, eax, 3 ; shift data into edi.
  1186. shl ebx, 1 ; advance clock counter.
  1187. jmp Stat_CheckClkState
  1188. ;---------------------------------------------------------------------;
  1189. ; This section of code compensates for when the clock cycle count is ;
  1190. ; on a ULONG boundary. This happens on the 11th clock cycle. Two bits ;
  1191. ; of data belong in the 1st ULONG and one bit belong in the 2nd ULONG ;
  1192. ;---------------------------------------------------------------------;
  1193. Stat_MidPacket:
  1194. shrd edi, eax, 2 ; put 2 bits in 1st ULONG.
  1195. mov [esi], edi ; Save 1st ULONG in packet ptr.
  1196. xor edi, edi ; zero out edi.
  1197. shr al, 2 ; move 3rd bit over.
  1198. shrd edi, eax, 1 ; put 3rd bit in 2nd ULONG.
  1199. shl ebx, 1 ; advance clock counter.
  1200. jmp Stat_CheckClkState
  1201. Stat_Success:
  1202. shrd edi, eax, 3 ; shift data into edi.
  1203. shr edi, 22
  1204. and edi, 3ffh
  1205. mov word ptr [esi+4], di
  1206. mov ax, [esi]
  1207. mov Status, ax
  1208. mov ax, [esi+2]
  1209. mov Status+2, ax
  1210. mov ax, [esi+4]
  1211. mov Status+4, ax
  1212. mov eax, ERROR_SUCCESS
  1213. Stat_Complete:
  1214. mov Result, eax
  1215. mov Clks, ebx
  1216. pop esi
  1217. pop edi
  1218. }
  1219. // ----------------
  1220. ReadStatusExit:
  1221. // ----------------
  1222. for (StatusPacket->ClocksSampled = 0; Clks >> (StatusPacket->ClocksSampled+1); StatusPacket->ClocksSampled++);
  1223. StatusPacket->TimeStamp = TIMER_GetTickCount ();
  1224. StatusPacket->LastError = Result;
  1225. StatusPacket->LastError = Result;
  1226. StatusPacket->Transaction = MSGAME_TRANSACT_STATUS;
  1227. PORTIO_UnMaskInterrupts ();
  1228. PORTIO_ReleasePort (PortInfo);
  1229. #if (DBG==1)
  1230. switch (Result)
  1231. {
  1232. case ERROR_SUCCESS:
  1233. MsGamePrint ((DBG_VERBOSE, "SW3DFF_ReadStatus - SUCCEEDED, Data=0x%X%X%X,Clk=%ld\n", (ULONG)Status[2],(ULONG)Status[1],(ULONG)Status[0],Clks));
  1234. break;
  1235. case ERROR_LOWCLOCKSTART:
  1236. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadStatus - TimeOut@LowClockStart\n"));
  1237. break;
  1238. case ERROR_HIGHCLOCKSTART:
  1239. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadStatus - TimeOut@HighClockStart\n"));
  1240. break;
  1241. case ERROR_CLOCKFALLING:
  1242. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadStatus - TimeOut@ClockFalling, Clk=%ld\n", Clks));
  1243. break;
  1244. case ERROR_CLOCKRISING:
  1245. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadStatus - TimeOut@ClockRising, Clk=%ld\n", Clks));
  1246. break;
  1247. }
  1248. #endif
  1249. MSGAME_PostTransaction (StatusPacket);
  1250. return (!Result);
  1251. }
  1252. //---------------------------------------------------------------------------
  1253. // @func Force feedback reset service
  1254. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1255. // @rdesc Returns NT status code
  1256. // @comm Private function
  1257. //---------------------------------------------------------------------------
  1258. NTSTATUS SW3DFF_ForceReset (PGAMEPORT PortInfo)
  1259. {
  1260. if (!SW3DFF_ResetDevice (PortInfo))
  1261. return (STATUS_DEVICE_NOT_CONNECTED);
  1262. return (STATUS_SUCCESS);
  1263. }
  1264. //---------------------------------------------------------------------------
  1265. // @func Force feedback status service
  1266. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1267. // @parm PVOID | Id | Id output buffer
  1268. // @rdesc Returns NT status code
  1269. // @comm Private function
  1270. //---------------------------------------------------------------------------
  1271. NTSTATUS SW3DFF_ForceId (PGAMEPORT PortInfo, PVOID Id)
  1272. {
  1273. PPRODUCT_ID pProduct = (PPRODUCT_ID)Id;
  1274. PSW3DFF_ID pSw3dff = (PSW3DFF_ID)&RawId;
  1275. if (!SW3DFF_ReadId (&IdInfo))
  1276. return (STATUS_DEVICE_NOT_CONNECTED);
  1277. pProduct->cBytes = sizeof (PRODUCT_ID);
  1278. pProduct->dwProductID = pSw3dff->ProductId;
  1279. pProduct->dwFWVersion = pSw3dff->Version;
  1280. return (STATUS_SUCCESS);
  1281. }
  1282. //---------------------------------------------------------------------------
  1283. // @func Force feedback status service
  1284. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1285. // @parm PVOID | Status | Status output buffer
  1286. // @rdesc Returns NT status code
  1287. // @comm Private function
  1288. //---------------------------------------------------------------------------
  1289. NTSTATUS SW3DFF_ForceStatus (PGAMEPORT PortInfo, PVOID Status)
  1290. {
  1291. PJOYCHANNELSTATUS pChannel = (PJOYCHANNELSTATUS)Status;
  1292. PSW3DFF_STATUS pSw3dff = (PSW3DFF_STATUS)&RawStatus;
  1293. if (!SW3DFF_ReadStatus (&StatusInfo))
  1294. return (STATUS_DEVICE_NOT_CONNECTED);
  1295. pChannel->cBytes = sizeof (JOYCHANNELSTATUS);
  1296. pChannel->dwXVel = pSw3dff->xVelocity;
  1297. pChannel->dwYVel = pSw3dff->yVelocity;
  1298. pChannel->dwXAccel = pSw3dff->xAccel;
  1299. pChannel->dwYAccel = pSw3dff->yAccel;
  1300. pChannel->dwEffect = 0;
  1301. pChannel->dwDeviceStatus = pSw3dff->Status & 0x3ff;
  1302. return (STATUS_SUCCESS);
  1303. }
  1304. //---------------------------------------------------------------------------
  1305. // @func Force feedback acknak service
  1306. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1307. // @parm PULONG | AckNak | AckNak
  1308. // @rdesc Returns NT status code
  1309. // @comm Private function
  1310. //---------------------------------------------------------------------------
  1311. NTSTATUS SW3DFF_ForceAckNak (PGAMEPORT PortInfo, PULONG AckNak)
  1312. {
  1313. if (!PORTIO_GetAckNak (PortInfo, StatusGateTimeout, (PUCHAR)AckNak))
  1314. return (STATUS_DEVICE_NOT_CONNECTED);
  1315. return (STATUS_SUCCESS);
  1316. }
  1317. //---------------------------------------------------------------------------
  1318. // @func Force feedback NakAck service
  1319. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1320. // @parm PULONG | NakAck | NakAck
  1321. // @rdesc Returns NT status code
  1322. // @comm Private function
  1323. //---------------------------------------------------------------------------
  1324. NTSTATUS SW3DFF_ForceNakAck (PGAMEPORT PortInfo, PULONG NakAck)
  1325. {
  1326. if (!PORTIO_GetNakAck (PortInfo, StatusGateTimeout, (PUCHAR)NakAck))
  1327. return (STATUS_DEVICE_NOT_CONNECTED);
  1328. return (STATUS_SUCCESS);
  1329. }
  1330. //---------------------------------------------------------------------------
  1331. // @func Force feedback sync service
  1332. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1333. // @parm PULONG | NakAck | NakAck
  1334. // @rdesc Returns NT status code
  1335. // @comm Private function
  1336. //---------------------------------------------------------------------------
  1337. NTSTATUS SW3DFF_ForceSync (PGAMEPORT PortInfo, PULONG Sync)
  1338. {
  1339. *Sync = PORTIO_Read (PortInfo);
  1340. return (STATUS_SUCCESS);
  1341. }
  1342. //---------------------------------------------------------------------------
  1343. // @func Driver entry point for device
  1344. // @rdesc Returns NT status code
  1345. // @comm Private function
  1346. //---------------------------------------------------------------------------
  1347. NTSTATUS SW3DFF_DriverEntry (VOID)
  1348. {
  1349. MsGamePrint((DBG_INFORM,"SW3DFF: SW3DFF_DriverEntry Enter\n"));
  1350. //
  1351. // Read timing values from registry
  1352. //
  1353. MSGAME_ReadRegistry (DEVICENAME, &Delays);
  1354. return (STATUS_SUCCESS);
  1355. }
  1356. //---------------------------------------------------------------------------
  1357. // @func Establishes connection to device by detection
  1358. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1359. // @rdesc Returns NT Status code
  1360. // @comm Private function
  1361. //---------------------------------------------------------------------------
  1362. NTSTATUS SW3DFF_ConnectDevice (PGAMEPORT PortInfo)
  1363. {
  1364. NTSTATUS ntStatus;
  1365. ULONG i = MAX_CONNECT_ATTEMPTS;
  1366. MsGamePrint ((DBG_INFORM, "SW3DFF_ConnectDevice enter\n"));
  1367. DataInfo.PortInfo = IdInfo.PortInfo = StatusInfo.PortInfo = *PortInfo;
  1368. //
  1369. // Convert registry timing values
  1370. //
  1371. SW3DFF_Calibrate (PortInfo);
  1372. //
  1373. // SW3DFF Connection method (try these steps twice)
  1374. //
  1375. do
  1376. {
  1377. //
  1378. // 1. Delay 1 millisecond.
  1379. //
  1380. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  1381. //
  1382. // 2. Get the ID string.
  1383. //
  1384. MsGamePrint ((DBG_CONTROL, "SW3DFF: DeviceConnectProc getting ID string\n"));
  1385. if (!SW3DFF_GetId (&IdInfo))
  1386. continue;
  1387. //
  1388. // 3. Delay 1 millisecond.
  1389. //
  1390. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  1391. //
  1392. // 4. Reset device (tri-state midi so we don't get unintended forces)
  1393. //
  1394. if (!ResetComplete)
  1395. {
  1396. MsGamePrint ((DBG_CONTROL, "SW3DFF_ConnectDevice - resetting device\n"));
  1397. if (!SW3DFF_ResetDevice (&DataInfo.PortInfo))
  1398. continue;
  1399. }
  1400. //
  1401. // 5. Delay 1 millisecond.
  1402. //
  1403. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  1404. //
  1405. // 6. Mark device found and return
  1406. //
  1407. JoltInfo.NumDevices = 1;
  1408. ResetComplete = TRUE;
  1409. return (STATUS_SUCCESS);
  1410. } while (--i);
  1411. //
  1412. // Return error
  1413. //
  1414. JoltInfo.NumDevices = 0;
  1415. return (STATUS_DEVICE_NOT_CONNECTED);
  1416. }
  1417. //---------------------------------------------------------------------------
  1418. // @func Reads and converts HID packet for this device
  1419. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1420. // @parm PUCHAR | Report | Output buffer for report
  1421. // @parm ULONG | MaxSize | Size of buffer for report
  1422. // @parm PULONG | Copied | Bytes copied to buffer for report
  1423. // @rdesc Returns Returns NT status code
  1424. // @comm Private function
  1425. //---------------------------------------------------------------------------
  1426. NTSTATUS SW3DFF_ReadReport (PGAMEPORT PortInfo, PDEVICE_PACKET Report)
  1427. {
  1428. NTSTATUS ntStatus = STATUS_SUCCESS;
  1429. MsGamePrint ((DBG_VERBOSE, "SW3DFF_ReadReport enter\n"));
  1430. //
  1431. // Log number of attempts
  1432. //
  1433. DataInfo.Attempts++;
  1434. //
  1435. // Set up default data to process
  1436. //
  1437. memcpy (DataInfo.Data, ValidData, sizeof (ValidData));
  1438. //
  1439. // Check for collision
  1440. //
  1441. if (DEVICE_IsCollision (&DataInfo))
  1442. {
  1443. MsGamePrint ((DBG_INFORM, "SW3DFF_ReadReport - port collision\n"));
  1444. ntStatus = STATUS_DEVICE_BUSY;
  1445. goto ReadReportExit;
  1446. }
  1447. //
  1448. // Get a packet and check for errors
  1449. //
  1450. ntStatus = SW3DFF_ReadData (&DataInfo);
  1451. if (NT_SUCCESS(ntStatus) && DEVICE_IsOddParity (DataInfo.Data, GAME_PACKET_SIZE))
  1452. {
  1453. memcpy (ValidData, DataInfo.Data, sizeof (ValidData));
  1454. }
  1455. else if (ntStatus != STATUS_DEVICE_BUSY)
  1456. {
  1457. DataInfo.Failures++;
  1458. ntStatus = STATUS_DEVICE_NOT_CONNECTED;
  1459. MsGamePrint ((DBG_SEVERE, "SW3DFF_ReadReport - Invalid packet or parity error\n"));
  1460. }
  1461. else
  1462. {
  1463. MsGamePrint ((DBG_CONTROL, "SW3DFF_ReadReport - Port busy or in use\n"));
  1464. }
  1465. // ---------------
  1466. ReadReportExit:
  1467. // ---------------
  1468. SW3DFF_ProcessData (ValidData, Report);
  1469. //
  1470. // Adjust Throttle jitter
  1471. //
  1472. if (NT_SUCCESS(ntStatus))
  1473. SW3DFF_AdjustThrottle (Report);
  1474. return (ntStatus);
  1475. }
  1476. //---------------------------------------------------------------------------
  1477. // @func Device handler for Pnp Start Device
  1478. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1479. // @rdesc Returns NT status code
  1480. // @comm Private function
  1481. //---------------------------------------------------------------------------
  1482. NTSTATUS SW3DFF_StartDevice (PGAMEPORT PortInfo)
  1483. {
  1484. MsGamePrint ((DBG_INFORM, "SW3DFF_StartDevice enter\n"));
  1485. UNREFERENCED_PARAMETER (PortInfo);
  1486. return (STATUS_SUCCESS);
  1487. }
  1488. //---------------------------------------------------------------------------
  1489. // @func Device handler for Pnp Stop Device
  1490. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1491. // @rdesc Returns NT status code
  1492. // @comm Private function
  1493. //---------------------------------------------------------------------------
  1494. NTSTATUS SW3DFF_StopDevice (PGAMEPORT PortInfo, BOOLEAN TouchHardware)
  1495. {
  1496. MsGamePrint ((DBG_INFORM, "SW3DFF_StopDevice enter\n"));
  1497. UNREFERENCED_PARAMETER (PortInfo);
  1498. UNREFERENCED_PARAMETER (TouchHardware);
  1499. return (STATUS_SUCCESS);
  1500. }
  1501. //---------------------------------------------------------------------------
  1502. // @func Device handler for HID Get Feature requests
  1503. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1504. // @parm HID_REPORT_ID | ReportId | HID Feature Id
  1505. // @parm PVOID | ReportBuffer | Output buffer pointer
  1506. // @parm ULONG | ReportSize | Output buffer size
  1507. // @parm PULONG | Returned | Bytes returned pointer
  1508. // @rdesc Returns NT status code
  1509. // @comm Private function
  1510. //---------------------------------------------------------------------------
  1511. NTSTATUS SW3DFF_GetFeature (PGAMEPORT PortInfo, HID_REPORT_ID ReportId, PVOID ReportBuffer, ULONG ReportSize, PULONG Returned)
  1512. {
  1513. NTSTATUS ntStatus = STATUS_SUCCESS;
  1514. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature enter\n"));
  1515. //
  1516. // Handle feature codes
  1517. //
  1518. switch (ReportId)
  1519. {
  1520. case MSGAME_INPUT_JOYINFOEX:
  1521. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature JoyInfoEx\n"));
  1522. if (ReportSize < sizeof (DEVICE_PACKET)+sizeof(HID_REPORT_ID))
  1523. {
  1524. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1525. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature JoyInfoEx Bad Buffer Size = %lu\n", ReportSize));
  1526. }
  1527. else
  1528. {
  1529. ntStatus = SW3DFF_ReadReport (PortInfo, ReportBuffer);
  1530. *Returned += sizeof (DEVICE_PACKET);
  1531. }
  1532. break;
  1533. case MSGAME_FEATURE_GETID:
  1534. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature GetId\n"));
  1535. if (ReportSize < sizeof(PRODUCT_ID)+sizeof(HID_REPORT_ID))
  1536. {
  1537. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1538. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature GetId Bad Buffer Size = %lu\n", ReportSize));
  1539. }
  1540. else
  1541. {
  1542. ntStatus = SW3DFF_ForceId (PortInfo, ReportBuffer);
  1543. *Returned += sizeof(PRODUCT_ID);
  1544. }
  1545. break;
  1546. case MSGAME_FEATURE_GETSTATUS:
  1547. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature GetStatus\n"));
  1548. if (ReportSize < sizeof(JOYCHANNELSTATUS)+sizeof(HID_REPORT_ID))
  1549. {
  1550. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1551. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature GetStatus Bad Buffer Size = %lu\n", ReportSize));
  1552. }
  1553. else
  1554. {
  1555. ntStatus = SW3DFF_ForceStatus (PortInfo, ReportBuffer);
  1556. *Returned += sizeof(JOYCHANNELSTATUS);
  1557. }
  1558. break;
  1559. case MSGAME_FEATURE_GETACKNAK:
  1560. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature GetAckNak\n"));
  1561. if (ReportSize < sizeof(ULONG)+sizeof(HID_REPORT_ID))
  1562. {
  1563. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1564. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature GetAckNak Bad Buffer Size = %lu\n", ReportSize));
  1565. }
  1566. else
  1567. {
  1568. ntStatus = SW3DFF_ForceAckNak (PortInfo, ReportBuffer);
  1569. *Returned += sizeof(ULONG);
  1570. }
  1571. break;
  1572. case MSGAME_FEATURE_GETNAKACK:
  1573. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature GetNakAck\n"));
  1574. if (ReportSize < sizeof(ULONG)+sizeof(HID_REPORT_ID))
  1575. {
  1576. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1577. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature GetNakAck Bad Buffer Size = %lu\n", ReportSize));
  1578. }
  1579. else
  1580. {
  1581. ntStatus = SW3DFF_ForceNakAck (PortInfo, ReportBuffer);
  1582. *Returned += sizeof(ULONG);
  1583. }
  1584. break;
  1585. case MSGAME_FEATURE_GETSYNC:
  1586. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature GetSync\n"));
  1587. if (ReportSize < sizeof(ULONG)+sizeof(HID_REPORT_ID))
  1588. {
  1589. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1590. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature GetSync Bad Buffer Size = %lu\n", ReportSize));
  1591. }
  1592. else
  1593. {
  1594. ntStatus = SW3DFF_ForceSync (PortInfo, ReportBuffer);
  1595. *Returned += sizeof(ULONG);
  1596. }
  1597. break;
  1598. case MSGAME_FEATURE_RESET:
  1599. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature Reset\n"));
  1600. if (ReportSize < sizeof(HID_REPORT_ID))
  1601. {
  1602. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1603. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature Reset Bad Buffer Size = %lu\n", ReportSize));
  1604. }
  1605. else
  1606. {
  1607. ntStatus = SW3DFF_ForceReset (PortInfo);
  1608. }
  1609. break;
  1610. case MSGAME_FEATURE_GETVERSION:
  1611. MsGamePrint ((DBG_INFORM, "SW3DFF_GetFeature GetVersion\n"));
  1612. if (ReportSize < sizeof(ULONG)+sizeof(HID_REPORT_ID))
  1613. {
  1614. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1615. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature GetVersion Bad Buffer Size = %lu\n", ReportSize));
  1616. }
  1617. else
  1618. {
  1619. *((PULONG)ReportBuffer) = 0x20000;
  1620. *Returned += sizeof(ULONG);
  1621. }
  1622. break;
  1623. default:
  1624. MsGamePrint ((DBG_SEVERE, "SW3DFF_GetFeature Invalid ReportId = %lu\n", ReportId));
  1625. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1626. break;
  1627. }
  1628. return (ntStatus);
  1629. }
  1630. //**************************************************************************
  1631. #endif // SAITEK
  1632. //**************************************************************************