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.

2182 lines
66 KiB

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