Source code of Windows XP (NT5)
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.

1447 lines
39 KiB

  1. /*****************************************************************************
  2. *
  3. * Copyright (c) 1996-1999 Microsoft Corporation
  4. *
  5. * @doc
  6. * @module irsir.c | IrSIR NDIS Miniport Driver
  7. * @comm
  8. *
  9. *-----------------------------------------------------------------------------
  10. *
  11. * Author: Scott Holden (sholden)
  12. *
  13. * Date: 10/3/1996 (created)
  14. *
  15. * Contents:
  16. *
  17. *****************************************************************************/
  18. #include "irsir.h"
  19. VOID
  20. ResetCallback(
  21. PIR_WORK_ITEM pWorkItem
  22. );
  23. NDIS_STATUS
  24. ResetIrDevice(
  25. PIR_DEVICE pThisDev
  26. );
  27. VOID
  28. StopWorkerThread(
  29. PIR_DEVICE pThisDev
  30. );
  31. NDIS_STATUS
  32. DriverEntry(
  33. PDRIVER_OBJECT DriverObject,
  34. PUNICODE_STRING RegistryPath
  35. );
  36. #pragma NDIS_INIT_FUNCTION(DriverEntry)
  37. #pragma alloc_text(PAGE,ResetCallback)
  38. #pragma alloc_text(PAGE,IrsirHalt)
  39. #pragma alloc_text(PAGE,ResetIrDevice)
  40. #pragma alloc_text(PAGE,IrsirInitialize)
  41. #pragma alloc_text(PAGE,IrsirHalt)
  42. #pragma alloc_text(PAGE,PassiveLevelThread)
  43. #pragma alloc_text(PAGE,SetIrFunctions)
  44. #pragma alloc_text(PAGE,StopWorkerThread)
  45. //
  46. // Global list of device objects and a spin lock to interleave access
  47. // to the global queue.
  48. //
  49. #ifdef DEBUG
  50. int DbgSettings =
  51. //DBG_PNP |
  52. //DBG_TIME |
  53. //DBG_DBG |
  54. //DBG_STAT |
  55. //DBG_FUNCTION |
  56. DBG_ERROR |
  57. DBG_WARN |
  58. //DBG_OUT |
  59. 0;
  60. #endif
  61. // We use these timeouts when we just have to return soon.
  62. SERIAL_TIMEOUTS SerialTimeoutsInit =
  63. {
  64. 30, // ReadIntervalTimeout
  65. 0, // ReadTotalTimeoutMultiplier
  66. 250, // ReadTotalTimeoutConstant
  67. 0, // WriteTotalTimeoutMultiplier
  68. 20*1000 // WriteTotalTimeoutConstant
  69. };
  70. // We use the timeouts while we're running, and we want to return less frequently.
  71. SERIAL_TIMEOUTS SerialTimeoutsIdle =
  72. {
  73. MAXULONG, // ReadIntervalTimeout
  74. 0, // ReadTotalTimeoutMultiplier
  75. 10, // ReadTotalTimeoutConstant
  76. 0, // WriteTotalTimeoutMultiplier
  77. 20*1000 // WriteTotalTimeoutConstant
  78. };
  79. #if IRSIR_EVENT_DRIVEN
  80. // We use the timeouts while we're running, and we want to return less frequently.
  81. SERIAL_TIMEOUTS SerialTimeoutsActive =
  82. {
  83. MAXULONG, // ReadIntervalTimeout
  84. 0, // ReadTotalTimeoutMultiplier
  85. 0, // ReadTotalTimeoutConstant
  86. 0, // WriteTotalTimeoutMultiplier
  87. 0 // WriteTotalTimeoutConstant
  88. };
  89. #endif
  90. /*****************************************************************************
  91. *
  92. * Function: DriverEntry
  93. *
  94. * Synopsis: register driver entry functions with NDIS
  95. *
  96. * Arguments: DriverObject - the driver object being initialized
  97. * RegistryPath - registry path of the driver
  98. *
  99. * Returns: value returned by NdisMRegisterMiniport
  100. *
  101. * Algorithm:
  102. *
  103. * History: dd-mm-yyyy Author Comment
  104. * 10/3/1996 sholden author
  105. *
  106. * Notes:
  107. *
  108. * This routine runs at IRQL PASSIVE_LEVEL.
  109. *
  110. *****************************************************************************/
  111. //
  112. // Mark the DriverEntry function to run once during initialization.
  113. //
  114. #ifndef MAX_PATH
  115. #define MAX_PATH 2048
  116. #endif
  117. NDIS_STATUS
  118. DriverEntry(
  119. IN PDRIVER_OBJECT pDriverObject,
  120. IN PUNICODE_STRING pRegistryPath
  121. )
  122. {
  123. NDIS_STATUS status;
  124. #if NDIS_MAJOR_VERSION < 5
  125. NDIS40_MINIPORT_CHARACTERISTICS characteristics;
  126. #else
  127. NDIS50_MINIPORT_CHARACTERISTICS characteristics;
  128. #endif
  129. NDIS_HANDLE hWrapper;
  130. #if MEM_CHECKING
  131. InitMemory();
  132. #endif
  133. DEBUGMSG(DBG_FUNC, ("+DriverEntry(irsir)\n"));
  134. NdisMInitializeWrapper(
  135. &hWrapper,
  136. pDriverObject,
  137. pRegistryPath,
  138. NULL
  139. );
  140. NdisZeroMemory(&characteristics, sizeof(characteristics));
  141. characteristics.MajorNdisVersion = (UCHAR)NDIS_MAJOR_VERSION;
  142. characteristics.MinorNdisVersion = (UCHAR)NDIS_MINOR_VERSION;
  143. characteristics.Reserved = 0;
  144. characteristics.HaltHandler = IrsirHalt;
  145. characteristics.InitializeHandler = IrsirInitialize;
  146. characteristics.QueryInformationHandler = IrsirQueryInformation;
  147. characteristics.SetInformationHandler = IrsirSetInformation;
  148. characteristics.ResetHandler = IrsirReset;
  149. //
  150. // For now we will allow NDIS to send only one packet at a time.
  151. //
  152. characteristics.SendHandler = IrsirSend;
  153. characteristics.SendPacketsHandler = NULL;
  154. //
  155. // We don't use NdisMIndicateXxxReceive function, so we will
  156. // need a ReturnPacketHandler to retrieve our packet resources.
  157. //
  158. characteristics.ReturnPacketHandler = IrsirReturnPacket;
  159. characteristics.TransferDataHandler = NULL;
  160. //
  161. // NDIS never calls the ReconfigureHandler.
  162. //
  163. characteristics.ReconfigureHandler = NULL;
  164. //
  165. // Let NDIS handle the hangs for now.
  166. //
  167. // If a CheckForHangHandler is supplied, NDIS will call it every two
  168. // seconds (by default) or at a driver specified interval.
  169. //
  170. // When not supplied, NDIS will conclude that the miniport is hung:
  171. // 1) a send packet has been pending longer than twice the
  172. // timeout period
  173. // 2) a request to IrsirQueryInformation or IrsirSetInformation
  174. // is not completed in a period equal to twice the timeout
  175. // period.
  176. // NDIS will keep track of the NdisMSendComplete calls and probably do
  177. // a better job of ensuring the miniport is not hung.
  178. //
  179. // If NDIS detects that the miniport is hung, NDIS calls
  180. // IrsirReset.
  181. //
  182. characteristics.CheckForHangHandler = NULL;
  183. //
  184. // This miniport driver does not handle interrupts.
  185. //
  186. characteristics.HandleInterruptHandler = NULL;
  187. characteristics.ISRHandler = NULL;
  188. characteristics.DisableInterruptHandler = NULL;
  189. characteristics.EnableInterruptHandler = NULL;
  190. //
  191. // This miniport does not control a busmaster DMA with
  192. // NdisMAllocateShareMemoryAsysnc, AllocateCompleteHandler won't be
  193. // called from NDIS.
  194. //
  195. characteristics.AllocateCompleteHandler = NULL;
  196. //
  197. // Need to initialize the ir device object queue and the spin lock
  198. // to interleave access to the queue at this point, since after we
  199. // return, the driver will only deal with the device level.
  200. //
  201. status = NdisMRegisterMiniport(
  202. hWrapper,
  203. (PNDIS_MINIPORT_CHARACTERISTICS)&characteristics,
  204. sizeof(characteristics)
  205. );
  206. if (status != NDIS_STATUS_SUCCESS)
  207. {
  208. DEBUGMSG(DBG_ERROR, (" NdisMRegisterMiniport failed. Returned 0x%.8x.\n", status));
  209. }
  210. DEBUGMSG(DBG_FUNC, ("-DriverEntry(irsir)\n"));
  211. return status;
  212. }
  213. // Provide some default functions for dongle handling.
  214. NDIS_STATUS UnknownDongleInit(PDEVICE_OBJECT NotUsed)
  215. {
  216. return NDIS_STATUS_FAILURE;
  217. }
  218. NDIS_STATUS UnknownDongleQueryCaps(PDONGLE_CAPABILITIES NotUsed)
  219. {
  220. return NDIS_STATUS_FAILURE;
  221. }
  222. void UnknownDongleDeinit(PDEVICE_OBJECT NotUsed)
  223. {
  224. return;
  225. }
  226. NDIS_STATUS UnknownDongleSetSpeed(PDEVICE_OBJECT pSerialDevObj,
  227. UINT bitsPerSec,
  228. UINT currentSpeed
  229. )
  230. {
  231. return NDIS_STATUS_FAILURE;
  232. }
  233. NTSTATUS SetIrFunctions(PIR_DEVICE pThisDev)
  234. {
  235. NTSTATUS Status = STATUS_SUCCESS;
  236. //
  237. // Need to initialize the dongle code.
  238. //
  239. switch (pThisDev->transceiverType)
  240. {
  241. case STANDARD_UART:
  242. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- UART\n", pThisDev->transceiverType));
  243. pThisDev->dongle.QueryCaps = StdUart_QueryCaps;
  244. pThisDev->dongle.Initialize = StdUart_Init;
  245. pThisDev->dongle.SetSpeed = StdUart_SetSpeed;
  246. pThisDev->dongle.Deinitialize = StdUart_Deinit;
  247. break;
  248. case ESI_9680:
  249. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- ESI_9680\n", pThisDev->transceiverType));
  250. pThisDev->dongle.QueryCaps = ESI_QueryCaps;
  251. pThisDev->dongle.Initialize = ESI_Init;
  252. pThisDev->dongle.SetSpeed = ESI_SetSpeed;
  253. pThisDev->dongle.Deinitialize = ESI_Deinit;
  254. break;
  255. case PARALLAX:
  256. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- PARALLAX\n", pThisDev->transceiverType));
  257. pThisDev->dongle.QueryCaps = PARALLAX_QueryCaps;
  258. pThisDev->dongle.Initialize = PARALLAX_Init;
  259. pThisDev->dongle.SetSpeed = PARALLAX_SetSpeed;
  260. pThisDev->dongle.Deinitialize = PARALLAX_Deinit;
  261. break;
  262. case ACTISYS_200L:
  263. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- ACTISYS 200L\n", pThisDev->transceiverType));
  264. pThisDev->dongle.QueryCaps = ACT200L_QueryCaps;
  265. pThisDev->dongle.Initialize = ACT200L_Init;
  266. pThisDev->dongle.SetSpeed = ACT200L_SetSpeed;
  267. pThisDev->dongle.Deinitialize = ACT200L_Deinit;
  268. break;
  269. case ACTISYS_220L:
  270. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- ACTISYS 220L\n", pThisDev->transceiverType));
  271. pThisDev->dongle.QueryCaps = ACT220L_QueryCaps;
  272. pThisDev->dongle.Initialize = ACT220L_Init;
  273. pThisDev->dongle.SetSpeed = ACT220L_SetSpeed;
  274. pThisDev->dongle.Deinitialize = ACT220L_Deinit;
  275. break;
  276. case ACTISYS_220LPLUS:
  277. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- ACTISYS 220L\n", pThisDev->transceiverType));
  278. pThisDev->dongle.QueryCaps = ACT220LPlus_QueryCaps;
  279. pThisDev->dongle.Initialize = ACT220L_Init;
  280. pThisDev->dongle.SetSpeed = ACT220L_SetSpeed;
  281. pThisDev->dongle.Deinitialize = ACT220L_Deinit;
  282. break;
  283. case TEKRAM_IRMATE_210:
  284. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- TEKRAM IRMATE 210 or PUMA\n", pThisDev->transceiverType));
  285. pThisDev->dongle.QueryCaps = TEKRAM_QueryCaps;
  286. pThisDev->dongle.Initialize = TEKRAM_Init;
  287. pThisDev->dongle.SetSpeed = TEKRAM_SetSpeed;
  288. pThisDev->dongle.Deinitialize = TEKRAM_Deinit;
  289. break;
  290. case AMP_PHASIR:
  291. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- AMP PHASIR or CRYSTAL\n", pThisDev->transceiverType));
  292. pThisDev->dongle.QueryCaps = Crystal_QueryCaps;
  293. pThisDev->dongle.Initialize = Crystal_Init;
  294. pThisDev->dongle.SetSpeed = Crystal_SetSpeed;
  295. pThisDev->dongle.Deinitialize = Crystal_Deinit;
  296. break;
  297. case TEMIC_TOIM3232:
  298. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- TEMIC TOIM3232\n", pThisDev->transceiverType));
  299. pThisDev->dongle.QueryCaps = TEMIC_QueryCaps;
  300. pThisDev->dongle.Initialize = TEMIC_Init;
  301. pThisDev->dongle.SetSpeed = TEMIC_SetSpeed;
  302. pThisDev->dongle.Deinitialize = TEMIC_Deinit;
  303. break;
  304. case GIRBIL:
  305. DEBUGMSG(DBG_OUT, ("IRSIR: Dongle type:%d -- GIRBIL\n", pThisDev->transceiverType));
  306. pThisDev->dongle.QueryCaps = GIRBIL_QueryCaps;
  307. pThisDev->dongle.Initialize = GIRBIL_Init;
  308. pThisDev->dongle.SetSpeed = GIRBIL_SetSpeed;
  309. pThisDev->dongle.Deinitialize = GIRBIL_Deinit;
  310. break;
  311. // case ADAPTEC:
  312. // case CRYSTAL:
  313. // case NSC_DEMO_BD:
  314. default:
  315. DEBUGMSG(DBG_ERROR, (" Failure: Tranceiver type is NOT supported!\n"));
  316. pThisDev->dongle.QueryCaps = UnknownDongleQueryCaps;
  317. pThisDev->dongle.Initialize = UnknownDongleInit;
  318. pThisDev->dongle.SetSpeed = UnknownDongleSetSpeed;
  319. pThisDev->dongle.Deinitialize = UnknownDongleDeinit;
  320. // The dongle functions have already been set to stubs in
  321. // InitializeDevice().
  322. Status = NDIS_STATUS_FAILURE;
  323. break;
  324. }
  325. return Status;
  326. }
  327. /*****************************************************************************
  328. *
  329. * Function: IrsirInitialize
  330. *
  331. * Synopsis: Initializes the NIC (serial.sys) and allocates all resources
  332. * required to carry out network io operations.
  333. *
  334. * Arguments: OpenErrorStatus - allows IrsirInitialize to return additional
  335. * status code NDIS_STATUS_xxx if returning
  336. * NDIS_STATUS_OPEN_FAILED
  337. * SelectedMediumIndex - specifies to NDIS the medium type the
  338. * driver uses
  339. * MediumArray - array of NdisMediumXXX the driver can choose
  340. * MediumArraySize
  341. * MiniportAdapterHandle - handle identifying miniport's NIC
  342. * WrapperConfigurationContext - used with Ndis config and init
  343. * routines
  344. *
  345. * Returns: NDIS_STATUS_SUCCESS if properly configure and resources allocated
  346. * NDIS_STATUS_FAILURE, otherwise
  347. * more specific failures:
  348. * NDIS_STATUS_UNSUPPORTED_MEDIA - driver can't support any medium
  349. * NDIS_STATUS_ADAPTER_NOT_FOUND - NdisOpenConfiguration or
  350. * NdisReadConfiguration failed
  351. * NDIS_STATUS_OPEN_FAILED - failed to open serial.sys
  352. * NDIS_STATUS_NOT_ACCEPTED - serial.sys does not accept the
  353. * configuration
  354. * NDIS_STATUS_RESOURCES - could not claim sufficient
  355. * resources
  356. *
  357. * Algorithm:
  358. *
  359. * History: dd-mm-yyyy Author Comment
  360. * 10/3/1996 sholden author
  361. *
  362. * Notes: NDIS will not submit requests until this is complete.
  363. *
  364. * This routine runs at IRQL PASSIVE_LEVEL.
  365. *
  366. *****************************************************************************/
  367. NDIS_STATUS
  368. IrsirInitialize(
  369. OUT PNDIS_STATUS OpenErrorStatus,
  370. OUT PUINT SelectedMediumIndex,
  371. IN PNDIS_MEDIUM MediumArray,
  372. IN UINT MediumArraySize,
  373. IN NDIS_HANDLE NdisAdapterHandle,
  374. IN NDIS_HANDLE WrapperConfigurationContext
  375. )
  376. {
  377. UINT i;
  378. PIR_DEVICE pThisDev = NULL;
  379. SERIAL_LINE_CONTROL serialLineControl;
  380. SERIAL_TIMEOUTS serialTimeouts;
  381. NDIS_STATUS status = NDIS_STATUS_SUCCESS;
  382. ULONG bitsPerSec = 9600;
  383. DEBUGMSG(DBG_FUNC, ("+IrsirInitialize\n"));
  384. //
  385. // Search for the irda medium in the medium array.
  386. //
  387. for (i = 0; i < MediumArraySize; i++)
  388. {
  389. if (MediumArray[i] == NdisMediumIrda)
  390. {
  391. break;
  392. }
  393. }
  394. if (i < MediumArraySize)
  395. {
  396. *SelectedMediumIndex = i;
  397. }
  398. else
  399. {
  400. //
  401. // Irda medium not found.
  402. //
  403. DEBUGMSG(DBG_ERROR, (" Failure: NdisMediumIrda not found!\n"));
  404. status = NDIS_STATUS_UNSUPPORTED_MEDIA;
  405. goto done;
  406. }
  407. //
  408. // Allocate a device object and zero memory.
  409. //
  410. pThisDev = NewDevice();
  411. if (pThisDev == NULL)
  412. {
  413. DEBUGMSG(DBG_ERROR, (" NewDevice failed.\n"));
  414. status = NDIS_STATUS_RESOURCES;
  415. goto done;
  416. }
  417. pThisDev->dongle.Initialize = UnknownDongleInit;
  418. pThisDev->dongle.SetSpeed = UnknownDongleSetSpeed;
  419. pThisDev->dongle.Deinitialize = UnknownDongleDeinit;
  420. pThisDev->dongle.QueryCaps = UnknownDongleQueryCaps;
  421. //
  422. // Initialize device object and resources.
  423. // All the queues and buffer/packets etc. are allocated here.
  424. //
  425. status = InitializeDevice(pThisDev);
  426. if (status != NDIS_STATUS_SUCCESS)
  427. {
  428. DEBUGMSG(DBG_ERROR, (" InitializeDevice failed. Returned 0x%.8x\n",
  429. status));
  430. goto done;
  431. }
  432. //
  433. // Record the NdisAdapterHandle.
  434. //
  435. pThisDev->hNdisAdapter = NdisAdapterHandle;
  436. //
  437. // NdisMSetAttributes will associate our adapter handle with the wrapper's
  438. // adapter handle. The wrapper will then always use our handle
  439. // when calling us. We use a pointer to the device object as the context.
  440. //
  441. NdisMSetAttributesEx(NdisAdapterHandle,
  442. (NDIS_HANDLE)pThisDev,
  443. 0,
  444. NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND |
  445. NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT |
  446. NDIS_ATTRIBUTE_DESERIALIZE, // Magic bullet
  447. NdisInterfaceInternal);
  448. //
  449. // Initialize a notification event for signalling PassiveLevelThread.
  450. //
  451. KeInitializeEvent(
  452. &pThisDev->eventPassiveThread,
  453. SynchronizationEvent, // auto-clearing event
  454. FALSE // event initially non-signalled
  455. );
  456. KeInitializeEvent(
  457. &pThisDev->eventKillThread,
  458. SynchronizationEvent, // auto-clearing event
  459. FALSE // event initially non-signalled
  460. );
  461. //
  462. // Create a thread to run at IRQL PASSIVE_LEVEL.
  463. //
  464. status = (NDIS_STATUS) PsCreateSystemThread(
  465. &pThisDev->hPassiveThread,
  466. (ACCESS_MASK) 0L,
  467. NULL,
  468. NULL,
  469. NULL,
  470. PassiveLevelThread,
  471. DEV_TO_CONTEXT(pThisDev)
  472. );
  473. if (status != NDIS_STATUS_SUCCESS)
  474. {
  475. DEBUGMSG(DBG_ERROR, (" PsCreateSystemThread failed. Returned 0x%.8x\n", status));
  476. goto done;
  477. }
  478. // At this point we've done everything but actually touch the serial
  479. // port. We do so now.
  480. //
  481. // Get device configuration from the registry settings.
  482. // We are getting the transceiver type and which serial
  483. // device object to access.
  484. // The information which we get from the registry will outlast
  485. // any NIC resets.
  486. //
  487. status = GetDeviceConfiguration(
  488. pThisDev,
  489. WrapperConfigurationContext
  490. );
  491. if (status != NDIS_STATUS_SUCCESS)
  492. {
  493. DEBUGMSG(DBG_ERROR, (" GetDeviceConfiguration failed. Returned 0x%.8x\n",
  494. status));
  495. status = NDIS_STATUS_ADAPTER_NOT_FOUND;
  496. goto done;
  497. }
  498. //
  499. // Open the serial device object specified in the registry.
  500. //
  501. status = SerialOpen(pThisDev);
  502. if (status != NDIS_STATUS_SUCCESS)
  503. {
  504. DEBUGMSG(DBG_ERROR, (" SerialOpen failed. Returned 0x%.8x\n", status));
  505. status = NDIS_STATUS_SUCCESS; // We'll get the port later.
  506. }
  507. if (pThisDev->pSerialDevObj)
  508. {
  509. {
  510. //
  511. // Set the minimum port buffering.
  512. //
  513. SERIAL_QUEUE_SIZE QueueSize;
  514. QueueSize.InSize = 3*1024; // 1.5 packet size
  515. QueueSize.OutSize = 0;
  516. // Ignore failure. We'll still work, just not as well.
  517. (void)SerialSetQueueSize(pThisDev->pSerialDevObj, &QueueSize);
  518. }
  519. #if 0
  520. {
  521. SERIAL_HANDFLOW Handflow;
  522. SerialGetHandflow(pThisDev->pSerialDevObj, &Handflow);
  523. DEBUGMSG(DBG_PNP, ("IRSIR: Serial Handflow was: %x %x %x %x\n",
  524. Handflow.ControlHandShake,
  525. Handflow.FlowReplace,
  526. Handflow.XonLimit,
  527. Handflow.XoffLimit));
  528. Handflow.ControlHandShake = 0;
  529. Handflow.FlowReplace = 0;
  530. SerialSetHandflow(pThisDev->pSerialDevObj, &Handflow);
  531. }
  532. #endif
  533. //
  534. // Must set the timeout value of the serial port
  535. // for a read.
  536. //
  537. status = (NDIS_STATUS) SerialSetTimeouts(pThisDev->pSerialDevObj,
  538. &SerialTimeoutsInit);
  539. if (status != NDIS_STATUS_SUCCESS)
  540. {
  541. DEBUGMSG(DBG_ERROR, (" SerialSetTimeouts failed. Returned 0x%.8x\n", status));
  542. status = NDIS_STATUS_FAILURE;
  543. goto done;
  544. }
  545. (void)SerialSetBaudRate(pThisDev->pSerialDevObj, &bitsPerSec);
  546. serialLineControl.StopBits = STOP_BIT_1;
  547. serialLineControl.Parity = NO_PARITY ;
  548. serialLineControl.WordLength = 8;
  549. status = (NDIS_STATUS) SerialSetLineControl(
  550. pThisDev->pSerialDevObj,
  551. &serialLineControl
  552. );
  553. if (status != NDIS_STATUS_SUCCESS)
  554. {
  555. DEBUGMSG(DBG_ERROR, (" SerialSetLineControl failed. Returned 0x%.8x\n", status));
  556. goto done;
  557. }
  558. }
  559. status = SetIrFunctions(pThisDev);
  560. if (status!=STATUS_SUCCESS)
  561. {
  562. goto done;
  563. }
  564. if (pThisDev->pSerialDevObj)
  565. {
  566. //
  567. // Now that a serial device object is open, we can initialize the
  568. // dongle and set the speed of the dongle to the default.
  569. //
  570. if (pThisDev->dongle.Initialize(pThisDev->pSerialDevObj)!=NDIS_STATUS_SUCCESS)
  571. {
  572. DEBUGMSG(DBG_ERROR, (" IRSIR: dongle failed to init!\n"));
  573. status = NDIS_STATUS_FAILURE;
  574. goto done;
  575. }
  576. }
  577. pThisDev->dongle.QueryCaps(&pThisDev->dongleCaps);
  578. if (pThisDev->pSerialDevObj)
  579. {
  580. //
  581. // Set the speed of the uart and the dongle.
  582. //
  583. status = (NDIS_STATUS) SetSpeed(pThisDev);
  584. if (status != NDIS_STATUS_SUCCESS)
  585. {
  586. DEBUGMSG(DBG_ERROR, (" IRSIR: Setspeed failed. Returned 0x%.8x\n", status));
  587. goto done;
  588. }
  589. //
  590. // Create an irp and do an MJ_READ to begin our receives.
  591. // NOTE: All other receive processing will be done in the read completion
  592. // routine which is done set from this MJ_READ.
  593. //
  594. status = InitializeReceive(pThisDev);
  595. if (status != NDIS_STATUS_SUCCESS)
  596. {
  597. DEBUGMSG(DBG_ERROR, (" InitializeReceive failed. Returned 0x%.8x\n", status));
  598. goto done;
  599. }
  600. }
  601. done:
  602. if (status != NDIS_STATUS_SUCCESS) {
  603. DEBUGMSG(DBG_ERR, ("IRSIR: IrsirInitialize failed %x\n", status));
  604. if (pThisDev != NULL) {
  605. if (pThisDev->hPassiveThread) {
  606. pThisDev->fPendingHalt = TRUE;
  607. StopWorkerThread(pThisDev);
  608. }
  609. if (pThisDev->pSerialDevObj != NULL) {
  610. if (pThisDev->dongle.Deinitialize) {
  611. pThisDev->dongle.Deinitialize(pThisDev->pSerialDevObj);
  612. }
  613. SerialClose(pThisDev);
  614. }
  615. DeinitializeDevice(pThisDev);
  616. FreeDevice(pThisDev);
  617. }
  618. }
  619. DEBUGMSG(DBG_FUNC, ("-IrsirInitialize\n"));
  620. return status;
  621. }
  622. /*****************************************************************************
  623. *
  624. * Function: IrsirHalt
  625. *
  626. * Synopsis: Deallocates resources when the NIC is removed and halts the
  627. * NIC.
  628. *
  629. * Arguments: Context - pointer to the ir device object
  630. *
  631. * Returns:
  632. *
  633. * Algorithm: Mirror image of IrsirInitialize...undoes everything initialize
  634. * did.
  635. *
  636. * History: dd-mm-yyyy Author Comment
  637. * 10/8/1996 sholden author
  638. *
  639. * Notes:
  640. *
  641. * This routine runs at IRQL PASSIVE_LEVEL.
  642. *
  643. *****************************************************************************/
  644. VOID
  645. IrsirHalt(
  646. IN NDIS_HANDLE Context
  647. )
  648. {
  649. PIR_DEVICE pThisDev;
  650. DEBUGMSG(DBG_FUNC, ("+IrsirHalt\n"));
  651. pThisDev = CONTEXT_TO_DEV(Context);
  652. //
  653. // Let the send completion and receive completion routine know that there
  654. // is a pending halt.
  655. //
  656. pThisDev->fPendingHalt = TRUE;
  657. //
  658. // We want to wait until all pending receives and sends to the
  659. // serial device object. We call serial purge to cancel any
  660. // irps. Wait until sends and receives have stopped.
  661. //
  662. SerialPurge(pThisDev->pSerialDevObj);
  663. PausePacketProcessing(&pThisDev->SendPacketQueue,TRUE);
  664. FlushQueuedPackets(&pThisDev->SendPacketQueue,pThisDev->hNdisAdapter);
  665. while(
  666. (pThisDev->fReceiving == TRUE)
  667. )
  668. {
  669. //
  670. // Sleep for 20 milliseconds.
  671. //
  672. NdisMSleep(20000);
  673. }
  674. //
  675. // Deinitialize the dongle.
  676. //
  677. ASSERT(pThisDev->packetsHeldByProtocol==0);
  678. pThisDev->dongle.Deinitialize(
  679. pThisDev->pSerialDevObj
  680. );
  681. //
  682. // Close the serial device object.
  683. //
  684. SerialClose(pThisDev);
  685. //
  686. // Need to terminate our worker threadxs. However, the thread
  687. // needs to call PsTerminateSystemThread itself. Therefore,
  688. // we will signal it.
  689. //
  690. StopWorkerThread(pThisDev);
  691. //
  692. // Deinitialize our own ir device object.
  693. //
  694. DeinitializeDevice(pThisDev);
  695. //
  696. // Free the device names.
  697. //
  698. if (pThisDev->serialDosName.Buffer)
  699. {
  700. MyMemFree(pThisDev->serialDosName.Buffer,
  701. MAX_SERIAL_NAME_SIZE
  702. );
  703. pThisDev->serialDosName.Buffer = NULL;
  704. }
  705. if (pThisDev->serialDevName.Buffer)
  706. {
  707. MyMemFree(
  708. pThisDev->serialDevName.Buffer,
  709. MAX_SERIAL_NAME_SIZE
  710. );
  711. pThisDev->serialDevName.Buffer = NULL;
  712. }
  713. //
  714. // Free our own ir device object.
  715. //
  716. FreeDevice(pThisDev);
  717. DEBUGMSG(DBG_FUNC, ("-IrsirHalt\n"));
  718. return;
  719. }
  720. VOID
  721. ResetCallback(
  722. PIR_WORK_ITEM pWorkItem
  723. )
  724. {
  725. PIR_DEVICE pThisDev = pWorkItem->pIrDevice;
  726. NDIS_STATUS status;
  727. BOOLEAN fSwitchSuccessful;
  728. NDIS_HANDLE hSwitchToMiniport;
  729. //
  730. // Reset this device by request of IrsirReset.
  731. //
  732. DEBUGMSG(DBG_STAT, (" primPassive = PASSIVE_RESET_DEVICE\n"));
  733. ASSERT(pThisDev->fPendingReset == TRUE);
  734. if (pThisDev->pSerialDevObj) {
  735. SerialPurge(pThisDev->pSerialDevObj);
  736. }
  737. PausePacketProcessing(&pThisDev->SendPacketQueue,TRUE);
  738. FlushQueuedPackets(&pThisDev->SendPacketQueue,pThisDev->hNdisAdapter);
  739. status = ResetIrDevice(pThisDev);
  740. #if DBG
  741. if (status != NDIS_STATUS_SUCCESS)
  742. {
  743. DEBUGMSG(DBG_ERROR, (" ResetIrDevice failed = 0x%.8x\n", status));
  744. }
  745. #endif //DBG
  746. //
  747. //
  748. if (status != STATUS_SUCCESS)
  749. {
  750. NdisWriteErrorLogEntry(pThisDev->hNdisAdapter,
  751. NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
  752. 1,
  753. status);
  754. status = NDIS_STATUS_HARD_ERRORS;
  755. }
  756. NdisMResetComplete(
  757. pThisDev->hNdisAdapter,
  758. (NDIS_STATUS)status,
  759. TRUE
  760. );
  761. FreeWorkItem(pWorkItem);
  762. ActivatePacketProcessing(&pThisDev->SendPacketQueue);
  763. pThisDev->fPendingReset = FALSE;
  764. return;
  765. }
  766. /*****************************************************************************
  767. *
  768. * Function: IrsirReset
  769. *
  770. * Synopsis: Resets the drivers software state.
  771. *
  772. * Arguments: AddressingReset - return arg. If set to TRUE, NDIS will call
  773. * MiniportSetInformation to restore addressing
  774. * information to the current values.
  775. * Context - pointer to ir device object
  776. *
  777. * Returns: NDIS_STATUS_PENDING
  778. *
  779. * Algorithm:
  780. *
  781. * History: dd-mm-yyyy Author Comment
  782. * 10/9/1996 sholden author
  783. *
  784. * Notes:
  785. *
  786. * Runs at IRQL_DISPATCH_LEVEL, therefore we need to call a thread at
  787. * passive level to perform the reset.
  788. *
  789. *****************************************************************************/
  790. NDIS_STATUS
  791. IrsirReset(
  792. OUT PBOOLEAN AddressingReset,
  793. IN NDIS_HANDLE MiniportAdapterContext
  794. )
  795. {
  796. PIR_DEVICE pThisDev;
  797. NDIS_STATUS status;
  798. DEBUGMSG(DBG_STAT, ("+IrsirReset\n"));
  799. pThisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
  800. //
  801. // Let the receive completion routine know that there
  802. // is a pending reset.
  803. //
  804. pThisDev->fPendingReset = TRUE;
  805. *AddressingReset = TRUE;
  806. if (ScheduleWorkItem(PASSIVE_RESET_DEVICE, pThisDev,
  807. ResetCallback, NULL, 0) != NDIS_STATUS_SUCCESS)
  808. {
  809. status = NDIS_STATUS_SUCCESS;
  810. }
  811. else
  812. {
  813. status = NDIS_STATUS_PENDING;
  814. }
  815. DEBUGMSG(DBG_STAT, ("-IrsirReset\n"));
  816. return status;
  817. }
  818. /*****************************************************************************
  819. *
  820. * Function: ResetIrDevice
  821. *
  822. * Synopsis:
  823. *
  824. * Arguments:
  825. *
  826. * Returns:
  827. *
  828. * Algorithm:
  829. *
  830. * History: dd-mm-yyyy Author Comment
  831. * 10/17/1996 sholden author
  832. *
  833. * Notes:
  834. *
  835. * The following elements of the ir device object outlast the reset:
  836. *
  837. * eventPassiveThread
  838. * hPassiveThread
  839. * primPassive
  840. *
  841. * serialDevName
  842. * pSerialDevObj
  843. * TransceiverType
  844. * dongle
  845. *
  846. * hNdisAdapter
  847. *
  848. *****************************************************************************/
  849. NDIS_STATUS
  850. ResetIrDevice(
  851. PIR_DEVICE pThisDev
  852. )
  853. {
  854. SERIAL_LINE_CONTROL serialLineControl;
  855. SERIAL_TIMEOUTS serialTimeouts;
  856. NDIS_STATUS status;
  857. ULONG bitsPerSec = 9600;
  858. DEBUGMSG(DBG_STAT, ("+ResetIrDeviceThread\n"));
  859. //
  860. // We need to wait for the completion of all pending sends and receives
  861. // to the serial driver.
  862. //
  863. //
  864. // We can speed up by purging the serial driver.
  865. //
  866. if (pThisDev->pSerialDevObj) {
  867. SerialPurge(pThisDev->pSerialDevObj);
  868. while(
  869. (pThisDev->fReceiving == TRUE)
  870. )
  871. {
  872. //
  873. // Sleep for 20 milliseconds.
  874. //
  875. NdisMSleep(20000);
  876. }
  877. //
  878. // Deinit the dongle.
  879. //
  880. pThisDev->dongle.Deinitialize(pThisDev->pSerialDevObj);
  881. } else {
  882. //
  883. // we were not able to open the serial driver when the miniport first initialized.
  884. // The thread will call this routine to attempt to open the device every 3 seconds.
  885. //
  886. status = SerialOpen(pThisDev);
  887. if (status != NDIS_STATUS_SUCCESS)
  888. {
  889. DEBUGMSG(DBG_ERROR, (" SerialOpen failed. Returned 0x%.8x\n", status));
  890. goto done;
  891. }
  892. }
  893. if (pThisDev->pSerialDevObj)
  894. {
  895. {
  896. //
  897. // Set the minimum port buffering.
  898. //
  899. SERIAL_QUEUE_SIZE QueueSize;
  900. QueueSize.InSize = 3*1024; // 1.5 packet size
  901. QueueSize.OutSize = 0;
  902. // Ignore failure. We'll still work, just not as well.
  903. (void)SerialSetQueueSize(pThisDev->pSerialDevObj, &QueueSize);
  904. }
  905. //
  906. // Must set the timeout value of the serial port
  907. // for a read.
  908. //
  909. status = (NDIS_STATUS) SerialSetTimeouts(pThisDev->pSerialDevObj,
  910. &SerialTimeoutsInit);
  911. if (status != NDIS_STATUS_SUCCESS)
  912. {
  913. DEBUGMSG(DBG_ERROR, (" SerialSetTimeouts failed. Returned 0x%.8x\n", status));
  914. status = NDIS_STATUS_FAILURE;
  915. goto done;
  916. }
  917. (void)SerialSetBaudRate(pThisDev->pSerialDevObj, &bitsPerSec);
  918. serialLineControl.StopBits = STOP_BIT_1;
  919. serialLineControl.Parity = NO_PARITY ;
  920. serialLineControl.WordLength = 8;
  921. status = (NDIS_STATUS) SerialSetLineControl(
  922. pThisDev->pSerialDevObj,
  923. &serialLineControl
  924. );
  925. if (status != NDIS_STATUS_SUCCESS)
  926. {
  927. DEBUGMSG(DBG_ERROR, (" SerialSetLineControl failed. Returned 0x%.8x\n", status));
  928. goto done;
  929. }
  930. }
  931. status = SetIrFunctions(pThisDev);
  932. if (status!=STATUS_SUCCESS)
  933. {
  934. goto done;
  935. }
  936. //
  937. // Initialize the dongle.
  938. //
  939. status = (NDIS_STATUS) SerialSetTimeouts(pThisDev->pSerialDevObj,
  940. &SerialTimeoutsInit);
  941. pThisDev->dongle.Initialize(pThisDev->pSerialDevObj);
  942. pThisDev->dongle.QueryCaps(&pThisDev->dongleCaps);
  943. //
  944. // Set the speed of the uart and the dongle.
  945. //
  946. status = (NDIS_STATUS) SetSpeed(pThisDev);
  947. if (status != NDIS_STATUS_SUCCESS)
  948. {
  949. DEBUGMSG(DBG_ERROR, (" SetSpeed failed. Returned 0x%.8x\n", status));
  950. // goto done;
  951. }
  952. serialLineControl.StopBits = STOP_BIT_1;
  953. serialLineControl.Parity = NO_PARITY ;
  954. serialLineControl.WordLength = 8;
  955. status = (NDIS_STATUS) SerialSetLineControl(
  956. pThisDev->pSerialDevObj,
  957. &serialLineControl
  958. );
  959. if (status != NDIS_STATUS_SUCCESS)
  960. {
  961. DEBUGMSG(DBG_ERROR, (" SerialSetLineControl failed. Returned 0x%.8x\n", status));
  962. // goto done;
  963. }
  964. //
  965. // Must set the timeout value of the serial port
  966. // for a read.
  967. //
  968. status = (NDIS_STATUS) SerialSetTimeouts(
  969. pThisDev->pSerialDevObj,
  970. &SerialTimeoutsInit
  971. );
  972. if (status != NDIS_STATUS_SUCCESS)
  973. {
  974. DEBUGMSG(DBG_ERROR, (" SerialSetTimeouts failed. Returned 0x%.8x\n", status));
  975. status = NDIS_STATUS_FAILURE;
  976. // goto done;
  977. }
  978. //
  979. // Initialize receive loop.
  980. //
  981. status = InitializeReceive(pThisDev);
  982. if (status != NDIS_STATUS_SUCCESS)
  983. {
  984. DEBUGMSG(DBG_ERROR, (" InitializeReceive failed. Returned 0x%.8x\n", status));
  985. status = NDIS_STATUS_FAILURE;
  986. // goto done;
  987. }
  988. done:
  989. DEBUGMSG(DBG_STAT, ("-ResetIrDeviceThread\n"));
  990. return status;
  991. }
  992. /*****************************************************************************
  993. *
  994. * Function: PassiveLevelThread
  995. *
  996. * Synopsis: Thread running at IRQL PASSIVE_LEVEL.
  997. *
  998. * Arguments:
  999. *
  1000. * Returns:
  1001. *
  1002. * Algorithm:
  1003. *
  1004. * History: dd-mm-yyyy Author Comment
  1005. * 10/22/1996 sholden author
  1006. *
  1007. * Notes:
  1008. *
  1009. * Any PASSIVE_PRIMITIVE that can be called must be serialized.
  1010. * i.e. when IrsirReset is called, NDIS will not make any other
  1011. * requests of the miniport until NdisMResetComplete is called.
  1012. *
  1013. *****************************************************************************/
  1014. VOID
  1015. PassiveLevelThread(
  1016. IN OUT PVOID Context
  1017. )
  1018. {
  1019. PIR_DEVICE pThisDev;
  1020. NTSTATUS ntStatus;
  1021. PLIST_ENTRY pListEntry;
  1022. PKEVENT EventList[2];
  1023. LARGE_INTEGER Timeout;
  1024. ULONG ulSerialOpenAttempts = 100;
  1025. DEBUGMSG(DBG_FUNC, ("+PassiveLevelThread\n"));
  1026. KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
  1027. pThisDev = CONTEXT_TO_DEV(Context);
  1028. Timeout.QuadPart = -10000 * 1000 * 3; // 3 second relative delay
  1029. EventList[0] = &pThisDev->eventPassiveThread;
  1030. EventList[1] = &pThisDev->eventKillThread;
  1031. while (1) {
  1032. //
  1033. // The eventPassiveThread is an auto-clearing event, so
  1034. // we don't need to reset the event.
  1035. //
  1036. ntStatus = KeWaitForMultipleObjects(2,
  1037. EventList,
  1038. WaitAny,
  1039. Executive,
  1040. KernelMode,
  1041. FALSE,
  1042. (pThisDev->pSerialDevObj ? NULL : &Timeout),
  1043. NULL);
  1044. if (ntStatus==0 || ntStatus==STATUS_TIMEOUT) {
  1045. //
  1046. // either the first event was signaled or a timeout occurred
  1047. //
  1048. if (!pThisDev->pSerialDevObj) {
  1049. //
  1050. // we have not opened the serial driver yet, try again
  1051. //
  1052. ResetIrDevice(pThisDev);
  1053. if ((pThisDev->pSerialDevObj == NULL) && (--ulSerialOpenAttempts == 0)) {
  1054. //
  1055. // still could not open the device, tell ndis to remove it
  1056. //
  1057. NdisMRemoveMiniport(pThisDev->hNdisAdapter);
  1058. }
  1059. }
  1060. while (pListEntry = MyInterlockedRemoveHeadList(&pThisDev->leWorkItems,
  1061. &pThisDev->slWorkItem))
  1062. {
  1063. PIR_WORK_ITEM pWorkItem = CONTAINING_RECORD(pListEntry,
  1064. IR_WORK_ITEM,
  1065. ListEntry);
  1066. pWorkItem->Callback(pWorkItem);
  1067. }
  1068. } else {
  1069. if (ntStatus==1) {
  1070. //
  1071. // the second event was signaled, this means that the thread should exit
  1072. //
  1073. DEBUGMSG(DBG_STAT, (" Thread: HALT\n"));
  1074. // Free any pending requests
  1075. while (pListEntry = MyInterlockedRemoveHeadList(&pThisDev->leWorkItems,
  1076. &pThisDev->slWorkItem))
  1077. {
  1078. PIR_WORK_ITEM pWorkItem = CONTAINING_RECORD(pListEntry,
  1079. IR_WORK_ITEM,
  1080. ListEntry);
  1081. DEBUGMSG(DBG_WARN, ("IRSIR: Releasing work item %08x\n", pWorkItem->Callback));
  1082. FreeWorkItem(pWorkItem);
  1083. }
  1084. ASSERT(pThisDev->fPendingHalt == TRUE);
  1085. //
  1086. // out of loop
  1087. //
  1088. break;
  1089. }
  1090. }
  1091. }
  1092. DEBUGMSG(DBG_FUNC, ("-PassiveLevelThread\n"));
  1093. PsTerminateSystemThread(STATUS_SUCCESS);
  1094. }
  1095. VOID
  1096. StopWorkerThread(
  1097. PIR_DEVICE pThisDev
  1098. )
  1099. {
  1100. PVOID ThreadObject;
  1101. NTSTATUS Status;
  1102. //
  1103. // get an object handle fomr the thread handle
  1104. //
  1105. Status=ObReferenceObjectByHandle(
  1106. pThisDev->hPassiveThread,
  1107. 0,
  1108. NULL,
  1109. KernelMode,
  1110. &ThreadObject,
  1111. NULL
  1112. );
  1113. ASSERT(Status == STATUS_SUCCESS);
  1114. //
  1115. // tell the thread to exit
  1116. //
  1117. KeSetEvent(
  1118. &pThisDev->eventKillThread,
  1119. 0,
  1120. FALSE
  1121. );
  1122. if (NT_SUCCESS(Status)) {
  1123. KeWaitForSingleObject(
  1124. ThreadObject,
  1125. Executive,
  1126. KernelMode,
  1127. FALSE,
  1128. NULL
  1129. );
  1130. ObDereferenceObject(ThreadObject);
  1131. ThreadObject=NULL;
  1132. }
  1133. //
  1134. // close the thread handle
  1135. //
  1136. ZwClose(pThisDev->hPassiveThread);
  1137. pThisDev->hPassiveThread = NULL;
  1138. return;
  1139. }