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.

1545 lines
41 KiB

  1. /*****************************************************************************
  2. *
  3. * Copyright (c) 1996-1999 Microsoft Corporation
  4. *
  5. * @doc
  6. * @module receive.c | IrSIR NDIS Miniport Driver
  7. * @comm
  8. *
  9. *-----------------------------------------------------------------------------
  10. *
  11. * Author: Scott Holden (sholden)
  12. *
  13. * Date: 10/4/1996 (created)
  14. *
  15. * Contents:
  16. *
  17. *****************************************************************************/
  18. #include "irsir.h"
  19. VOID
  20. SetSpeedCallback(
  21. PIR_WORK_ITEM pWorkItem
  22. );
  23. #if LOGGING
  24. ULONG LogIndex = 0;
  25. LOG Log[NUM_LOG];
  26. #endif
  27. #ifdef DEBUG_IRSIR
  28. static ULONG_PTR irpCount;
  29. static ULONG_PTR bytesReceived;
  30. #endif //DEBUG_IRSIR
  31. //
  32. // Declarations.
  33. //
  34. NTSTATUS SerialIoCompleteRead(
  35. IN PDEVICE_OBJECT pSerialDevObj,
  36. IN PIRP pIrp,
  37. IN PVOID Context
  38. );
  39. NTSTATUS
  40. SerialIoCompleteWait(
  41. IN PDEVICE_OBJECT pSerialDevObj,
  42. IN PIRP pIrp,
  43. IN PVOID Context
  44. );
  45. NTSTATUS ProcessData(
  46. IN PIR_DEVICE pThisDev,
  47. IN PUCHAR rawBuffer,
  48. IN UINT rawBytesRead
  49. );
  50. VOID
  51. DeliverBuffer(
  52. IN PIR_DEVICE pThisDev
  53. );
  54. VOID StartSerialReadCallback(PIR_WORK_ITEM pWorkItem);
  55. #pragma alloc_text(PAGE,SetSpeedCallback)
  56. #pragma alloc_text(PAGE,StartSerialReadCallback)
  57. VOID DBG_PrintBuf(PUCHAR bufptr, UINT buflen)
  58. {
  59. UINT i, linei;
  60. #define ISPRINT(ch) (((ch) >= ' ') && ((ch) <= '~'))
  61. #define PRINTCHAR(ch) (UCHAR)(ISPRINT(ch) ? (ch) : '.')
  62. DbgPrint("\r\n %d bytes @%x:", buflen, bufptr);
  63. /*
  64. * Print whole lines of 8 characters with HEX and ASCII
  65. */
  66. for (i = 0; i+8 <= buflen; i += 8) {
  67. UCHAR ch0 = bufptr[i+0],
  68. ch1 = bufptr[i+1], ch2 = bufptr[i+2],
  69. ch3 = bufptr[i+3], ch4 = bufptr[i+4],
  70. ch5 = bufptr[i+5], ch6 = bufptr[i+6],
  71. ch7 = bufptr[i+7];
  72. DbgPrint("\r\n %02x %02x %02x %02x %02x %02x %02x %02x"
  73. " %c %c %c %c %c %c %c %c",
  74. ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7,
  75. PRINTCHAR(ch0), PRINTCHAR(ch1),
  76. PRINTCHAR(ch2), PRINTCHAR(ch3),
  77. PRINTCHAR(ch4), PRINTCHAR(ch5),
  78. PRINTCHAR(ch6), PRINTCHAR(ch7));
  79. }
  80. /*
  81. * Print final incomplete line
  82. */
  83. DbgPrint("\r\n ");
  84. for (linei = 0; (linei < 8) && (i < buflen); i++, linei++){
  85. DbgPrint(" %02x", (UINT)(bufptr[i]));
  86. }
  87. DbgPrint(" ");
  88. i -= linei;
  89. while (linei++ < 8) DbgPrint(" ");
  90. for (linei = 0; (linei < 8) && (i < buflen); i++, linei++){
  91. UCHAR ch = bufptr[i];
  92. DbgPrint(" %c", PRINTCHAR(ch));
  93. }
  94. DbgPrint("\t\t<>\r\n");
  95. }
  96. NTSTATUS StartSerialRead(IN PIR_DEVICE pThisDev)
  97. /*++
  98. Routine Description:
  99. Allocates an irp and calls the serial driver.
  100. Arguments:
  101. pThisDev - Current IR device.
  102. Return Value:
  103. STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
  104. --*/
  105. {
  106. NTSTATUS Status;
  107. PIRP pIrp;
  108. LOG_ENTRY('SR', pThisDev, 0, 0);
  109. #if DBG
  110. NdisZeroMemory(
  111. pThisDev->pRcvIrpBuffer,
  112. SERIAL_RECEIVE_BUFFER_LENGTH
  113. );
  114. #endif
  115. //
  116. // Now that we have processed the irp, we will send another read
  117. // request to the serial device object.
  118. //
  119. pIrp = SerialBuildReadWriteIrp(
  120. pThisDev->pSerialDevObj,
  121. IRP_MJ_READ,
  122. pThisDev->pRcvIrpBuffer,
  123. SERIAL_RECEIVE_BUFFER_LENGTH,
  124. NULL
  125. );
  126. if (pIrp == NULL)
  127. {
  128. DEBUGMSG(DBG_ERR, (" SerialBuildReadWriteIrp failed.\n"));
  129. Status = STATUS_INSUFFICIENT_RESOURCES;
  130. pThisDev->fReceiving = FALSE;
  131. goto done;
  132. }
  133. //
  134. // Set up the io completion routine for the irp.
  135. //
  136. IoSetCompletionRoutine(
  137. pIrp, // irp to use
  138. SerialIoCompleteRead, // routine to call when irp is done
  139. DEV_TO_CONTEXT(pThisDev), // context to pass routine
  140. TRUE, // call on success
  141. TRUE, // call on error
  142. TRUE); // call on cancel
  143. //
  144. // Call IoCallDriver to send the irp to the serial port.
  145. //
  146. LOG_ENTRY('2I', pThisDev, pIrp, 0);
  147. IoCallDriver(
  148. pThisDev->pSerialDevObj,
  149. pIrp
  150. );
  151. Status=STATUS_PENDING;
  152. done:
  153. return Status;
  154. }
  155. VOID
  156. StartSerialReadCallback(PIR_WORK_ITEM pWorkItem)
  157. /*++
  158. Routine Description:
  159. Arguments:
  160. Return Value:
  161. none
  162. --*/
  163. {
  164. PIR_DEVICE pThisDev = pWorkItem->pIrDevice;
  165. FreeWorkItem(pWorkItem);
  166. (void)StartSerialRead(pThisDev);
  167. return;
  168. }
  169. /*****************************************************************************
  170. *
  171. * Function: InitializeReceive
  172. *
  173. * Synopsis: Initialize the receive functionality.
  174. *
  175. * Arguments: pThisDevice - pointer to current ir device object
  176. *
  177. * Returns: NDIS_STATUS_SUCCESS - if irp is successfully sent to serial
  178. * device object
  179. * NDIS_STATUS_RESOURCES - if mem can't be alloc'd
  180. * NDIS_STATUS_FAILURE - otherwise
  181. *
  182. * Algorithm:
  183. * 1) Set the receive timeout to READ_INTERVAL_TIMEOUT_MSEC.
  184. * 2) Initialize our rcvInfo and associate info for our
  185. * receive state machine.
  186. * 3) Build an IRP_MJ_READ irp to send to the serial device
  187. * object, and set the completion(or timeout) routine
  188. * to SerialIoCompleteRead.
  189. *
  190. * History: dd-mm-yyyy Author Comment
  191. * 10/4/1996 sholden author
  192. *
  193. * Notes:
  194. *
  195. * This routine must be called in IRQL PASSIVE_LEVEL.
  196. *
  197. *****************************************************************************/
  198. NDIS_STATUS
  199. InitializeReceive(
  200. IN PIR_DEVICE pThisDev
  201. )
  202. {
  203. PIRP pIrp;
  204. PIO_STACK_LOCATION irpSp;
  205. NDIS_STATUS status;
  206. #if IRSIR_EVENT_DRIVEN
  207. NTSTATUS NtStatus;
  208. SERIAL_CHARS SerialChars;
  209. #endif
  210. DEBUGMSG(DBG_FUNC, ("+InitializeReceive\n"));
  211. #ifdef DEBUG_IRSIR
  212. irpCount = 0;
  213. bytesReceived = 0;
  214. #endif //DEBUG_IRSIR
  215. //
  216. // Set up the receive information for our read completion routine.
  217. //
  218. pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
  219. pThisDev->rcvInfo.rcvBufPos = 0;
  220. if (pThisDev->rcvInfo.pRcvBuffer == NULL)
  221. {
  222. pThisDev->rcvInfo.pRcvBuffer =
  223. (PRCV_BUFFER)MyInterlockedRemoveHeadList(
  224. &(pThisDev->rcvFreeQueue),
  225. &(pThisDev->rcvQueueSpinLock)
  226. );
  227. ASSERT(pThisDev->rcvInfo.pRcvBuffer != NULL);
  228. }
  229. #if IRSIR_EVENT_DRIVEN
  230. NtStatus = (NDIS_STATUS) SerialSetTimeouts(pThisDev->pSerialDevObj,
  231. &SerialTimeoutsActive);
  232. NtStatus = SerialGetChars(pThisDev->pSerialDevObj, &SerialChars);
  233. if (NtStatus!=STATUS_SUCCESS)
  234. {
  235. DEBUGMSG(DBG_ERROR, ("IRSIR: SerialGetChars failed (0x%x:%d)\n", NtStatus));
  236. }
  237. else
  238. {
  239. SerialChars.EventChar = SLOW_IR_EOF;
  240. NtStatus = SerialSetChars(pThisDev->pSerialDevObj, &SerialChars);
  241. }
  242. if (NtStatus!=STATUS_SUCCESS)
  243. {
  244. DEBUGMSG(DBG_ERROR, ("IRSIR: SerialSetChars failed (0x%x:%d)\n", NtStatus));
  245. }
  246. else
  247. {
  248. ULONG WaitMask = SERIAL_EV_RXFLAG | SERIAL_EV_RX80FULL;
  249. NtStatus = SerialSetWaitMask(pThisDev->pSerialDevObj, &WaitMask);
  250. }
  251. if (NtStatus!=STATUS_SUCCESS)
  252. {
  253. DEBUGMSG(DBG_ERROR, ("IRSIR: SerialSetWaitMask failed (0x%x:%d)\n", NtStatus));
  254. }
  255. else
  256. {
  257. if (InterlockedExchange(&pThisDev->fWaitPending, 1)==0)
  258. {
  259. NtStatus = SerialCallbackOnMask(pThisDev->pSerialDevObj,
  260. SerialIoCompleteWait,
  261. &pThisDev->WaitIosb,
  262. DEV_TO_CONTEXT(pThisDev),
  263. &pThisDev->MaskResult);
  264. if (NtStatus==STATUS_PENDING)
  265. {
  266. NtStatus = STATUS_SUCCESS;
  267. }
  268. }
  269. }
  270. if (NtStatus!=STATUS_SUCCESS)
  271. {
  272. DEBUGMSG(DBG_ERROR, ("IRSIR: SerialCallbackOnMask failed (0x%x:%d)\n", NtStatus));
  273. ASSERT(0);
  274. }
  275. status = NtStatus;
  276. #else
  277. pThisDev->fReceiving = TRUE;
  278. (void)SerialSetTimeouts(pThisDev->pSerialDevObj,
  279. &SerialTimeoutsIdle);
  280. status = (NDIS_STATUS)StartSerialRead(pThisDev);
  281. if ( (status != STATUS_SUCCESS) &&
  282. (status != STATUS_PENDING) &&
  283. (status != STATUS_TIMEOUT) )
  284. {
  285. DEBUGMSG(DBG_ERR, (" IoCallDriver failed. Returned 0x%.8x\n", status));
  286. status = NDIS_STATUS_FAILURE;
  287. pThisDev->fReceiving = FALSE;
  288. goto error10;
  289. }
  290. //
  291. // If IoCallDriver returned STATUS_PENDING, we were successful
  292. // in sending the irp to the serial device object. This
  293. // routine will return STATUS_SUCCESS.
  294. //
  295. if (status == NDIS_STATUS_PENDING)
  296. {
  297. status = NDIS_STATUS_SUCCESS;
  298. }
  299. //
  300. // Set us into the receive state.
  301. //
  302. goto done;
  303. error10:
  304. #endif
  305. done:
  306. DEBUGMSG(DBG_FUNC, ("-InitializeReceive\n"));
  307. return status;
  308. }
  309. VOID
  310. SetSpeedCallback(
  311. PIR_WORK_ITEM pWorkItem
  312. )
  313. {
  314. PIR_DEVICE pThisDev = pWorkItem->pIrDevice;
  315. NDIS_STATUS status;
  316. BOOLEAN fSwitchSuccessful;
  317. NDIS_HANDLE hSwitchToMiniport;
  318. //
  319. // Set speed of serial device object by request of
  320. // IrsirSetInformation(OID_IRDA_LINK_SPEED).
  321. //
  322. DEBUGMSG(DBG_STAT, (" primPassive = PASSIVE_SET_SPEED\n"));
  323. //
  324. // The set speed event should not be set until a set
  325. // speed is required.
  326. //
  327. ASSERT(pThisDev->fPendingSetSpeed == TRUE);
  328. //
  329. // Ensure that receives and sends have been stopped.
  330. //
  331. ASSERT(pThisDev->fReceiving == FALSE);
  332. PausePacketProcessing(&pThisDev->SendPacketQueue,TRUE);
  333. //
  334. // We can perform the set speed now.
  335. //
  336. status = SetSpeed(pThisDev);
  337. if (status != STATUS_SUCCESS)
  338. {
  339. DEBUGMSG(DBG_STAT, (" SetSpeed failed. Returned 0x%.8x\n", status));
  340. }
  341. ActivatePacketProcessing(&pThisDev->SendPacketQueue);
  342. pThisDev->fPendingSetSpeed = FALSE;
  343. {
  344. NdisMSetInformationComplete(
  345. pThisDev->hNdisAdapter,
  346. (NDIS_STATUS)status
  347. );
  348. }
  349. //
  350. // NOTE: PassiveLevelThread is only signalled with primPassive
  351. // equal to PASSIVE_SET_SPEED from the receive completion
  352. // routine. After this thread is signalled, the receive
  353. // completion routine is shut down...we need to start
  354. // it up again.
  355. //
  356. status = InitializeReceive(pThisDev);
  357. if (status != STATUS_SUCCESS)
  358. {
  359. DEBUGMSG(DBG_ERROR, (" InitializeReceive failed = 0x%.8x\n", status));
  360. }
  361. FreeWorkItem(pWorkItem);
  362. return;
  363. }
  364. /*****************************************************************************
  365. *
  366. * Function: SerialIoCompleteRead
  367. *
  368. * Synopsis:
  369. *
  370. * Arguments: pSerialDevObj - pointer to the serial device object which
  371. * completed the irp
  372. * pIrp - the irp which was completed by the serial device
  373. * object
  374. * Context - the context given to IoSetCompletionRoutine
  375. * before calling IoCallDriver on the irp
  376. * The Context is a pointer to the ir device object.
  377. *
  378. * Returns: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine
  379. * (IofCompleteRequest) to stop working on the irp.
  380. *
  381. * Algorithm:
  382. * This is the completion routine for all pending IRP_MJ_READ irps
  383. * sent to the serial device object.
  384. *
  385. * If there is a pending halt or reset, we exit the completion
  386. * routine without sending another irp to the serial device object.
  387. *
  388. * If there is a pending set speed, this function will wait for
  389. * any pending sends to complete and then perform the set speed.
  390. *
  391. * If the IRP_MJ_READ irp returned either STATUS_SUCCESS or
  392. * STATUS_TIMEOUT, we must process any data (stripping BOFs, ESC
  393. * sequences, and EOF) into an NDIS_BUFFER and NDIS_PACKET.
  394. *
  395. * Another irp is then built (we just re-use the incoming irp) and
  396. * sent to the serial device object with another IRP_MJ_READ
  397. * request.
  398. *
  399. * History: dd-mm-yyyy Author Comment
  400. * 10/5/1996 sholden author
  401. *
  402. * Notes:
  403. *
  404. * This routine is called (by the io manager) in IRQL DISPATCH_LEVEL.
  405. *
  406. *****************************************************************************/
  407. NTSTATUS
  408. SerialIoCompleteRead(
  409. IN PDEVICE_OBJECT pSerialDevObj,
  410. IN PIRP pIrp,
  411. IN PVOID Context
  412. )
  413. {
  414. PIR_DEVICE pThisDev;
  415. BOOLEAN fSwitchSuccessful;
  416. NDIS_HANDLE hSwitchToMiniport;
  417. NTSTATUS status;
  418. ULONG_PTR BytesRead;
  419. BOOLEAN NewRead = TRUE;
  420. // DEBUGMSG(DBG_FUNC, ("+SerialIoCompleteRead\n"));
  421. //
  422. // The context given to IoSetCompletionRoutine is simply the the ir
  423. // device object pointer.
  424. //
  425. pThisDev = CONTEXT_TO_DEV(Context);
  426. //
  427. // Need to check if there is a pending halt or reset. If there is, we
  428. // just leave the receive completion. Since we maintain one irp associated
  429. // with the receive functionality, the irp will be deallocated in
  430. // the ir device object deinitialization routine.
  431. //
  432. if ((pThisDev->fPendingHalt == TRUE) ||
  433. (pThisDev->fPendingReset == TRUE))
  434. {
  435. //
  436. // Set the fReceiving boolean so that the halt and reset routines
  437. // know when it is okay to continue.
  438. //
  439. pThisDev->fReceiving = FALSE;
  440. //
  441. // Free the irp and associate memory...the rest will be
  442. // freed in the halt or reset.
  443. //
  444. LOG_ENTRY('3i', pThisDev, pIrp, 0);
  445. IoFreeIrp(pIrp);
  446. goto done;
  447. }
  448. //
  449. // Next we take care of any pending set speeds.
  450. //
  451. //
  452. // This completion routine is running at IRQL DISPATCH_LEVEL. Therefore,
  453. // we cannot make a synchronous call to the serial driver. Set an event
  454. // to notify the PassiveLevelThread to perform the speed change. We will
  455. // exit this without creating another irp to the serial device object.
  456. // PassiveLevelThread will call InitializeReceive after the speed has
  457. // been set.
  458. //
  459. if (pThisDev->fPendingSetSpeed == TRUE)
  460. {
  461. pThisDev->fReceiving = FALSE;
  462. if (ScheduleWorkItem(PASSIVE_SET_SPEED, pThisDev,
  463. SetSpeedCallback, NULL, 0) != NDIS_STATUS_SUCCESS)
  464. {
  465. status = NDIS_STATUS_SUCCESS;
  466. }
  467. else
  468. {
  469. status = NDIS_STATUS_PENDING;
  470. }
  471. LOG_ENTRY('4i', pThisDev, pIrp, 0);
  472. IoFreeIrp(pIrp);
  473. goto done;
  474. }
  475. //
  476. // We have a number of cases:
  477. // 1) The serial read timed out and we received no data.
  478. // 2) The serial read timed out and we received some data.
  479. // 3) The serial read was successful and fully filled our irp buffer.
  480. // 4) The irp was cancelled.
  481. // 5) Some other failure from the serial device object.
  482. //
  483. status = pIrp->IoStatus.Status;
  484. BytesRead = pIrp->IoStatus.Information;
  485. LOG_ENTRY('CR', pThisDev, BytesRead, 0);
  486. switch (status)
  487. {
  488. case STATUS_SUCCESS:
  489. case STATUS_TIMEOUT:
  490. if (BytesRead > 0)
  491. {
  492. #ifdef DEBUG_IRSIR
  493. //
  494. // Count number of irps received with data. Count will be
  495. // reset when delivering a buffer to the protocol.
  496. //
  497. irpCount++;
  498. bytesReceived += pIrp->IoStatus.Information;
  499. #endif //DEBUG_IRSIR
  500. //
  501. // Indicate that the next send should implement
  502. // the min turnaround delay.
  503. //
  504. pThisDev->fRequireMinTurnAround = TRUE;
  505. ProcessData(
  506. pThisDev,
  507. pThisDev->pRcvIrpBuffer,
  508. (UINT) pIrp->IoStatus.Information
  509. );
  510. }
  511. break; // STATUS_SUCCESS || STATUS_TIMEOUT
  512. case STATUS_DELETE_PENDING:
  513. NewRead = FALSE;
  514. pThisDev->fReceiving = FALSE;
  515. break;
  516. case STATUS_CANCELLED:
  517. //
  518. // If our irp was cancelled, we just ignore and continue as if
  519. // we processed data.
  520. //
  521. break;
  522. case STATUS_PENDING:
  523. case STATUS_UNSUCCESSFUL:
  524. case STATUS_INSUFFICIENT_RESOURCES:
  525. default:
  526. ASSERT(FALSE);
  527. break;
  528. }
  529. //
  530. // Free the irp and reinit the buffer and status block.
  531. //
  532. LOG_ENTRY('5i', pThisDev, pIrp, 0);
  533. IoFreeIrp(pIrp);
  534. if (NewRead)
  535. {
  536. pThisDev->NumReads++;
  537. if (InterlockedIncrement(&pThisDev->ReadRecurseLevel)>1)
  538. {
  539. if (ScheduleWorkItem(0, pThisDev, StartSerialReadCallback, 0, 0)!=NDIS_STATUS_SUCCESS)
  540. {
  541. DEBUGMSG(DBG_ERR, ("IRSIR:SerialIoCompleteRead: Timed out and couldn't reschedule read.\n"
  542. " We're going down.\n"));
  543. pThisDev->fReceiving = FALSE;
  544. }
  545. }
  546. else
  547. {
  548. StartSerialRead(pThisDev);
  549. }
  550. InterlockedDecrement(&pThisDev->ReadRecurseLevel);
  551. }
  552. done:
  553. // DEBUGMSG(DBG_FUNC, ("-SerialIoCompleteRead\n"));
  554. //
  555. // We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
  556. // routine (IofCompleteRequest) will stop working on the irp.
  557. //
  558. status = STATUS_MORE_PROCESSING_REQUIRED;
  559. return status;
  560. }
  561. /*****************************************************************************
  562. *
  563. * Function: ProcessData
  564. *
  565. * Synopsis: State machine to process the input data by stripping BOFs, EOFs
  566. * and ESC sequences in the data.
  567. *
  568. * Arguments: pThisDev - a pointer to the current ir device object
  569. * rawBuffer - a pointer to the input data to process
  570. * rawBytesRead - the number of bytes in rawBuffer
  571. *
  572. * Returns: STATUS_SUCCESS
  573. *
  574. * Algorithm:
  575. *
  576. * The state machine for receiving characters is as follows:
  577. *
  578. * -------------------------------------------------------------------
  579. * | Event/State || READY | BOF | IN_ESC | RX |
  580. * -------------------------------------------------------------------
  581. * -------------------------------------------------------------------
  582. * | || | | | |
  583. * | char = BOF || state = | | reset | reset |
  584. * | || BOF | | state = | state = |
  585. * | || | | BOF | BOF |
  586. * -------------------------------------------------------------------
  587. * | || | | error | |
  588. * | char = ESC || | state = | reset | state = |
  589. * | || | IN_ESC | state = | IN_ESC |
  590. * | || | | READY | |
  591. * -------------------------------------------------------------------
  592. * | || | | | if valid |
  593. * | char = EOF || | state = | error | FCS { |
  594. * | || | READY | reset | indicate |
  595. * | || | | state = | data |
  596. * | || | | READY | state = |
  597. * | || | | | READY } |
  598. * -------------------------------------------------------------------
  599. * | || | | complement| |
  600. * | char = || | state = | bit 6 of | data[] = |
  601. * | || | RX | char | char |
  602. * | || | | data[] = | |
  603. * | || | data[] = | char | |
  604. * | || | char | state = | |
  605. * | || | | RX | |
  606. * -------------------------------------------------------------------
  607. *
  608. * History: dd-mm-yyyy Author Comment
  609. * 10/7/1996 sholden author
  610. *
  611. * Notes:
  612. *
  613. *
  614. *****************************************************************************/
  615. NTSTATUS
  616. ProcessData(
  617. IN PIR_DEVICE pThisDev,
  618. IN PUCHAR rawBuffer,
  619. IN UINT rawBytesRead
  620. )
  621. {
  622. UINT rawBufPos;
  623. UCHAR currentChar;
  624. PUCHAR pReadBuffer;
  625. NTSTATUS status;
  626. #if DBG
  627. int i = 0;
  628. #endif //DBG
  629. DEBUGMSG(DBG_FUNC, ("+ProcessData\n"));
  630. DBGTIME("+ProcessData");
  631. DEBUGMSG(DBG_OUT, (" Address: 0x%.8x, Length: %d\n", rawBuffer, rawBytesRead));
  632. LOG_ENTRY('DP', pThisDev, rawBuffer, rawBytesRead);
  633. status = STATUS_SUCCESS;
  634. pReadBuffer = pThisDev->rcvInfo.pRcvBuffer->dataBuf;
  635. //
  636. // While there is data in the buffer which we have not processed.
  637. //
  638. //
  639. // NOTE: We have to loop once more after getting MAX_RCV_DATA_SIZE bytes
  640. // so that we can see the 'EOF'; hence the <= and not <.
  641. // Also, to ensure that we don't overrun the buffer,
  642. // RCV_BUFFER_SIZE = MAX_RCV_DATA_SIZE + 4;
  643. //
  644. for (
  645. rawBufPos = 0;
  646. (rawBufPos < rawBytesRead) && (pThisDev->rcvInfo.rcvBufPos <= MAX_RCV_DATA_SIZE);
  647. rawBufPos++
  648. )
  649. {
  650. #if DBG
  651. i++;
  652. if (i > 10000)
  653. {
  654. ASSERT(0);
  655. }
  656. #endif //DBG
  657. currentChar = rawBuffer[rawBufPos];
  658. switch (pThisDev->rcvInfo.rcvState)
  659. {
  660. case RCV_STATE_READY:
  661. switch (currentChar)
  662. {
  663. case SLOW_IR_BOF:
  664. pThisDev->rcvInfo.rcvState = RCV_STATE_BOF;
  665. break;
  666. case SLOW_IR_EOF:
  667. case SLOW_IR_ESC:
  668. default:
  669. //
  670. // Ignore this data.
  671. //
  672. break;
  673. }
  674. break; // RCV_STATE_READY
  675. case RCV_STATE_BOF:
  676. switch (currentChar)
  677. {
  678. case SLOW_IR_EOF:
  679. pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
  680. pThisDev->rcvInfo.rcvBufPos = 0;
  681. break;
  682. case SLOW_IR_ESC:
  683. pThisDev->rcvInfo.rcvState = RCV_STATE_IN_ESC;
  684. pThisDev->rcvInfo.rcvBufPos = 0;
  685. break;
  686. case SLOW_IR_BOF:
  687. //
  688. // state = RCV_STATE_BOF
  689. //
  690. break;
  691. default:
  692. //
  693. // We have data, copy the character into the buffer and
  694. // change our state to RCV_STATE_RX.
  695. //
  696. pReadBuffer[0] = currentChar;
  697. pThisDev->rcvInfo.rcvState = RCV_STATE_RX;
  698. pThisDev->rcvInfo.rcvBufPos = 1;
  699. break;
  700. }
  701. break; // RCV_STATE_BOF
  702. case RCV_STATE_IN_ESC:
  703. switch (currentChar)
  704. {
  705. //
  706. // ESC + (ESC||EOF||BOF) is an abort sequence.
  707. //
  708. // If ESC + (ESC||EOF) then state = READY.
  709. // If ESC + BOF then state = BOF.
  710. //
  711. case SLOW_IR_ESC:
  712. case SLOW_IR_EOF:
  713. pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
  714. pThisDev->rcvInfo.rcvBufPos = 0;
  715. break;
  716. case SLOW_IR_BOF:
  717. pThisDev->rcvInfo.rcvState = RCV_STATE_BOF;
  718. pThisDev->rcvInfo.rcvBufPos = 0;
  719. break;
  720. case SLOW_IR_BOF^SLOW_IR_ESC_COMP:
  721. case SLOW_IR_ESC^SLOW_IR_ESC_COMP:
  722. case SLOW_IR_EOF^SLOW_IR_ESC_COMP:
  723. //
  724. // Escape sequence for BOF, ESC or EOF chars.
  725. //
  726. //
  727. // Fall through, do same as unnecessary escape
  728. // sequence.
  729. //
  730. default:
  731. //
  732. // Unnecessary escape sequence, copy the data in to the buffer
  733. // we must complement bit 6 of the data.
  734. //
  735. pReadBuffer[pThisDev->rcvInfo.rcvBufPos++] =
  736. currentChar ^ SLOW_IR_ESC_COMP;
  737. pThisDev->rcvInfo.rcvState = RCV_STATE_RX;
  738. break;
  739. }
  740. break; // RCV_STATE_IN_ESC
  741. case RCV_STATE_RX:
  742. switch (currentChar)
  743. {
  744. case SLOW_IR_BOF:
  745. //
  746. // Reset.
  747. //
  748. pThisDev->rcvInfo.rcvState = RCV_STATE_BOF;
  749. pThisDev->rcvInfo.rcvBufPos = 0;
  750. break;
  751. case SLOW_IR_ESC:
  752. pThisDev->rcvInfo.rcvState = RCV_STATE_IN_ESC;
  753. break;
  754. case SLOW_IR_EOF:
  755. if (pThisDev->rcvInfo.rcvBufPos <
  756. (SLOW_IR_ADDR_SIZE + SLOW_IR_CONTROL_SIZE +
  757. SLOW_IR_FCS_SIZE)
  758. )
  759. {
  760. //
  761. // Reset. Not enough data.
  762. //
  763. pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
  764. pThisDev->rcvInfo.rcvBufPos = 0;
  765. break;
  766. }
  767. //
  768. // Need to set the length to the proper amount.
  769. // (It isn't rcvBufPos + 1 since it was incremented
  770. // the next free location...which we are not using.)
  771. //
  772. pThisDev->rcvInfo.pRcvBuffer->dataLen =
  773. pThisDev->rcvInfo.rcvBufPos;
  774. DEBUGMSG(DBG_OUT, (" RcvBuffer = 0x%.8x, Length = %d\n",
  775. pReadBuffer,
  776. pThisDev->rcvInfo.rcvBufPos
  777. ));
  778. //
  779. // DeliverBuffer attempts to deliver the current
  780. // frame in pThisDev->rcvInfo. If the ownership
  781. // of the packet is retained by the protocol, the
  782. // DeliverBuffer routine gives us a new receive
  783. // buffer.
  784. //
  785. DeliverBuffer(
  786. pThisDev
  787. );
  788. //
  789. // Since DeliverBuffer could have given us a new
  790. // buffer, we must update our pReadBuffer pointer.
  791. //
  792. pReadBuffer = pThisDev->rcvInfo.pRcvBuffer->dataBuf;
  793. pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
  794. pThisDev->rcvInfo.rcvBufPos = 0;
  795. break;
  796. default:
  797. //
  798. // The current character is data in the frame.
  799. //
  800. pReadBuffer[pThisDev->rcvInfo.rcvBufPos++] =
  801. currentChar;
  802. break;
  803. }
  804. break; // RCV_STATE_RX
  805. default:
  806. DEBUGMSG(DBG_ERR, (" Illegal state\n"));
  807. //
  808. // Reset.
  809. //
  810. pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
  811. pThisDev->rcvInfo.rcvBufPos = 0;
  812. break;
  813. }
  814. }
  815. //
  816. // There are two ways to break the for loop:
  817. // 1) out of data - this is fine
  818. // 2) overrun, the frame is larger than our buffer size
  819. //
  820. if (pThisDev->rcvInfo.rcvBufPos > MAX_RCV_DATA_SIZE)
  821. {
  822. DEBUGMSG(DBG_WARN, (" Overrun in ProcessData!!!\n"));
  823. //
  824. // Reset the buffer for our next read.
  825. //
  826. pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
  827. pThisDev->rcvInfo.rcvBufPos = 0;
  828. pThisDev->packetsReceivedOverflow++;
  829. }
  830. DEBUGMSG(DBG_FUNC, ("-ProcessData\n"));
  831. return status;
  832. }
  833. VOID
  834. ProcessReturnPacket(
  835. PIR_DEVICE pThisDev,
  836. PRCV_BUFFER pRcvBuffer
  837. )
  838. {
  839. PNDIS_BUFFER pBuffer;
  840. NdisQueryPacket(
  841. pRcvBuffer->packet,
  842. NULL, // physical buffer count, don't care
  843. NULL, // buffer count, don't care, we know it is 1
  844. &pBuffer, // get a pointer to our buffer
  845. NULL // total packet lenght, don't care
  846. );
  847. //
  848. // We adjusted the buffer length of the NDIS_BUFFER to the size
  849. // of the data before we gave ownership to the protocol. Now we
  850. // should reset the buffer length to the full size of the data
  851. // buffer.
  852. //
  853. NdisAdjustBufferLength(
  854. pBuffer,
  855. RCV_BUFFER_SIZE
  856. );
  857. #if DBG
  858. NdisZeroMemory(
  859. pRcvBuffer->dataBuf,
  860. RCV_BUFFER_SIZE
  861. );
  862. #endif
  863. pRcvBuffer->dataLen = 0;
  864. InterlockedDecrement(&pThisDev->packetsHeldByProtocol);
  865. //
  866. // Add the buffer to the free queue.
  867. //
  868. MyInterlockedInsertTailList(
  869. &(pThisDev->rcvFreeQueue),
  870. &pRcvBuffer->linkage,
  871. &(pThisDev->rcvQueueSpinLock)
  872. );
  873. }
  874. /*****************************************************************************
  875. *
  876. * Function: DeliverBuffer
  877. *
  878. * Synopsis: Delivers the buffer to the protocol via
  879. * NdisMIndicateReceivePacket.
  880. *
  881. * Arguments: pThisDev - pointer to the current ir device object
  882. *
  883. * Returns: STATUS_SUCCESS - on success
  884. * STATUS_UNSUCCESSFUL - if packet can't be delivered to protocol
  885. *
  886. * Algorithm:
  887. *
  888. * History: dd-mm-yyyy Author Comment
  889. * 10/7/1996 sholden author
  890. *
  891. * Notes:
  892. *
  893. *
  894. *****************************************************************************/
  895. VOID
  896. DeliverBuffer(
  897. IN PIR_DEVICE pThisDev
  898. )
  899. {
  900. SLOW_IR_FCS_TYPE fcs;
  901. PNDIS_BUFFER pBuffer;
  902. BOOLEAN fProcessPacketNow;
  903. NDIS_HANDLE hSwitchToMiniport;
  904. NTSTATUS status;
  905. PRCV_BUFFER pThisBuffer, pNextBuffer;
  906. DEBUGMSG(DBG_FUNC, ("+DeliverBuffer\n"));
  907. LOG_ENTRY('BD', pThisDev,
  908. pThisDev->rcvInfo.pRcvBuffer->dataBuf,
  909. pThisDev->rcvInfo.pRcvBuffer->dataLen);
  910. #if 0
  911. LOG_ENTRY('DD',
  912. ((PULONG)pThisDev->rcvInfo.pRcvBuffer->dataBuf)[0],
  913. ((PULONG)pThisDev->rcvInfo.pRcvBuffer->dataBuf)[1],
  914. ((PULONG)pThisDev->rcvInfo.pRcvBuffer->dataBuf)[2]);
  915. #endif
  916. #ifdef DEBUG_IRSIR
  917. //
  918. // This is the count of how many irps with data to get this frame.
  919. //
  920. DEBUGMSG(DBG_STAT, ("****IrpCount = %d, Bytes = %d, Frame Length = %d\n",
  921. irpCount, bytesReceived, pThisDev->rcvInfo.pRcvBuffer->dataLen));
  922. irpCount = 0;
  923. bytesReceived = 0;
  924. #endif //DEBUG_IRSIR
  925. pNextBuffer = (PRCV_BUFFER)MyInterlockedRemoveHeadList(
  926. &(pThisDev->rcvFreeQueue),
  927. &(pThisDev->rcvQueueSpinLock)
  928. );
  929. //
  930. // Compute the FCS.
  931. //
  932. fcs = ComputeFCS(
  933. pThisDev->rcvInfo.pRcvBuffer->dataBuf,
  934. pThisDev->rcvInfo.pRcvBuffer->dataLen
  935. );
  936. if (fcs != GOOD_FCS || !pNextBuffer)
  937. {
  938. //
  939. // Bad frame, just drop it and increment our dropped packets
  940. // count.
  941. //
  942. pThisDev->packetsReceivedDropped++;
  943. #if DBG
  944. if (fcs != GOOD_FCS)
  945. {
  946. LOG_ENTRY('CF', pThisDev, 0, 0);
  947. DEBUGMSG(DBG_STAT|DBG_WARN, (" FCS ERR Len(%d)\n", pThisDev->rcvInfo.pRcvBuffer->dataLen));
  948. }
  949. if (!pNextBuffer)
  950. {
  951. LOG_ENTRY('BI', pThisDev, 0, 0);
  952. DEBUGMSG(DBG_STAT|DBG_WARN, (" Dropped packet due to insufficient buffers\n"));
  953. }
  954. #endif
  955. #if 0
  956. DBG_PrintBuf(pThisDev->rcvInfo.pRcvBuffer->dataBuf,
  957. pThisDev->rcvInfo.pRcvBuffer->dataLen);
  958. #endif
  959. status = STATUS_UNSUCCESSFUL;
  960. NdisZeroMemory(
  961. pThisDev->rcvInfo.pRcvBuffer->dataBuf,
  962. RCV_BUFFER_SIZE
  963. );
  964. pThisDev->rcvInfo.pRcvBuffer->dataLen = 0;
  965. if (pNextBuffer)
  966. {
  967. MyInterlockedInsertHeadList(
  968. &(pThisDev->rcvFreeQueue),
  969. &pNextBuffer->linkage,
  970. &(pThisDev->rcvQueueSpinLock)
  971. );
  972. }
  973. goto done;
  974. }
  975. LOG_ENTRY('HF', pThisDev, 0, 0);
  976. //
  977. // Remove fcs from the end of the packet.
  978. //
  979. pThisDev->rcvInfo.pRcvBuffer->dataLen -= SLOW_IR_FCS_SIZE;
  980. //
  981. // Fix up some other packet fields.
  982. //
  983. NDIS_SET_PACKET_HEADER_SIZE(
  984. pThisDev->rcvInfo.pRcvBuffer->packet,
  985. SLOW_IR_ADDR_SIZE + SLOW_IR_CONTROL_SIZE
  986. );
  987. //
  988. // We need to call NdisQueryPacket to get a pointer to the
  989. // NDIS_BUFFER so that we can adjust the buffer length
  990. // to the actual size of the data and not the size
  991. // of the buffer.
  992. //
  993. // NdisQueryPacket will return other information, but since
  994. // we built the packet ourselves, we already know that info.
  995. //
  996. NdisQueryPacket(
  997. pThisDev->rcvInfo.pRcvBuffer->packet,
  998. NULL, // physical buffer count, don't care
  999. NULL, // buffer count, don't care, we know it is 1
  1000. &pBuffer, // get a pointer to our buffer
  1001. NULL // total packet lenght, don't care
  1002. );
  1003. NdisAdjustBufferLength(
  1004. pBuffer,
  1005. pThisDev->rcvInfo.pRcvBuffer->dataLen
  1006. );
  1007. //
  1008. // Set to use the new buffer before we indicate the packet.
  1009. //
  1010. pThisBuffer = pThisDev->rcvInfo.pRcvBuffer;
  1011. pThisDev->rcvInfo.pRcvBuffer = pNextBuffer;
  1012. ASSERT(pThisDev->rcvInfo.pRcvBuffer != NULL);
  1013. //
  1014. // Indicate the packet to NDIS.
  1015. //
  1016. InterlockedIncrement(&pThisDev->packetsHeldByProtocol);
  1017. NdisMIndicateReceivePacket(
  1018. pThisDev->hNdisAdapter,
  1019. &pThisBuffer->packet,
  1020. 1
  1021. );
  1022. done:
  1023. DEBUGMSG(DBG_FUNC, ("-DeliverBuffer\n"));
  1024. return;
  1025. }
  1026. /*****************************************************************************
  1027. *
  1028. * Function: IrsirReturnPacket
  1029. *
  1030. * Synopsis: The protocol returns ownership of a receive packet to
  1031. * the ir device object.
  1032. *
  1033. * Arguments: Context - a pointer to the current ir device obect.
  1034. * pReturnedPacket - a pointer the packet which the protocol
  1035. * is returning ownership.
  1036. *
  1037. * Returns: None.
  1038. *
  1039. * Algorithm:
  1040. * 1) Take the receive buffer off of the pending queue.
  1041. * 2) Put the receive buffer back on the free queue.
  1042. *
  1043. * History: dd-mm-yyyy Author Comment
  1044. * 10/8/1996 sholden author
  1045. *
  1046. * Notes:
  1047. *
  1048. *
  1049. *****************************************************************************/
  1050. VOID
  1051. IrsirReturnPacket(
  1052. IN NDIS_HANDLE Context,
  1053. IN PNDIS_PACKET pReturnedPacket
  1054. )
  1055. {
  1056. PIR_DEVICE pThisDev;
  1057. PNDIS_BUFFER pBuffer;
  1058. PRCV_BUFFER pRcvBuffer;
  1059. PLIST_ENTRY pTmpListEntry;
  1060. DEBUGMSG(DBG_FUNC, ("+IrsirReturnPacket\n"));
  1061. //
  1062. // The context is just the pointer to the current ir device object.
  1063. //
  1064. pThisDev = CONTEXT_TO_DEV(Context);
  1065. pThisDev->packetsReceived++;
  1066. {
  1067. PPACKET_RESERVED_BLOCK PacketReserved;
  1068. PacketReserved=(PPACKET_RESERVED_BLOCK)&pReturnedPacket->MiniportReservedEx[0];
  1069. pRcvBuffer=PacketReserved->Context;
  1070. }
  1071. ProcessReturnPacket(pThisDev, pRcvBuffer);
  1072. DEBUGMSG(DBG_FUNC, ("-IrsirReturnPacket\n"));
  1073. return;
  1074. }
  1075. VOID
  1076. SerialWaitCallback(PIR_WORK_ITEM pWorkItem)
  1077. /*++
  1078. Routine Description:
  1079. Arguments:
  1080. Return Value:
  1081. none
  1082. --*/
  1083. {
  1084. PIR_DEVICE pThisDev = pWorkItem->pIrDevice;
  1085. NTSTATUS Status;
  1086. ULONG BytesRead;
  1087. FreeWorkItem(pWorkItem);
  1088. do
  1089. {
  1090. SerialSynchronousRead(pThisDev->pSerialDevObj,
  1091. pThisDev->pRcvIrpBuffer,
  1092. SERIAL_RECEIVE_BUFFER_LENGTH,
  1093. &BytesRead);
  1094. if (BytesRead>0)
  1095. {
  1096. ProcessData(pThisDev, pThisDev->pRcvIrpBuffer, BytesRead);
  1097. }
  1098. } while ( BytesRead == SERIAL_RECEIVE_BUFFER_LENGTH );
  1099. if (InterlockedExchange(&pThisDev->fWaitPending, 1)==0)
  1100. {
  1101. LARGE_INTEGER Time;
  1102. KeQuerySystemTime(&Time);
  1103. LOG_ENTRY('WS', pThisDev, Time.LowPart/10000, Time.HighPart);
  1104. Status = SerialCallbackOnMask(pThisDev->pSerialDevObj,
  1105. SerialIoCompleteWait,
  1106. &pThisDev->WaitIosb,
  1107. DEV_TO_CONTEXT(pThisDev),
  1108. &pThisDev->MaskResult);
  1109. if (Status!=STATUS_SUCCESS && Status!=STATUS_PENDING)
  1110. {
  1111. DEBUGMSG(DBG_ERROR, ("IRSIR: SerialCallbackOnMask failed (0x%x:%d)\n", Status));
  1112. ASSERT(0);
  1113. }
  1114. }
  1115. return;
  1116. }
  1117. NTSTATUS
  1118. SerialIoCompleteWait(
  1119. IN PDEVICE_OBJECT pSerialDevObj,
  1120. IN PIRP pIrp,
  1121. IN PVOID Context
  1122. )
  1123. {
  1124. PIR_DEVICE pThisDev;
  1125. BOOLEAN fSwitchSuccessful;
  1126. NDIS_HANDLE hSwitchToMiniport;
  1127. NTSTATUS status = STATUS_SUCCESS;
  1128. ULONG BytesRead;
  1129. ULONG WaitWasPending;
  1130. DEBUGMSG(DBG_FUNC, ("+SerialIoCompleteWait\n"));
  1131. //
  1132. // The context given to IoSetCompletionRoutine is simply the the ir
  1133. // device object pointer.
  1134. //
  1135. pThisDev = CONTEXT_TO_DEV(Context);
  1136. WaitWasPending = InterlockedExchange(&pThisDev->fWaitPending, 0);
  1137. ASSERT(WaitWasPending);
  1138. *pIrp->UserIosb = pIrp->IoStatus;
  1139. LOG_ENTRY('1i', pThisDev, pIrp, 0);
  1140. IoFreeIrp(pIrp);
  1141. //
  1142. // Need to check if there is a pending halt or reset. If there is, we
  1143. // just leave the receive completion. Since we maintain one irp associated
  1144. // with the receive functionality, the irp will be deallocated in
  1145. // the ir device object deinitialization routine.
  1146. //
  1147. if ((pThisDev->fPendingHalt == TRUE) ||
  1148. (pThisDev->fPendingReset == TRUE))
  1149. {
  1150. //
  1151. // Set the fReceiving boolean so that the halt and reset routines
  1152. // know when it is okay to continue.
  1153. //
  1154. pThisDev->fReceiving = FALSE;
  1155. //
  1156. // Free the irp and associate memory...the rest will be
  1157. // freed in the halt or reset.
  1158. //
  1159. goto done;
  1160. }
  1161. //
  1162. // Next we take care of any pending set speeds.
  1163. //
  1164. //
  1165. // This completion routine is running at IRQL DISPATCH_LEVEL. Therefore,
  1166. // we cannot make a synchronous call to the serial driver. Set an event
  1167. // to notify the PassiveLevelThread to perform the speed change. We will
  1168. // exit this without creating another irp to the serial device object.
  1169. // PassiveLevelThread will call InitializeReceive after the speed has
  1170. // been set.
  1171. //
  1172. if (pThisDev->fPendingSetSpeed == TRUE)
  1173. {
  1174. pThisDev->fReceiving = FALSE;
  1175. goto done;
  1176. }
  1177. //
  1178. // Free the irp and reinit the buffer and status block.
  1179. //
  1180. {
  1181. LARGE_INTEGER Time;
  1182. KeQuerySystemTime(&Time);
  1183. LOG_ENTRY('ES', pThisDev, Time.LowPart/10000, Time.HighPart);
  1184. }
  1185. if (ScheduleWorkItem(0, pThisDev, SerialWaitCallback,
  1186. (PVOID)0, 0)!=NDIS_STATUS_SUCCESS
  1187. )
  1188. {
  1189. DEBUGMSG(DBG_ERR, ("IRSIR:SerialIoCompleteWait: Timed out and couldn't reschedule Wait.\n"
  1190. " We're going down.\n"));
  1191. }
  1192. done:
  1193. DEBUGMSG(DBG_FUNC, ("-SerialIoCompleteWait\n"));
  1194. //
  1195. // We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
  1196. // routine (IofCompleteRequest) will stop working on the irp.
  1197. //
  1198. status = STATUS_MORE_PROCESSING_REQUIRED;
  1199. return status;
  1200. }