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.

1424 lines
39 KiB

  1. //**************************************************************************
  2. //
  3. // SWGAMPAD.C -- Xena Gaming Project
  4. //
  5. // Version 3.XX
  6. //
  7. // Copyright (c) 1997 Microsoft Corporation. All rights reserved.
  8. //
  9. // @doc
  10. // @module SWGAMPAD.C | Gameport mini-driver for GamePads
  11. //**************************************************************************
  12. #ifndef SAITEK
  13. #include "msgame.h"
  14. //---------------------------------------------------------------------------
  15. // Definitions
  16. //---------------------------------------------------------------------------
  17. #define DEVICENAME "SWGAMPAD"
  18. #define DEVICE_PID 0x0003
  19. #define HARDWARE_ID L"Gameport\\SideWindergamepad\0\0"
  20. //
  21. // Packet Constants
  22. //
  23. #define GAME_PACKET_SIZE 32
  24. #define GAME_PACKET_BUTTONS 10
  25. #define GAME_Y_UP_BIT 0x01
  26. #define GAME_Y_DOWN_BIT 0x02
  27. #define GAME_Y_BITS (GAME_Y_UP_BIT|GAME_Y_DOWN_BIT)
  28. #define GAME_X_LEFT_BIT 0x04
  29. #define GAME_X_RIGHT_BIT 0x08
  30. #define GAME_X_BITS (GAME_X_LEFT_BIT|GAME_X_RIGHT_BIT)
  31. #define GAME_BUTTON_BITS 0x3ff0
  32. //
  33. // Id Definitions
  34. //
  35. #define GAME_ID_STRING "H0003"
  36. //
  37. // Timing Constants
  38. //
  39. #define PACKET_START_TIMEOUT 500
  40. #define PACKET_LOWHIGH_TIMEOUT 75
  41. #define PACKET_HIGHLOW_TIMEOUT 150
  42. #define PACKET_INTERRUPT_DELAY 45
  43. #define ID_START_TIMEOUT 500
  44. #define ID_LOWHIGH_TIMEOUT 75
  45. #define ID_HIGHLOW_TIMEOUT 150
  46. #define MAX_CLOCK_DUTY_CYCLE 50
  47. #define MAX_STD_SCLKS 150
  48. //
  49. // Joystick Extents
  50. //
  51. #define EXTENTS_X_MIN 1
  52. #define EXTENTS_X_MID 0x80
  53. #define EXTENTS_X_MAX 0xff
  54. #define EXTENTS_Y_MIN 1
  55. #define EXTENTS_Y_MID 0x80
  56. #define EXTENTS_Y_MAX 0xff
  57. //---------------------------------------------------------------------------
  58. // Types
  59. //---------------------------------------------------------------------------
  60. typedef struct
  61. { // @struct SWGAMPAD_ID | GamePad Id String
  62. #pragma pack(1)
  63. UCHAR OpenParen; // @field Open parentheses
  64. UCHAR EisaId[5]; // @field Eisa bus Id
  65. USHORT Version[3]; // @field Firmware version
  66. UCHAR CloseParen; // @field Close parentheses
  67. UCHAR Reserved[22]; // @field Reserved
  68. #pragma pack()
  69. } SWGAMPAD_ID, *PSWGAMPAD_ID;
  70. //---------------------------------------------------------------------------
  71. // Procedures
  72. //---------------------------------------------------------------------------
  73. static VOID SWGAMPAD_Calibrate (PGAMEPORT PortInfo);
  74. static BOOLEAN SWGAMPAD_GoAnalog (PPACKETINFO Packet1, PPACKETINFO Packet2);
  75. static BOOLEAN SWGAMPAD_ReadId (PPACKETINFO DataPacket, PPACKETINFO IdPacket);
  76. static BOOLEAN SWGAMPAD_GetId (PPACKETINFO IdPacket);
  77. static NTSTATUS SWGAMPAD_ReadData (PPACKETINFO DataPacket);
  78. static BOOLEAN SWGAMPAD_Read1Wide (PPACKETINFO DataPacket);
  79. static BOOLEAN SWGAMPAD_Read3Wide (PPACKETINFO DataPacket);
  80. static BOOLEAN SWGAMPAD_ValidateData (PPACKETINFO DataPacket);
  81. static VOID SWGAMPAD_ProcessData (ULONG UnitId, USHORT Data[], PDEVICE_PACKET Report);
  82. //---------------------------------------------------------------------------
  83. // Services
  84. //---------------------------------------------------------------------------
  85. static NTSTATUS SWGAMPAD_DriverEntry (VOID);
  86. static NTSTATUS SWGAMPAD_ConnectDevice (PGAMEPORT PortInfo);
  87. static NTSTATUS SWGAMPAD_StartDevice (PGAMEPORT PortInfo);
  88. static NTSTATUS SWGAMPAD_ReadReport (PGAMEPORT PortInfo, PDEVICE_PACKET Report);
  89. static NTSTATUS SWGAMPAD_StopDevice (PGAMEPORT PortInfo, BOOLEAN TouchHardware);
  90. //---------------------------------------------------------------------------
  91. // Alloc_text pragma to specify routines that can be paged out.
  92. //---------------------------------------------------------------------------
  93. #ifdef ALLOC_PRAGMA
  94. #pragma alloc_text (INIT, SWGAMPAD_DriverEntry)
  95. #endif
  96. //---------------------------------------------------------------------------
  97. // Private Data
  98. //---------------------------------------------------------------------------
  99. //
  100. // HID Descriptors
  101. //
  102. static UCHAR ReportDescriptor[] =
  103. {
  104. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_GENERIC, // USAGE_PAGE (Generic Desktop)
  105. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_JOYSTICK,// USAGE (Joystick)
  106. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_APP, // COLLECTION (Application)
  107. //id
  108. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  109. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  110. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  111. //do_other
  112. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  113. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  114. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  115. //dwX / dwY
  116. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_POINTER, // USAGE (Pointer)
  117. HIDP_MAIN_COLLECTION, HIDP_MAIN_COLLECTION_LINK, // COLLECTION (Linked)
  118. HIDP_GLOBAL_LOG_MIN_1, 0x01, // LOGICAL_MINIMUM (1)
  119. HIDP_GLOBAL_LOG_MAX_4, 0xFF, 0x00, 0x00, 0x00, // LOGICAL_MAXIMUM (255)
  120. HIDP_GLOBAL_PHY_MIN_1, 0x01, // PHYSICAL_MINIMUM (1)
  121. HIDP_GLOBAL_PHY_MAX_4, 0xFF, 0x00, 0x00, 0x00, // PHYSICAL_MAXIMUM (255)
  122. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  123. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  124. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  125. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_X, // USAGE (X)
  126. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  127. HIDP_LOCAL_USAGE_1, HID_USAGE_GENERIC_Y, // USAGE (Y)
  128. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  129. HIDP_MAIN_ENDCOLLECTION, // END_COLLECTION
  130. //dwZ
  131. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  132. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  133. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  134. //dwR
  135. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  136. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  137. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  138. //dwU
  139. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  140. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  141. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  142. //dwV
  143. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  144. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  145. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  146. //dwPOV
  147. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (32)
  148. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  149. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  150. //dwButtons
  151. HIDP_GLOBAL_USAGE_PAGE_1, HID_USAGE_PAGE_BUTTON, // USAGE_PAGE (Button)
  152. HIDP_LOCAL_USAGE_MIN_1, 0x01, // USAGE_MINIMUM (Button 1)
  153. HIDP_LOCAL_USAGE_MAX_1, 0x0A, // USAGE_MAXIMUM (Button 10)
  154. HIDP_GLOBAL_LOG_MIN_1, 0x00, // LOGICAL_MINIMUM (0)
  155. HIDP_GLOBAL_LOG_MAX_1, 0x01, // LOGICAL_MAXIMUM (1)
  156. HIDP_GLOBAL_PHY_MIN_1, 0x00, // PHYSICAL_MINIMUM (0)
  157. HIDP_GLOBAL_PHY_MAX_1, 0x01, // PHYSICAL_MAXIMUM (1)
  158. HIDP_GLOBAL_UNIT_2, 0x00, 0x00, // UNIT (None)
  159. HIDP_GLOBAL_REPORT_SIZE, 0x01, // REPORT_SIZE (1)
  160. HIDP_GLOBAL_REPORT_COUNT_1,0x20, // REPORT_COUNT (32)
  161. HIDP_MAIN_INPUT_1, 0x02, // INPUT (Data,Var,Abs)
  162. //dwButtonNumber
  163. HIDP_GLOBAL_REPORT_SIZE, 0x20, // REPORT_SIZE (20)
  164. HIDP_GLOBAL_REPORT_COUNT_1,0x01, // REPORT_COUNT (1)
  165. HIDP_MAIN_INPUT_1, 0x01, // INPUT (Cnst,Ary,Abs)
  166. //END OF COLLECTION
  167. HIDP_MAIN_ENDCOLLECTION // END_COLLECTION
  168. };
  169. static HID_DESCRIPTOR DeviceDescriptor =
  170. {
  171. sizeof (HID_DESCRIPTOR),
  172. HID_HID_DESCRIPTOR_TYPE,
  173. MSGAME_HID_VERSION,
  174. MSGAME_HID_COUNTRY,
  175. MSGAME_HID_DESCRIPTORS,
  176. {HID_REPORT_DESCRIPTOR_TYPE,
  177. sizeof(ReportDescriptor)}
  178. };
  179. //
  180. // Raw Data Buffer
  181. //
  182. static USHORT RawData[GAME_PACKET_SIZE/sizeof(USHORT)] =
  183. {
  184. 0
  185. };
  186. //
  187. // Raw Id Buffer
  188. //
  189. static SWGAMPAD_ID RawId =
  190. {
  191. 0
  192. };
  193. //
  194. // Timing Variables
  195. //
  196. static DEVICE_VALUES Delays =
  197. {
  198. PACKET_START_TIMEOUT,
  199. PACKET_HIGHLOW_TIMEOUT,
  200. PACKET_LOWHIGH_TIMEOUT,
  201. ID_START_TIMEOUT,
  202. ID_HIGHLOW_TIMEOUT,
  203. ID_LOWHIGH_TIMEOUT,
  204. PACKET_INTERRUPT_DELAY,
  205. MAX_CLOCK_DUTY_CYCLE,
  206. 0,0,0,0 // No status packet used
  207. };
  208. //
  209. // Data Packet Info
  210. //
  211. static PACKETINFO DataInfo =
  212. {
  213. sizeof (PACKETINFO), // Size of structure
  214. DEVICENAME, // Name of device
  215. MSGAME_TRANSACT_NONE, // Transaction type
  216. IMODE_DIGITAL_STD, // Interface mode
  217. GAME_SPEED_100K, // Transmission speed
  218. ERROR_SUCCESS, // Last internal error result
  219. {0}, // Game port info
  220. FLAG_WAIT_FOR_CLOCK, // Packet acquisition mode
  221. 1, // Number of packets received
  222. 0, // Last valid acquisition time stamp
  223. 0, // Number of clocks sampled
  224. 0, // Number of B4 line transitions (std mode only)
  225. 0, // Start timeout period (in samples)
  226. 0, // Clock High to Low timeout period (in samples)
  227. 0, // Clock Low to High timeout period (in samples)
  228. 0, // Interrupt Timeout period
  229. 0, // Maximum clock duty cycle
  230. 0, // Number of Packet Failures
  231. 0, // Number of Packet Attempts
  232. sizeof (RawData), // Size of raw data buffer
  233. RawData // Pointer to Raw data
  234. };
  235. //
  236. // ID Packet Info
  237. //
  238. static PACKETINFO IdInfo =
  239. {
  240. sizeof (PACKETINFO), // Size of structure
  241. DEVICENAME, // Name of device
  242. MSGAME_TRANSACT_NONE, // Transaction type
  243. IMODE_DIGITAL_STD, // Interface mode
  244. GAME_SPEED_100K, // Transmission speed
  245. ERROR_SUCCESS, // Last internal error result
  246. {0}, // Game port info
  247. FLAG_START_CLOCK_LOW, // Packet acquisition mode
  248. 1, // Number of packets received
  249. 0, // Last valid acquisition time stamp
  250. 0, // Number of clocks sampled
  251. 0, // Number of B4 line transitions (std mode only)
  252. 0, // Start timeout period (in samples)
  253. 0, // Clock High to Low timeout period (in samples)
  254. 0, // Clock Low to High timeout period (in samples)
  255. 0, // Interrupt Timeout period
  256. 0, // Maximum clock duty cycle
  257. 0, // Number of Packet Failures
  258. 0, // Number of Packet Attempts
  259. sizeof (RawId), // Size of raw id buffer
  260. &RawId // Pointer to Raw data
  261. };
  262. //
  263. // Services Table
  264. //
  265. static DRIVERSERVICES Services =
  266. {
  267. SWGAMPAD_DriverEntry, // DriverEntry
  268. SWGAMPAD_ConnectDevice, // ConnectDevice
  269. SWGAMPAD_StartDevice, // StartDevice
  270. SWGAMPAD_ReadReport, // ReadReport
  271. SWGAMPAD_StopDevice, // StopDevice
  272. NULL // GetFeature
  273. };
  274. //
  275. // Last Valid Data
  276. //
  277. static USHORT ValidData[GAME_PACKET_SIZE/sizeof(USHORT)] =
  278. {
  279. GAME_BUTTON_BITS,
  280. GAME_BUTTON_BITS,
  281. GAME_BUTTON_BITS,
  282. GAME_BUTTON_BITS
  283. };
  284. //
  285. // Interrupt Flags
  286. //
  287. static UCHAR InterruptFlags = 0;
  288. //
  289. // Hardware ID String
  290. //
  291. static WCHAR HardwareId[] = HARDWARE_ID;
  292. //---------------------------------------------------------------------------
  293. // Public Data
  294. //---------------------------------------------------------------------------
  295. public DEVICEINFO GamePadInfo =
  296. {
  297. &Services, // Service table
  298. NULL, // Sibling device list
  299. &DeviceDescriptor, // Device descriptor data
  300. ReportDescriptor, // Report descriptor data
  301. sizeof(ReportDescriptor), // Report descriptor size
  302. 0, // Number of devices detected
  303. 0, // Number of devices started
  304. 0, // Number of devices pending
  305. DEVICENAME, // Name of device
  306. DETECT_NORMAL, // Detection order
  307. FALSE, // Analog device flag
  308. DEVICE_PID, // Hid device identifier
  309. HardwareId // PnP hardware identifier
  310. };
  311. //---------------------------------------------------------------------------
  312. // @func Reads registry timing values and calibrates them
  313. // @parm PGAMEPORT | PortInfo | Gameport parameters
  314. // @rdesc Returns nothing
  315. // @comm Private function
  316. //---------------------------------------------------------------------------
  317. VOID SWGAMPAD_Calibrate (PGAMEPORT PortInfo)
  318. {
  319. MsGamePrint((DBG_INFORM,"SWGAMPAD: SWGAMPAD_Calibrate Enter\n"));
  320. //
  321. // Convert timing values to counts
  322. //
  323. DataInfo.StartTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketStartTimeout);
  324. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: DataInfo.StartTimeout = %ld\n", DataInfo.StartTimeout));
  325. DataInfo.LowHighTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketLowHighTimeout);
  326. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: DataInfo.LowHighTimeout = %ld\n", DataInfo.LowHighTimeout));
  327. DataInfo.HighLowTimeout = TIMER_CalibratePort (PortInfo, Delays.PacketHighLowTimeout);
  328. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: DataInfo.HighLowTimeout = %ld\n", DataInfo.HighLowTimeout));
  329. IdInfo.StartTimeout = TIMER_CalibratePort (PortInfo, Delays.IdStartTimeout);
  330. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: IdInfo.StartTimeout = %ld\n", IdInfo.StartTimeout));
  331. IdInfo.LowHighTimeout = TIMER_CalibratePort (PortInfo, Delays.IdLowHighTimeout);
  332. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: IdInfo.LowHighTimeout=%ld\n", IdInfo.LowHighTimeout));
  333. IdInfo.HighLowTimeout = TIMER_CalibratePort (PortInfo, Delays.IdHighLowTimeout);
  334. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: IdInfo.HighLowTimeout=%ld\n", IdInfo.HighLowTimeout));
  335. DataInfo.ClockDutyCycle = TIMER_CalibratePort (PortInfo, Delays.MaxClockDutyCycle);
  336. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: DataInfo.ClockDutyCycle = %ld\n", DataInfo.ClockDutyCycle));
  337. IdInfo.ClockDutyCycle = TIMER_CalibratePort (PortInfo, Delays.MaxClockDutyCycle);
  338. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: IdInfo.ClockDutyCycle = %ld\n", IdInfo.ClockDutyCycle));
  339. DataInfo.InterruptDelay = Delays.InterruptDelay;
  340. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: DataInfo.InterruptDelay = %ld\n", DataInfo.InterruptDelay));
  341. IdInfo.InterruptDelay = Delays.InterruptDelay;
  342. MsGamePrint((DBG_VERBOSE, "SWGAMPAD: IdInfo.InterruptDelay = %ld\n", IdInfo.InterruptDelay));
  343. }
  344. //---------------------------------------------------------------------------
  345. // @func Puts Gamepads into analog mode
  346. // @parm PPACKETINFO | Packet1 | Data packet
  347. // @parm PPACKETINFO | Packet2 | Id packet
  348. // @rdesc True if successful, False otherwise
  349. // @comm Private function
  350. //---------------------------------------------------------------------------
  351. BOOLEAN SWGAMPAD_GoAnalog (PPACKETINFO Packet1, PPACKETINFO Packet2)
  352. {
  353. LONG Result = ERROR_SUCCESS;
  354. PGAMEPORT PortInfo = &Packet1->PortInfo;
  355. MsGamePrint ((DBG_INFORM, "SWGAMPAD_ResetDevice enter\n"));
  356. if (!PORTIO_AcquirePort (PortInfo))
  357. return (FALSE);
  358. PORTIO_MaskInterrupts ();
  359. InterruptFlags = INTERRUPT_AFTER_PACKET;
  360. Packet1->B4Transitions = 0;
  361. Packet1->ClocksSampled = 0;
  362. PORTIO_Write (PortInfo, 0);
  363. if (!(PORTIO_Read (PortInfo) & XA_BIT_MASK))
  364. {
  365. Result = ERROR_XA_TIMEOUT;
  366. }
  367. else
  368. {
  369. if (Packet1->Mode == IMODE_DIGITAL_ENH)
  370. SWGAMPAD_Read3Wide (Packet1);
  371. else SWGAMPAD_Read1Wide (Packet1);
  372. Packet2->B4Transitions = 0;
  373. Packet2->ClocksSampled = 0;
  374. if (Packet2->Mode == IMODE_DIGITAL_ENH)
  375. {
  376. SWGAMPAD_Read3Wide (Packet2);
  377. Result = Packet2->LastError;
  378. }
  379. else SWGAMPAD_Read1Wide (Packet2);
  380. }
  381. Packet1->B4Transitions = 0;
  382. Packet1->ClocksSampled = 0;
  383. Packet2->B4Transitions = 0;
  384. Packet2->ClocksSampled = 0;
  385. InterruptFlags = 0;
  386. DataInfo.LastError = Result;
  387. DataInfo.Transaction = MSGAME_TRANSACT_GOANALOG;
  388. PORTIO_UnMaskInterrupts ();
  389. PORTIO_ReleasePort (PortInfo);
  390. if (Result == ERROR_SUCCESS)
  391. DataInfo.Mode = IdInfo.Mode = IMODE_ANALOG;
  392. else MsGamePrint ((DBG_SEVERE, "SWGAMPAD_ResetDevice (GoAnalog) Failed\n"));
  393. MSGAME_PostTransaction (&DataInfo);
  394. return (!Result);
  395. }
  396. //---------------------------------------------------------------------------
  397. // @func Reads device id string from port
  398. // @parm PPACKETINFO | DataPacket | Data packet parameters
  399. // @parm PPACKETINFO | IdPacket | ID packet parameters
  400. // @rdesc True if successful, False otherwise
  401. // @comm Private function
  402. //---------------------------------------------------------------------------
  403. BOOLEAN SWGAMPAD_ReadId (PPACKETINFO DataPacket, PPACKETINFO IdPacket)
  404. {
  405. LONG Result = ERROR_SUCCESS;
  406. PGAMEPORT PortInfo = &DataPacket->PortInfo;
  407. MsGamePrint ((DBG_INFORM, "SWGAMPAD_ReadId enter\n"));
  408. if (!PORTIO_AcquirePort (PortInfo))
  409. return (FALSE);
  410. PORTIO_MaskInterrupts ();
  411. InterruptFlags = INTERRUPT_AFTER_PACKET;
  412. DataPacket->B4Transitions = 0;
  413. DataPacket->ClocksSampled = 0;
  414. PORTIO_Write (PortInfo, 0);
  415. if (!(PORTIO_Read (PortInfo) & XA_BIT_MASK))
  416. {
  417. Result = ERROR_XA_TIMEOUT;
  418. }
  419. else
  420. {
  421. if (DataPacket->Mode == IMODE_DIGITAL_ENH)
  422. SWGAMPAD_Read3Wide (DataPacket);
  423. else SWGAMPAD_Read1Wide (DataPacket);
  424. InterruptFlags = 0;
  425. IdPacket->B4Transitions = 0;
  426. IdPacket->ClocksSampled = 0;
  427. SWGAMPAD_Read1Wide (IdPacket);
  428. Result = IdPacket->LastError;
  429. }
  430. IdPacket->LastError = Result;
  431. IdPacket->Transaction = MSGAME_TRANSACT_ID;
  432. PORTIO_UnMaskInterrupts ();
  433. PORTIO_ReleasePort (PortInfo);
  434. if (Result != ERROR_SUCCESS)
  435. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_GetId Failed\n"));
  436. MSGAME_PostTransaction (IdPacket);
  437. return (!Result);
  438. }
  439. //---------------------------------------------------------------------------
  440. // @func Reads and validates device id string
  441. // @parm PPACKETINFO | IdPacket | ID Packet parameters
  442. // @rdesc True if successful, False otherwise
  443. // @comm Private function
  444. //---------------------------------------------------------------------------
  445. BOOLEAN SWGAMPAD_GetId (PPACKETINFO IdPacket)
  446. {
  447. BOOLEAN Result = FALSE;
  448. MsGamePrint ((DBG_INFORM, "SWGAMPAD_GetId enter\n"));
  449. IdPacket->Attempts++;
  450. if (SWGAMPAD_ReadId (&DataInfo, IdPacket))
  451. {
  452. ULONG i;
  453. PUSHORT p;
  454. PSWGAMPAD_ID pId;
  455. //
  456. // Remove parity bit and convert to words
  457. //
  458. p = IdPacket->Data;
  459. for (i = 0; i < 5; i++, p++)
  460. *p = ((*p<<1) & 0x7f00) | (*p & 0x7f);
  461. //
  462. // Check Id String
  463. //
  464. pId = (PSWGAMPAD_ID)IdPacket->Data;
  465. if (!strncmp (pId->EisaId, GAME_ID_STRING, strlen(GAME_ID_STRING)))
  466. {
  467. if (IdPacket->B4Transitions > 10)
  468. {
  469. DataInfo.Mode = IdInfo.Mode = IMODE_DIGITAL_ENH;
  470. }
  471. else
  472. {
  473. SWGAMPAD_GoAnalog (&DataInfo, &IdInfo);
  474. DataInfo.Mode = IdInfo.Mode = IMODE_DIGITAL_STD;
  475. }
  476. Result = TRUE;
  477. }
  478. else MsGamePrint ((DBG_SEVERE, "SWGAMPAD_GetId - Id string did not match = 0x%X\n", (ULONG)(*(PULONG)&pId->EisaId)));
  479. }
  480. if (!Result)
  481. IdPacket->Failures++;
  482. return (Result);
  483. }
  484. //---------------------------------------------------------------------------
  485. // @func Reads 1 wide data packet from gameport
  486. // @parm PPACKETINFO | DataPacket| Data packet parameters
  487. // @rdesc True if successful, False otherwise
  488. // @comm Private function
  489. //---------------------------------------------------------------------------
  490. #if _MSC_FULL_VER >= 13008827 && defined(_M_IX86)
  491. #pragma warning(disable:4731) // EBP modified with inline asm
  492. #endif
  493. BOOLEAN SWGAMPAD_Read1Wide (PPACKETINFO DataPacket)
  494. {
  495. LONG Result;
  496. // MsGamePrint ((DBG_VERBOSE, "SWGAMPAD_Read1Wide enter\n"));
  497. __asm
  498. {
  499. push edi
  500. push esi
  501. push ebp
  502. mov edi, DataPacket
  503. mov esi, (PPACKETINFO [edi]).Data
  504. lea edx, (PPACKETINFO [edi]).PortInfo
  505. mov ebx, 10000h
  506. xor ebp, ebp
  507. xor eax, eax
  508. test (PPACKETINFO [edi]).Acquisition, FLAG_START_CLOCK_LOW
  509. jnz Std_StartClockLow
  510. ; make sure clock is "high" before sampling clocks...
  511. mov ecx, (PPACKETINFO [edi]).StartTimeout
  512. Std_StartClockHigh:
  513. push edx ; read byte from gameport
  514. call PORTIO_Read
  515. test al, CLOCK_BIT_MASK ; Q: Start of Packet ?
  516. jz Std_StartHighToLow ; Y: jump
  517. dec ecx
  518. jnz Std_StartClockHigh ; else keep looping
  519. mov eax, ERROR_LOWCLOCKSTART
  520. jmp PacketDone ; Time out error.
  521. Std_StartHighToLow:
  522. mov ecx, (PPACKETINFO [edi]).StartTimeout
  523. Std_StartHighToLow_1:
  524. push edx ; read byte from gameport
  525. call PORTIO_Read
  526. test al, CLOCK_BIT_MASK ; Q: clock = 0
  527. jz Std_LowToHigh ; Y: jump.
  528. dec ecx
  529. jnz Std_StartHighToLow_1 ; else see if we timed out
  530. mov eax, ERROR_CLOCKFALLING
  531. jmp PacketDone ; Time out error.
  532. Std_StartClockLow:
  533. ; wait for clock to transition to "high" (sample immediately)
  534. mov ecx, (PPACKETINFO [edi]).StartTimeout
  535. Std_StartClockLow_1:
  536. push edx ; read byte from gameport
  537. call PORTIO_Read
  538. test al, CLOCK_BIT_MASK ; Q: Clock went high ?
  539. jnz CollectData ; Y: jump (sample data)
  540. dec ecx
  541. jnz Std_StartClockLow_1 ; else keep looping
  542. mov eax, ERROR_CLOCKRISING
  543. jmp PacketDone ; Time out error.
  544. Std_CheckClkState:
  545. push edx ; read byte from gameport
  546. call PORTIO_Read
  547. test al, CLOCK_BIT_MASK
  548. jz Std_LowToHigh
  549. ;Std_HighToLow:
  550. mov ecx, (PPACKETINFO [edi]).HighLowTimeout
  551. Std_HighToLow_1:
  552. test al, CLOCK_BIT_MASK ; Q: clock = 0
  553. jz Std_LowToHigh ; Y: jump.
  554. push edx ; read byte from gameport
  555. call PORTIO_Read
  556. dec ecx
  557. jnz Std_HighToLow_1 ; else see if we timed out
  558. mov eax, ERROR_CLOCKFALLING
  559. jmp PacketDone ; Time out error.
  560. Std_LowToHigh:
  561. mov ecx, (PPACKETINFO [edi]).LowHighTimeout
  562. Std_LowToHigh_1:
  563. test al, CLOCK_BIT_MASK ; Q: clock high ?
  564. jnz CollectData ; Y: jump. (get data)
  565. push edx ; read byte from gameport
  566. call PORTIO_Read
  567. dec ecx ; else see if we timed out
  568. jnz Std_LowToHigh_1
  569. jmp Std_TestInterrupt
  570. CollectData:
  571. inc ebp
  572. cmp ebp, MAX_STD_SCLKS
  573. jg Std_BufferOverFlow
  574. xor ah, al
  575. test ah, DATA2_BIT_MASK ; Q: Data 2 is toggled ?
  576. jz CollectData_1 ; N: jump.
  577. inc (PPACKETINFO [edi]).B4Transitions ; Y: increment Data 2 count.
  578. CollectData_1:
  579. mov ah, al
  580. shr al, 6 ; put data into carry
  581. rcr bx, 1 ; and then in data counter
  582. add ebx, 10000h ; inc mini packet clk counter
  583. test ebx, 100000h ; Q: done mini packet ?
  584. jz Std_CheckClkState ; N: jump.
  585. shr bx, 1 ; right align
  586. mov word ptr [esi], bx ; move mini packet into buffer
  587. add esi, 2 ; advance data pointer
  588. mov ebx, 10000h ; init mini-packet counter
  589. jmp Std_CheckClkState ; go look for more clocks.
  590. Std_TestInterrupt:
  591. test InterruptFlags, INTERRUPT_AFTER_PACKET; Q: Interrupt packet ?
  592. jnz Std_IntPacket ; Y: jump.
  593. mov eax, ERROR_SUCCESS
  594. jmp PacketDone
  595. Std_IntPacket:
  596. mov ecx, 700
  597. Std_IntPacket_1:
  598. push edx ; read byte from gameport
  599. call PORTIO_Read
  600. test al, INTXA_BIT_MASK
  601. jz Std_IntPacket_2
  602. loop Std_IntPacket_1
  603. mov eax, ERROR_XA_TIMEOUT
  604. jmp PacketDone
  605. Std_IntPacket_2:
  606. cmp ecx, 700
  607. je Std_IntOut
  608. mov ecx, (PPACKETINFO [edi]).InterruptDelay
  609. Std_IntPacket_3:
  610. push edx ; read byte from gameport
  611. call PORTIO_Read
  612. test al, al
  613. xchg al, ah
  614. dec ecx
  615. jnz Std_IntPacket_3
  616. Std_IntOut:
  617. push 0 ; write byte to gameport
  618. push edx
  619. call PORTIO_Write
  620. mov eax, ERROR_SUCCESS
  621. jmp PacketDone
  622. Std_BufferOverFlow:
  623. mov eax, ERROR_CLOCKOVERFLOW
  624. PacketDone:
  625. mov (PPACKETINFO [edi]).ClocksSampled, ebp
  626. pop ebp
  627. pop esi
  628. pop edi
  629. mov Result, eax
  630. }
  631. DataPacket->LastError = Result;
  632. #if (DBG==1)
  633. switch (Result)
  634. {
  635. case ERROR_LOWCLOCKSTART:
  636. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_Read1Wide - TimeOut@LowClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  637. break;
  638. case ERROR_HIGHCLOCKSTART:
  639. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_Read1Wide - TimeOut@HighClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  640. break;
  641. case ERROR_CLOCKFALLING:
  642. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_Read1Wide - TimeOut@ClockFalling, Clk=%ld\n", DataPacket->ClocksSampled));
  643. break;
  644. case ERROR_CLOCKRISING:
  645. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_Read1Wide - TimeOut@ClockRising, Clk=%ld\n", DataPacket->ClocksSampled));
  646. break;
  647. }
  648. #endif
  649. return (!Result);
  650. }
  651. //---------------------------------------------------------------------------
  652. // @func Reads 3 wide data packet from gameport
  653. // @parm PPACKETINFO | DataPacket| Data packet parameters
  654. // @rdesc True if successful, False otherwise
  655. // @comm Private function
  656. //---------------------------------------------------------------------------
  657. BOOLEAN SWGAMPAD_Read3Wide (PPACKETINFO DataPacket)
  658. {
  659. LONG Result;
  660. // MsGamePrint ((DBG_VERBOSE, "SWGAMPAD_Read3Wide enter\n"));
  661. __asm
  662. {
  663. push edi
  664. push esi
  665. push ebp
  666. mov edi, DataPacket
  667. mov esi, (PPACKETINFO [edi]).Data
  668. lea edx, (PPACKETINFO [edi]).PortInfo
  669. xor eax, eax
  670. xor ebx, ebx
  671. xor ebp, ebp
  672. ;StartEnhancedMode:
  673. test (PPACKETINFO [edi]).Acquisition, FLAG_START_CLOCK_LOW
  674. jnz Enh_LowToHigh
  675. ; make sure clock is "high" before sampling clocks...
  676. mov ecx, (PPACKETINFO [edi]).StartTimeout
  677. StartEnhancedMode_1:
  678. push edx ; read byte from gameport
  679. call PORTIO_Read
  680. test al, CLOCK_BIT_MASK ; Q: Start of Packet ?
  681. jnz Enh_StartHighToLow ; Y: jump
  682. dec ecx
  683. jnz StartEnhancedMode_1 ; else keep looping
  684. mov eax, ERROR_LOWCLOCKSTART
  685. jmp Enh_PacketDone ; Time out error.
  686. Enh_StartHighToLow:
  687. mov ecx, (PPACKETINFO [edi]).StartTimeout
  688. Enh_StartHighToLow_1:
  689. push edx ; read byte from gameport
  690. call PORTIO_Read
  691. test al, CLOCK_BIT_MASK ; Q: clock = 0
  692. jz Enh_LowToHigh ; Y: jump.
  693. dec ecx
  694. jnz Enh_StartHighToLow_1 ; else see if we timed out
  695. mov eax, ERROR_HIGHCLOCKSTART
  696. jmp Enh_PacketDone ; Time out error.
  697. ;Enh_StartClockLow:
  698. ; wait for clock to transition to "high" (sample immediately)
  699. mov ecx, (PPACKETINFO [edi]).StartTimeout
  700. Enh_StartClockLow_1:
  701. push edx ; read byte from gameport
  702. call PORTIO_Read
  703. test al, CLOCK_BIT_MASK ; Q: Clock went high ?
  704. jnz Enh_CollectData ; Y: jump (sample data)
  705. dec ecx
  706. jnz Enh_StartClockLow_1 ; else keep looping
  707. mov eax, ERROR_CLOCKFALLING
  708. jmp Enh_PacketDone ; Time out error.
  709. Enh_CheckClkState:
  710. push edx ; read byte from gameport
  711. call PORTIO_Read
  712. test al, CLOCK_BIT_MASK
  713. jz Enh_LowToHigh
  714. ; Wait for clock to transition from high to low.
  715. ;Enh_HighToLow:
  716. mov ecx, (PPACKETINFO [edi]).HighLowTimeout
  717. Enh_HighToLow_1:
  718. test al, CLOCK_BIT_MASK ; Q: Clock Low ?
  719. jz Enh_LowToHigh ; Y: jump.
  720. push edx ; read byte from gameport
  721. call PORTIO_Read
  722. dec ecx
  723. jnz Enh_HighToLow_1 ; if !Timeout continue looping.
  724. mov eax, ERROR_LOWCLOCKSTART
  725. jmp Enh_PacketDone ; Time out error.
  726. ; Wait for clock to transition from low to high.
  727. Enh_LowToHigh:
  728. mov ecx, (PPACKETINFO [edi]).LowHighTimeout
  729. Enh_LowToHigh_1:
  730. test al, CLOCK_BIT_MASK ; Q: Clock = 1 ?
  731. jnz Enh_CollectData ; Y: jump.
  732. push edx ; read byte from gameport
  733. call PORTIO_Read
  734. dec ecx
  735. jnz Enh_LowToHigh_1 ; else continue looping.
  736. jmp Enh_TestInterrupt
  737. Enh_CollectData:
  738. inc ebp ; inc. total clocks sampled
  739. test ebp, 40h
  740. jnz Enh_BufferOverflow
  741. shr al, 5 ; move data to lower 3 bits
  742. shrd ebx, eax, 3 ; shift data into ebx.
  743. add ebp, 10000h ; inc hiword of ebp
  744. mov eax, ebp
  745. shr eax, 16 ; set ax = hiword of ebp
  746. cmp al, 5 ; Q: mini-packet done ?
  747. jne Enh_CheckClkState ; N: jump.
  748. shr ebx, 17
  749. mov word ptr [esi],bx
  750. add esi, 2
  751. and ebp, 0ffffh ; zero out hiword of ebp
  752. jmp Enh_CheckClkState
  753. Enh_TestInterrupt:
  754. test InterruptFlags, INTERRUPT_AFTER_PACKET ; Q: Interrupt packet ?
  755. jz Enh_PacketOK ; N: jump.
  756. ; Wait for XA line to be cleared before we can fire interrupt.
  757. mov ecx, 700
  758. Enh_Interrupt:
  759. push edx ; read byte from gameport
  760. call PORTIO_Read
  761. test al, INTXA_BIT_MASK
  762. jz Enh_Interrupt_1
  763. loop Enh_Interrupt
  764. mov eax, ERROR_XA_TIMEOUT
  765. jmp Enh_PacketDone
  766. Enh_Interrupt_1:
  767. mov ecx, (PPACKETINFO [edi]).InterruptDelay
  768. Enh_Interrupt_2:
  769. push edx ; read byte from gameport
  770. call PORTIO_Read
  771. test al, al
  772. dec ecx
  773. jnz Enh_Interrupt_2
  774. push 0 ; write byte to gameport
  775. push edx
  776. call PORTIO_Write
  777. Enh_PacketOK:
  778. and ebp, 0ffffh
  779. mov (PPACKETINFO [edi]).ClocksSampled, ebp
  780. mov eax, ERROR_SUCCESS
  781. jmp Enh_PacketDone
  782. Enh_BufferOverflow:
  783. mov eax, ERROR_CLOCKOVERFLOW
  784. Enh_PacketDone:
  785. pop ebp
  786. pop esi
  787. pop edi
  788. mov Result, eax
  789. }
  790. DataPacket->LastError = Result;
  791. #if (DBG==1)
  792. switch (Result)
  793. {
  794. case ERROR_LOWCLOCKSTART:
  795. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_Read3Wide - TimeOut@LowClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  796. break;
  797. case ERROR_HIGHCLOCKSTART:
  798. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_Read3Wide - TimeOut@HighClockStart, Clk=%ld\n", DataPacket->ClocksSampled));
  799. break;
  800. case ERROR_CLOCKFALLING:
  801. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_Read3Wide - TimeOut@ClockFalling, Clk=%ld\n", DataPacket->ClocksSampled));
  802. break;
  803. case ERROR_CLOCKRISING:
  804. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_Read3Wide - TimeOut@ClockRising, Clk=%ld\n", DataPacket->ClocksSampled));
  805. break;
  806. }
  807. #endif
  808. return (!Result);
  809. }
  810. //---------------------------------------------------------------------------
  811. // @func Reads data packet from gameport depending on mode
  812. // @parm PPACKETINFO | DataPacket| Data packet parameters
  813. // @rdesc Returns NT status code
  814. // @comm Private function
  815. //---------------------------------------------------------------------------
  816. NTSTATUS SWGAMPAD_ReadData (PPACKETINFO DataPacket)
  817. {
  818. BOOLEAN Result = FALSE;
  819. PGAMEPORT PortInfo = &DataPacket->PortInfo;
  820. MsGamePrint ((DBG_VERBOSE, "SWGAMPAD_ReadData enter\n"));
  821. if (!PORTIO_AcquirePort (PortInfo))
  822. return (STATUS_DEVICE_BUSY);
  823. PORTIO_MaskInterrupts ();
  824. DataPacket->ClocksSampled = 0;
  825. DataPacket->B4Transitions = 0;
  826. InterruptFlags = 0;
  827. switch (DataPacket->Mode)
  828. {
  829. case IMODE_DIGITAL_STD:
  830. PORTIO_Write (PortInfo, 0);
  831. Result = SWGAMPAD_Read1Wide (DataPacket);
  832. break;
  833. case IMODE_DIGITAL_ENH:
  834. PORTIO_Write (PortInfo, 0);
  835. Result = SWGAMPAD_Read3Wide (DataPacket);
  836. break;
  837. default:
  838. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_ReadData - unknown interface\n"));
  839. break;
  840. }
  841. DataPacket->TimeStamp = TIMER_GetTickCount ();
  842. DataPacket->Transaction = MSGAME_TRANSACT_DATA;
  843. PORTIO_UnMaskInterrupts ();
  844. PORTIO_ReleasePort (PortInfo);
  845. MSGAME_PostTransaction (DataPacket);
  846. if (!Result)
  847. return (STATUS_DEVICE_NOT_CONNECTED);
  848. return (STATUS_SUCCESS);
  849. }
  850. //---------------------------------------------------------------------------
  851. // @func Validates raw packet information
  852. // @parm PPACKETINFO | DataPacket| Data packet parameters
  853. // @rdesc True if successful, False otherwise
  854. // @comm Private function
  855. //---------------------------------------------------------------------------
  856. BOOLEAN SWGAMPAD_ValidateData (PPACKETINFO DataPacket)
  857. {
  858. BOOLEAN Result = FALSE;
  859. PVOID Data = DataPacket->Data;
  860. ULONG Packets = DataPacket->NumPackets;
  861. ULONG Clocks = DataPacket->ClocksSampled;
  862. MsGamePrint ((DBG_VERBOSE, "SWGAMPAD_ValidateData enter\n"));
  863. if ((Clocks % 5) || (Clocks > 20))
  864. {
  865. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_ValidateData - wrong number of clocks = %lu\n", Clocks));
  866. return (Result);
  867. }
  868. __asm
  869. {
  870. mov esi, Data
  871. mov ecx, Packets
  872. ValidateLoop:
  873. mov ax, [esi]
  874. xor al, ah
  875. jpo ValidateDone
  876. add esi, 2
  877. loop ValidateLoop
  878. mov Result, TRUE
  879. ValidateDone:
  880. }
  881. return (Result);
  882. }
  883. //---------------------------------------------------------------------------
  884. // @func Converts raw packet information to HID report
  885. // @parm ULONG | UnitId | UnitId for this device
  886. // @parm USHORT[] | Data | Pointer to raw data buffer
  887. // @parm PDEVICE_PACKET | Report | Pointer to device packet
  888. // @rdesc Returns nothing
  889. // @comm Private function
  890. //---------------------------------------------------------------------------
  891. VOID SWGAMPAD_ProcessData (ULONG UnitId, USHORT Data[], PDEVICE_PACKET Report)
  892. {
  893. ULONG B1;
  894. MsGamePrint ((DBG_VERBOSE, "SWGAMPAD_ProcessData enter\n"));
  895. //
  896. // Process X Axis
  897. //
  898. switch (Data[UnitId] & GAME_X_BITS)
  899. {
  900. case GAME_X_LEFT_BIT:
  901. Report->dwX = EXTENTS_X_MIN;
  902. break;
  903. case GAME_X_RIGHT_BIT:
  904. Report->dwX = EXTENTS_X_MAX;
  905. break;
  906. default:
  907. Report->dwX = EXTENTS_X_MID;
  908. break;
  909. }
  910. //
  911. // Process Y Axis
  912. //
  913. switch (Data[UnitId] & GAME_Y_BITS)
  914. {
  915. case GAME_Y_DOWN_BIT:
  916. Report->dwY = EXTENTS_Y_MIN;
  917. break;
  918. case GAME_Y_UP_BIT:
  919. Report->dwY = EXTENTS_Y_MAX;
  920. break;
  921. default:
  922. Report->dwY = EXTENTS_Y_MID;
  923. break;
  924. }
  925. //
  926. // Process Buttons
  927. //
  928. Report->dwButtons = ~((Data[UnitId] & GAME_BUTTON_BITS) >> 4);
  929. Report->dwButtons &= ((1L << GAME_PACKET_BUTTONS) - 1);
  930. Report->dwButtonNumber = 0;
  931. for (B1 = 1; B1 <= GAME_PACKET_BUTTONS; B1++)
  932. if (Report->dwButtons & (1L << (B1-1)))
  933. {
  934. Report->dwButtonNumber = B1;
  935. break;
  936. }
  937. }
  938. //---------------------------------------------------------------------------
  939. // @func Driver entry point for device
  940. // @rdesc Returns NT status code
  941. // @comm Private function
  942. //---------------------------------------------------------------------------
  943. NTSTATUS SWGAMPAD_DriverEntry (VOID)
  944. {
  945. MsGamePrint((DBG_INFORM,"SWGAMPAD: SWGAMPAD_DriverEntry Enter\n"));
  946. //
  947. // Read timing values from registry
  948. //
  949. MSGAME_ReadRegistry (DEVICENAME, &Delays);
  950. return (STATUS_SUCCESS);
  951. }
  952. //---------------------------------------------------------------------------
  953. // @func Establishes connection to device by detection
  954. // @parm PGAMEPORT | PortInfo | Gameport parameters
  955. // @rdesc Returns NT Status code
  956. // @comm Private function
  957. //---------------------------------------------------------------------------
  958. NTSTATUS SWGAMPAD_ConnectDevice (PGAMEPORT PortInfo)
  959. {
  960. NTSTATUS ntStatus;
  961. ULONG i = MAX_CONNECT_ATTEMPTS;
  962. MsGamePrint ((DBG_INFORM, "SWGAMPAD_ConnectDevice enter\n"));
  963. DataInfo.PortInfo = IdInfo.PortInfo = *PortInfo;
  964. //
  965. // Convert registry timing values
  966. //
  967. SWGAMPAD_Calibrate (PortInfo);
  968. //
  969. // Reset to "known" state
  970. //
  971. MsGamePrint ((DBG_CONTROL, "SWGAMPAD_ConnectDevice - resetting device\n"));
  972. if (!SWGAMPAD_GoAnalog (&DataInfo, &IdInfo))
  973. MsGamePrint ((DBG_CONTROL, "SWGAMPAD_ConnectDevice - unable to go Analog\n"));
  974. else do
  975. {
  976. //
  977. // SWGAMPAD Connection method (try these steps twice)
  978. //
  979. TIMER_DelayMicroSecs (TIMER_GetDelay(ONE_MILLI_SEC));
  980. //
  981. // Get the ID string.
  982. //
  983. MsGamePrint ((DBG_CONTROL, "SWGAMPAD_ConnectDevice - getting ID string\n"));
  984. if (!SWGAMPAD_GetId (&IdInfo))
  985. continue;
  986. //
  987. // Mark device found and return
  988. //
  989. if (!GamePadInfo.NumDevices)
  990. GamePadInfo.NumDevices = 1;
  991. return (STATUS_SUCCESS);
  992. } while (--i);
  993. //
  994. // Return error
  995. //
  996. GamePadInfo.NumDevices = 0;
  997. return (STATUS_DEVICE_NOT_CONNECTED);
  998. }
  999. //---------------------------------------------------------------------------
  1000. // @func Reads and converts HID packet for this device
  1001. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1002. // @parm PUCHAR | Report | Output buffer for report
  1003. // @parm ULONG | MaxSize | Size of buffer for report
  1004. // @parm PULONG | Copied | Bytes copied to buffer for report
  1005. // @rdesc Returns Returns NT status code
  1006. // @comm Private function
  1007. //---------------------------------------------------------------------------
  1008. NTSTATUS SWGAMPAD_ReadReport (PGAMEPORT PortInfo, PDEVICE_PACKET Report)
  1009. {
  1010. NTSTATUS ntStatus = STATUS_SUCCESS;
  1011. MsGamePrint ((DBG_VERBOSE, "SWGAMPAD_ReadReport enter\n"));
  1012. //
  1013. // Log number of attempts
  1014. //
  1015. DataInfo.Attempts++;
  1016. //
  1017. // Set up default data to process
  1018. //
  1019. memcpy (DataInfo.Data, ValidData, sizeof (ValidData));
  1020. //
  1021. // Check for collision
  1022. //
  1023. if (DEVICE_IsCollision (&DataInfo))
  1024. {
  1025. MsGamePrint ((DBG_INFORM, "SWGAMPAD_ReadReport - port collision\n"));
  1026. ntStatus = STATUS_DEVICE_BUSY;
  1027. goto ReadReportExit;
  1028. }
  1029. //
  1030. // Get a packet and check for errors
  1031. //
  1032. ntStatus = SWGAMPAD_ReadData (&DataInfo);
  1033. if (!NT_SUCCESS(ntStatus))
  1034. {
  1035. if (ntStatus != STATUS_DEVICE_BUSY)
  1036. {
  1037. DataInfo.Failures++;
  1038. ntStatus = STATUS_DEVICE_NOT_CONNECTED;
  1039. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_ReadReport - invalid packet\n"));
  1040. }
  1041. else
  1042. {
  1043. MsGamePrint ((DBG_CONTROL, "SWGAMPAD_ReadReport - Port busy or in use\n"));
  1044. }
  1045. }
  1046. else
  1047. {
  1048. if (DataInfo.Mode == IMODE_DIGITAL_ENH)
  1049. DataInfo.NumPackets = DataInfo.ClocksSampled / 5;
  1050. else DataInfo.NumPackets = DataInfo.ClocksSampled / 15;
  1051. if (DataInfo.NumPackets == 0)
  1052. DataInfo.NumPackets = 1;
  1053. else if (DataInfo.NumPackets > 4)
  1054. DataInfo.NumPackets = 4;
  1055. if (!SWGAMPAD_ValidateData (&DataInfo))
  1056. {
  1057. DataInfo.Failures++;
  1058. ntStatus = STATUS_DEVICE_NOT_CONNECTED;
  1059. MsGamePrint ((DBG_SEVERE, "SWGAMPAD_ReadReport - invalid packet\n"));
  1060. }
  1061. else memcpy (ValidData, DataInfo.Data, sizeof (ValidData));
  1062. }
  1063. // ---------------
  1064. ReadReportExit:
  1065. // ---------------
  1066. if (NT_SUCCESS(ntStatus))
  1067. GamePadInfo.NumDevices = DataInfo.NumPackets;
  1068. if (GET_DEVICE_UNIT (PortInfo) < GamePadInfo.NumDevices)
  1069. SWGAMPAD_ProcessData (GET_DEVICE_UNIT (PortInfo), ValidData, Report);
  1070. else ntStatus = STATUS_DEVICE_NOT_CONNECTED;
  1071. return (ntStatus);
  1072. }
  1073. //---------------------------------------------------------------------------
  1074. // @func Device handler for Pnp Start Device
  1075. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1076. // @rdesc Returns NT status code
  1077. // @comm Private function
  1078. //---------------------------------------------------------------------------
  1079. NTSTATUS SWGAMPAD_StartDevice (PGAMEPORT PortInfo)
  1080. {
  1081. MsGamePrint ((DBG_INFORM, "SWGAMPAD_StartDevice enter\n"));
  1082. UNREFERENCED_PARAMETER (PortInfo);
  1083. return (STATUS_SUCCESS);
  1084. }
  1085. //---------------------------------------------------------------------------
  1086. // @func Device handler for Pnp Stop Device
  1087. // @parm PGAMEPORT | PortInfo | Gameport parameters
  1088. // @rdesc Returns NT status code
  1089. // @comm Private function
  1090. //---------------------------------------------------------------------------
  1091. NTSTATUS SWGAMPAD_StopDevice (PGAMEPORT PortInfo, BOOLEAN TouchHardware)
  1092. {
  1093. MsGamePrint ((DBG_INFORM, "SWGAMPAD_StopDevice enter\n"));
  1094. UNREFERENCED_PARAMETER (PortInfo);
  1095. UNREFERENCED_PARAMETER (TouchHardware);
  1096. return (STATUS_SUCCESS);
  1097. }
  1098. //**************************************************************************
  1099. #endif // SAITEK
  1100. //**************************************************************************