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.

1445 lines
48 KiB

  1. /*-------------------------------------------------------------------
  2. | isr.c - Interrupt(or Timer) Service Routine, RocketPort & VS.
  3. 1-21-99 fix broken EV_TXEMPTY events due to 1-18-99 spinlock changes. kpb
  4. 1-18-99 implement better write spinlocking to avoid blue-screen
  5. with wait on tx option.
  6. 1-18-99 implement wait on tx option for VS.
  7. 9-24-98 add RING emulation.
  8. Copyright 1993-98 Comtrol Corporation. All rights reserved.
  9. |--------------------------------------------------------------------*/
  10. #include "precomp.h"
  11. // #define LOAD_TESTING
  12. // #define SOFT_LOOP_BACK
  13. // local prototypes
  14. static BOOLEAN SerialPoll(void);
  15. static void ServiceRocket(PSERIAL_DEVICE_EXTENSION extension);
  16. static void ServiceVS(PSERIAL_DEVICE_EXTENSION extension);
  17. static void RocketRead(PSERIAL_DEVICE_EXTENSION extension);
  18. static void VSRead(PSERIAL_DEVICE_EXTENSION extension);
  19. static void RocketRefresh(void);
  20. static void ring_check(PSERIAL_DEVICE_EXTENSION extension,
  21. BYTE *data,
  22. int len);
  23. #ifdef S_VS
  24. #define USE_MEMCHR_SCAN
  25. #ifdef USE_MEMCHR_SCAN
  26. #define search_match(buf, cnt, chr) \
  27. (memchr(buf, chr, cnt) != NULL)
  28. #else
  29. static int search_match(BYTE *buf, int count, BYTE eventchar);
  30. #endif
  31. #endif
  32. #ifdef S_RK
  33. /*---------------------------------------------------------------------------
  34. Function : SerialISR
  35. Purpose: This is the Interrupt Service Routine for RocketPort.
  36. Call: SerialISR(InterruptObject,Context)
  37. PDEVICE_OBJECT DeviceObject: Pointer to the Device Object
  38. Context: Pointer to the extensionst Packet
  39. Return: STATUS_SUCCESS: always
  40. Comments: This function is the device driver ISR entry point.
  41. The interrupt from the first active board is used to poll the
  42. ports for any work to be done.
  43. |---------------------------------------------------------------------------*/
  44. BOOLEAN SerialISR(
  45. IN PKINTERRUPT InterruptObject,
  46. IN PVOID Context)
  47. {
  48. CONTROLLER_T *CtlP;
  49. unsigned char CtlInt; /* controller interrupt status */
  50. //static int trace_cnt = 0;
  51. // ++trace_cnt;
  52. // if (trace_cnt < 5)
  53. // {
  54. // {
  55. // char str[20];
  56. // Sprintf(str, "isr trace:%d\n", trace_cnt);
  57. // q_put(&Driver.DebugQ, (BYTE *) str, strlen(str));
  58. // // showed IRQL:2, ms doc says should be at DISPATCH_LEVEL
  59. // }
  60. // }
  61. CtlP = Driver.irq_ext->CtlP; // &sController[0];
  62. if (CtlP->BusType == Isa)
  63. {
  64. CtlInt = sGetControllerIntStatus(CtlP);
  65. }
  66. else if (CtlP->BusType == PCIBus)
  67. {
  68. CtlInt = sPCIGetControllerIntStatus(CtlP);
  69. if ((CtlInt & PCI_PER_INT_STATUS) ==0)
  70. return FALSE; // Not our Interupt PCI devices share interrupts
  71. }
  72. SerialPoll();
  73. if (CtlP->BusType == Isa)
  74. {
  75. sControllerEOI(CtlP);
  76. }
  77. else if (CtlP->BusType == PCIBus)
  78. sPCIControllerEOI(CtlP);
  79. return TRUE;
  80. }
  81. #endif
  82. /*---------------------------------------------------------------------------
  83. Function : TimerDpc
  84. Purpose: This is the Timer routine, alternative to interrupts for polling.
  85. Call: SerialTimerDpc(InterruptObject,Context)
  86. PDEVICE_OBJECT DeviceObject: Pointer to the Device Object
  87. Context: Pointer to the extensionst Packet
  88. Return: STATUS_SUCCESS: always
  89. |---------------------------------------------------------------------------*/
  90. VOID TimerDpc(
  91. IN PKDPC Dpc,
  92. IN PVOID DeferredContext,
  93. IN PVOID SystemContext1,
  94. IN PVOID SystemContext2)
  95. {
  96. KIRQL OldIrql;
  97. #ifdef USE_SYNC_LOCKS
  98. KeAcquireSpinLock(&Driver.TimerLock, &OldIrql);
  99. #endif
  100. SerialPoll(); // poll the rocketport for work to do
  101. #ifdef USE_SYNC_LOCKS
  102. KeReleaseSpinLock(&Driver.TimerLock, OldIrql );
  103. #endif
  104. // setup the Timer again.
  105. KeSetTimer(&Driver.PollTimer,
  106. Driver.PollIntervalTime,
  107. &Driver.TimerDpc);
  108. return;
  109. }
  110. /*---------------------------------------------------------------------------
  111. Function : SerialPoll
  112. Purpose: This is called from ISR or Timer routine. Common routine to
  113. periodically service the rocketport card.
  114. Return: FALSE if not our interrupt(sharing allowed so causes the
  115. OS to pass on to next handler(if present).
  116. TRUE if it was our interrupt. Return value does not matter
  117. if running off from Kernal TIMER.
  118. |---------------------------------------------------------------------------*/
  119. static BOOLEAN SerialPoll(void)
  120. {
  121. PSERIAL_DEVICE_EXTENSION extension;
  122. PSERIAL_DEVICE_EXTENSION board_ext;
  123. // periodically we will re-calculate the timer base of NT.
  124. // we do it periodically, so that we don't waste a bunch of
  125. // CPU time, we only do it every 128 ticks..
  126. // We use this information so that our timers can have a
  127. // valid tick-base. The timers could do these system calls
  128. // everytime, but this would get expense CPU wise, so we
  129. // calculate the basic tick rate in milliseconds so that
  130. // timer routines can do something simple like
  131. // ticktime += msTickBase
  132. ++Driver.TickBaseCnt;
  133. if (Driver.TickBaseCnt > 128)
  134. {
  135. ULONG msBase;
  136. Driver.TickBaseCnt = 0;
  137. KeQuerySystemTime(&Driver.IsrSysTime);
  138. msBase = (ULONG)(Driver.IsrSysTime.QuadPart - Driver.LastIsrSysTime.QuadPart);
  139. // msBase now has 100ns ticks since last time we did this(128 ticks ago)
  140. msBase = (msBase / 128);
  141. // now msBase has the average 100ns time for 1 of our ISR ticks.
  142. // covert this to 100us units
  143. msBase = (msBase / 1000);
  144. if (msBase < 10) // make at least 1ms
  145. msBase = 10;
  146. if (msBase > 200) // ensure it is less than 20ms
  147. msBase = 200;
  148. // store it for timer use
  149. Driver.Tick100usBase = msBase;
  150. Driver.LastIsrSysTime.QuadPart = Driver.IsrSysTime.QuadPart;
  151. }
  152. ++Driver.PollCnt;
  153. if (Driver.Stop_Poll) // flag to stop poll access
  154. return TRUE; // signal it was our interrupt
  155. if ((Driver.PollCnt & 0x7f) == 0) // every 128 ticks(about once a sec)
  156. {
  157. RocketRefresh(); // general background activity
  158. }
  159. #ifdef LOAD_TESTING
  160. if (Driver.load_testing != 0)
  161. {
  162. unsigned int i,j;
  163. for (j=1000; j<Driver.load_testing; j++)
  164. {
  165. for (i=0; i<10000; i++)
  166. {
  167. //ustat = sGetModemStatus(extension->ChP);
  168. ustat = i+1;
  169. }
  170. }
  171. }
  172. #endif
  173. // main poll service loop, service each board...
  174. board_ext = Driver.board_ext;
  175. while (board_ext != NULL)
  176. {
  177. if ((!board_ext->FdoStarted) || (!board_ext->config->HardwareStarted))
  178. {
  179. board_ext = board_ext->board_ext; // next in chain
  180. continue; // Check next port on this board
  181. }
  182. #ifdef S_VS
  183. if (board_ext->pm->state == ST_ACTIVE)
  184. {
  185. port_poll(board_ext->pm); // poll x times per second
  186. hdlc_poll(board_ext->hd);
  187. }
  188. else
  189. {
  190. port_state_handler(board_ext->pm);
  191. }
  192. #endif
  193. // main poll service loop, service each board...
  194. extension = board_ext->port_ext;
  195. while (extension != NULL)
  196. {
  197. // If device not open, don't do anything
  198. if ( !extension->DeviceIsOpen )
  199. {
  200. extension = extension->port_ext; // next in chain
  201. continue; // Check next port on this board
  202. }
  203. #ifdef S_RK
  204. ServiceRocket(extension);
  205. #else
  206. ServiceVS(extension);
  207. #endif
  208. extension = extension->port_ext; // next in chain
  209. } // while port extension
  210. board_ext = board_ext->board_ext; // next in chain
  211. } // while board extension
  212. return TRUE; // signal it was our interrupt
  213. }
  214. #ifdef S_VS
  215. /*---------------------------------------------------------------------------
  216. ServiceVS - Service the VS virtual hardware(queues, nic handling..)
  217. |---------------------------------------------------------------------------*/
  218. static void ServiceVS(PSERIAL_DEVICE_EXTENSION extension)
  219. {
  220. SerPort *sp;
  221. ULONG wCount;
  222. int wrote_some_data;
  223. sp = extension->Port;
  224. #ifdef SOFT_LOOP_BACK
  225. if (sp->mcr_value & MCR_LOOP_SET_ON)
  226. {
  227. int room, out_cnt, wrap_cnt;
  228. Queue *qin, *qout;
  229. //--------- Do a simple loopback emulation
  230. if (!q_empty(&sp->QOut)) // if output queue has data
  231. {
  232. qin = &sp->QIn;
  233. qout = &sp->QOut;
  234. room = q_room(qin); // chk if room to dump it in
  235. out_cnt = q_count(qout);
  236. if (out_cnt > room)
  237. out_cnt = room;
  238. if (out_cnt > (int)(extension->BaudRate / 1000)) // assume 10ms tick
  239. {
  240. out_cnt = (int)(extension->BaudRate / 1000);
  241. }
  242. if (out_cnt != 0)
  243. {
  244. if (q_room_put_till_wrap(qin) < out_cnt) // need a two part move
  245. {
  246. wrap_cnt = q_room_put_till_wrap(qin);
  247. // read in the data to the buffer, first block
  248. q_get(qout, &qin->QBase[qin->QPut], wrap_cnt);
  249. // read in the data to the buffer, second block
  250. q_get(qout, qin->QBase, out_cnt - wrap_cnt);
  251. }
  252. else // single move will do, no wrap
  253. {
  254. // read in the data to the buffer, 1 block
  255. q_get(qout, &qin->QBase[qin->QPut], out_cnt);
  256. }
  257. q_putted(qin, out_cnt); // update queue indexes
  258. } // room to put it
  259. } // output q not empty
  260. }
  261. #endif
  262. //////////////////////////////////////
  263. // If there is any data in the Rx FIFO
  264. // Read the data and do error checking
  265. if(!q_empty(&extension->Port->QIn))
  266. VSRead(extension);
  267. if (extension->port_config->RingEmulate)
  268. {
  269. if (extension->ring_timer != 0) // RI on
  270. {
  271. --extension->ring_timer;
  272. if (extension->ring_timer != 0) // RI on
  273. sp->msr_value |= MSR_RING_ON;
  274. else
  275. {
  276. //MyKdPrint(D_Test,("RING OFF!\n"))
  277. sp->msr_value &= ~MSR_RING_ON;
  278. }
  279. }
  280. }
  281. if (sp->old_msr_value != sp->msr_value) // delta change bits
  282. {
  283. WORD diff, ModemStatus;
  284. diff = sp->old_msr_value ^ sp->msr_value;
  285. sp->old_msr_value = sp->msr_value;
  286. if (Driver.TraceOptions & 8) // trace output data
  287. {
  288. char str[20];
  289. Sprintf(str, "msr:%x\n", sp->msr_value);
  290. q_put(&Driver.DebugQ, (BYTE *) str, strlen(str));
  291. }
  292. // Check on modem changes and update the modem status
  293. if (diff & (MSR_CD_ON | MSR_CTS_ON | MSR_RING_ON | MSR_DSR_ON | MSR_TX_FLOWED_OFF))
  294. {
  295. // make a bit set that ioctl can use in report
  296. ModemStatus = 0;
  297. if (sp->msr_value & MSR_CTS_ON)
  298. {
  299. ModemStatus |= SERIAL_CTS_STATE;
  300. if (extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE)
  301. extension->TXHolding &= ~SERIAL_TX_CTS; // set holding
  302. }
  303. else
  304. {
  305. if (extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE)
  306. extension->TXHolding |= SERIAL_TX_CTS; // set holding
  307. }
  308. if (sp->msr_value & MSR_DSR_ON)
  309. {
  310. ModemStatus |= SERIAL_DSR_STATE;
  311. if (extension->HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE)
  312. extension->TXHolding &= ~SERIAL_TX_DSR; // set holding
  313. }
  314. else
  315. {
  316. if (extension->HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE)
  317. extension->TXHolding |= SERIAL_TX_DSR; // set holding
  318. }
  319. if (sp->msr_value & MSR_RING_ON)
  320. ModemStatus |= SERIAL_RI_STATE;
  321. if (sp->msr_value & MSR_CD_ON)
  322. {
  323. ModemStatus |= SERIAL_DCD_STATE;
  324. if (extension->HandFlow.ControlHandShake & SERIAL_DCD_HANDSHAKE)
  325. extension->TXHolding &= ~SERIAL_TX_DCD; // set holding
  326. }
  327. else
  328. {
  329. if (extension->HandFlow.ControlHandShake & SERIAL_DCD_HANDSHAKE)
  330. extension->TXHolding |= SERIAL_TX_DCD; // set holding
  331. }
  332. if (sp->msr_value & MSR_TX_FLOWED_OFF)
  333. {
  334. // handle holding detection if xon,xoff tx control activated
  335. if (extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT)
  336. {
  337. extension->TXHolding |= SERIAL_TX_XOFF; // holding
  338. }
  339. }
  340. else if (extension->TXHolding & SERIAL_TX_XOFF)
  341. {
  342. extension->TXHolding &= ~SERIAL_TX_XOFF; // not holding
  343. }
  344. extension->ModemStatus = (ULONG) ModemStatus;
  345. // following is for built in NT virtual 16450 uart support
  346. // virtual uart depends on escape commands in data stream to
  347. // detect modem-signal changes.
  348. if (extension->escapechar != 0)
  349. {
  350. UCHAR msr;
  351. if (q_room(&extension->RxQ) > 2)
  352. {
  353. q_put_one(&extension->RxQ, extension->escapechar);
  354. q_put_one(&extension->RxQ, SERIAL_LSRMST_MST);
  355. msr = (UCHAR)extension->ModemStatus;
  356. if (diff & MSR_CD_ON) msr |= 8; // SERIAL_MSR_DDCD
  357. if (diff & MSR_RING_ON) msr |= 4; // SERIAL_MSR_TERI
  358. if (diff & MSR_DSR_ON) msr |= 2; // SERIAL_MSR_DDSR
  359. if (diff & MSR_CTS_ON) msr |= 1; // SERIAL_MSR_DCTS
  360. q_put_one(&extension->RxQ, msr);
  361. } // q_room
  362. } // if escapechar
  363. // Check if there are any modem events in the WaitMask
  364. if (extension->IsrWaitMask & ( SERIAL_EV_RING |
  365. SERIAL_EV_CTS |
  366. SERIAL_EV_DSR |
  367. SERIAL_EV_RLSD ))
  368. {
  369. if( (extension->IsrWaitMask & SERIAL_EV_RING) &&
  370. (diff & MSR_RING_ON) )
  371. { extension->HistoryMask |= SERIAL_EV_RING;
  372. }
  373. if ((extension->IsrWaitMask & SERIAL_EV_CTS) &&
  374. (diff & MSR_CTS_ON) )
  375. { extension->HistoryMask |= SERIAL_EV_CTS;
  376. }
  377. if( (extension->IsrWaitMask & SERIAL_EV_DSR) &&
  378. (diff & MSR_DSR_ON) )
  379. { extension->HistoryMask |= SERIAL_EV_DSR;
  380. }
  381. if( (extension->IsrWaitMask & SERIAL_EV_RLSD) &&
  382. (diff & MSR_CD_ON) )
  383. { extension->HistoryMask |= SERIAL_EV_RLSD;
  384. }
  385. } // isrwaitmask
  386. } // diff
  387. } // old_msr != msr
  388. ////////////////////////////////////////////////////////////
  389. // At this point, all receive events should be chalked up.
  390. // Some events have been checked in VSRead()
  391. // Any Tx related WaitMask events will be reported in Tx Dpc
  392. // Abort all pending reads and writes if an error and ERROR_ABORT
  393. if( (extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) &&
  394. (extension->ErrorWord) )
  395. {
  396. KeInsertQueueDpc(&extension->CommErrorDpc,NULL,NULL);
  397. }
  398. // Tell the app about any Wait events that have occurred if needed
  399. if (extension->WaitIsISRs && extension->HistoryMask)
  400. {
  401. *extension->IrpMaskLocation = extension->HistoryMask;
  402. // Done with these
  403. extension->WaitIsISRs = 0;
  404. extension->HistoryMask = 0;
  405. extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  406. KeInsertQueueDpc(&extension->CommWaitDpc,NULL,NULL);
  407. }
  408. //-------- check for data to move from input queue to irp-buffer
  409. if (extension->ReadPending && // we are given control to fill
  410. extension->NumberNeededForRead && // more to be filled
  411. extension->CurrentReadIrp) // rug not pulled out from our feet
  412. {
  413. if (extension->RxQ.QPut != extension->RxQ.QGet) // not empty
  414. {
  415. // move data from input queue to IRP buffer.
  416. extension->CountOnLastRead |=
  417. SerialGetCharsFromIntBuffer(extension);
  418. if (extension->NumberNeededForRead == 0) // IRP complete!
  419. {
  420. extension->CurrentReadIrp->IoStatus.Information =
  421. IoGetCurrentIrpStackLocation(
  422. extension->CurrentReadIrp
  423. )->Parameters.Read.Length;
  424. extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
  425. // We're finished with this read
  426. extension->ReadPending = FALSE;
  427. KeInsertQueueDpc( &extension->CompleteReadDpc, NULL, NULL );
  428. } // irp complete
  429. } // more data to read out of input queue
  430. } // end of Read completion
  431. wrote_some_data = 0;
  432. if (extension->WriteBelongsToIsr == 1) // its ours to process
  433. {
  434. // own the cur write irp, have data to write
  435. if (extension->WriteLength)
  436. {
  437. wrote_some_data = 1;
  438. extension->ISR_Flags |= TX_NOT_EMPTY; // use to detect fifo empty
  439. // Send it all ,WriteTxBlk will chk fifo
  440. wCount = q_put( &extension->Port->QOut,
  441. (PUCHAR)((extension->CurrentWriteIrp)->AssociatedIrp.SystemBuffer)+
  442. (extension->CurrentWriteIrp)->IoStatus.Information,
  443. extension->WriteLength);
  444. extension->OurStats.TransmittedCount += wCount;
  445. extension->WriteLength -= wCount;
  446. (extension->CurrentWriteIrp)->IoStatus.Information += wCount;
  447. if(!extension->WriteLength)//No more to write Close the DPC call
  448. {
  449. if (!extension->port_config->WaitOnTx)
  450. {
  451. extension->WriteBelongsToIsr = 2;
  452. KeInsertQueueDpc( &extension->CompleteWriteDpc, NULL, NULL );
  453. }
  454. }
  455. } // if (extension->WriteLength) // data to write
  456. }
  457. if (!wrote_some_data)
  458. {
  459. if (extension->ISR_Flags & TX_NOT_EMPTY)
  460. {
  461. //----- check for EV_TXEMPTY condition
  462. // and no pending writes
  463. // check to see if tx-fifo is empty
  464. if ((q_empty(&extension->Port->QOut)) &&
  465. (PortGetTxCntRemote(extension->Port) == 0))
  466. {
  467. if (IsListEmpty(&extension->WriteQueue))
  468. {
  469. extension->ISR_Flags &= ~TX_NOT_EMPTY;
  470. // do we have an ev_txempty thing to take care of?
  471. if (extension->IrpMaskLocation &&
  472. (extension->IsrWaitMask & SERIAL_EV_TXEMPTY) )
  473. {
  474. // app has wait irp pending
  475. if (extension->CurrentWaitIrp)
  476. {
  477. extension->HistoryMask |= SERIAL_EV_TXEMPTY;
  478. }
  479. }
  480. } // no more write irps queued up
  481. // see if we need to finish waitontx write irp
  482. if (extension->port_config->WaitOnTx)
  483. {
  484. if (extension->WriteBelongsToIsr == 1) // its ours to process
  485. {
  486. extension->WriteBelongsToIsr = 2;
  487. KeInsertQueueDpc( &extension->CompleteWriteDpc, NULL, NULL );
  488. }
  489. }
  490. } // tx fifo is empty
  491. } // TX_NOT_EMPTY
  492. } // !wrote_some_data
  493. // Tell the app about any Wait events that have occurred if needed
  494. if (extension->WaitIsISRs && extension->HistoryMask)
  495. {
  496. #ifdef COMMENT_OUT
  497. if (Driver.TraceOptions & 8) // trace output data
  498. {
  499. char str[20];
  500. Sprintf(str, "ISR Event:%xH\n", extension->HistoryMask);
  501. q_put(&Driver.DebugQ, (BYTE *) str, strlen(str));
  502. }
  503. #endif
  504. *extension->IrpMaskLocation = extension->HistoryMask;
  505. // Done with these
  506. extension->WaitIsISRs = 0;
  507. extension->HistoryMask = 0;
  508. extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  509. KeInsertQueueDpc(&extension->CommWaitDpc,NULL,NULL);
  510. }
  511. }
  512. #endif
  513. #ifdef S_RK
  514. /*---------------------------------------------------------------------------
  515. ServiceRocket - Handle the RocketPort hardware service
  516. |---------------------------------------------------------------------------*/
  517. static void ServiceRocket(PSERIAL_DEVICE_EXTENSION extension)
  518. {
  519. ULONG ustat;
  520. ULONG wCount;
  521. int wrote_some_data;
  522. ustat = sGetChanIntID(extension->ChP);
  523. //////////////////////////////////////
  524. // If there is any data in the Rx FIFO
  525. // Read the data and do error checking
  526. if (ustat & RXF_TRIG)
  527. {
  528. RocketRead(extension);
  529. }
  530. // Check on modem changes and update the modem status
  531. if (ustat & (DELTA_CD|DELTA_CTS|DELTA_DSR))
  532. {
  533. // Read and update the modem status in the extension
  534. SetExtensionModemStatus(extension);
  535. }
  536. // handle RPortPlus RI signal
  537. if (extension->board_ext->config->IsRocketPortPlus)
  538. {
  539. if (sGetRPlusModemRI(extension->ChP) != 0) // RI on
  540. {
  541. extension->ModemStatus |= SERIAL_RI_STATE;
  542. }
  543. else
  544. {
  545. extension->ModemStatus &= ~SERIAL_RI_STATE;
  546. }
  547. }
  548. #ifdef RING_FAKE
  549. if (extension->port_config->RingEmulate)
  550. {
  551. if (extension->ring_timer != 0) // RI on
  552. {
  553. --extension->ring_timer;
  554. if (extension->ring_timer != 0) // RI on
  555. extension->ModemStatus |= SERIAL_RI_STATE;
  556. else
  557. extension->ModemStatus &= ~SERIAL_RI_STATE;
  558. }
  559. }
  560. #endif
  561. if (extension->EventModemStatus != extension->ModemStatus)
  562. {
  563. // xor to show changed bits
  564. ustat = extension->EventModemStatus ^ extension->ModemStatus;
  565. // update change
  566. extension->EventModemStatus = extension->ModemStatus;
  567. // following is for built in NT virtual 16450 uart support
  568. // virtual uart depends on escape commands in data stream to
  569. // detect modem-signal changes.
  570. if (extension->escapechar != 0)
  571. {
  572. UCHAR msr;
  573. // we are assuming we have room to put the following!
  574. if (q_room(&extension->RxQ) > 2)
  575. {
  576. q_put_one(&extension->RxQ, extension->escapechar);
  577. q_put_one(&extension->RxQ, SERIAL_LSRMST_MST);
  578. msr = (UCHAR)extension->ModemStatus;
  579. if (ustat & SERIAL_DCD_STATE) msr |= 8; // SERIAL_MSR_DDCD
  580. if (ustat & SERIAL_RI_STATE) msr |= 4; // SERIAL_MSR_TERI
  581. if (ustat & SERIAL_DSR_STATE) msr |= 2; // SERIAL_MSR_DDSR
  582. if (ustat & SERIAL_CTS_STATE) msr |= 1; // SERIAL_MSR_DCTS
  583. q_put_one(&extension->RxQ, msr);
  584. }
  585. }
  586. // Check if there are any modem events in the WaitMask
  587. if(extension->IsrWaitMask & ( SERIAL_EV_RING |
  588. SERIAL_EV_CTS |
  589. SERIAL_EV_DSR |
  590. SERIAL_EV_RLSD )
  591. )
  592. {
  593. if( (extension->IsrWaitMask & SERIAL_EV_RING) &&
  594. (ustat & SERIAL_RI_STATE) )
  595. { extension->HistoryMask |= SERIAL_EV_RING;
  596. }
  597. if( (extension->IsrWaitMask & SERIAL_EV_CTS) &&
  598. (ustat & SERIAL_CTS_STATE) )
  599. { extension->HistoryMask |= SERIAL_EV_CTS;
  600. }
  601. if( (extension->IsrWaitMask & SERIAL_EV_DSR) &&
  602. (ustat & SERIAL_DSR_STATE) )
  603. { extension->HistoryMask |= SERIAL_EV_DSR;
  604. }
  605. if( (extension->IsrWaitMask & SERIAL_EV_RLSD) &&
  606. (ustat & SERIAL_DCD_STATE) )
  607. { extension->HistoryMask |= SERIAL_EV_RLSD;
  608. }
  609. }
  610. } // end if modem-control detect change
  611. ////////////////////////////////////////////////////////////
  612. // At this point, all receive events should be chalked up.
  613. // Some events have been checked in RocketRead()
  614. // Any Tx related WaitMask events will be reported in Tx Dpc
  615. // Abort all pending reads and writes if an error and ERROR_ABORT
  616. if( (extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) &&
  617. (extension->ErrorWord) )
  618. {
  619. KeInsertQueueDpc(&extension->CommErrorDpc,NULL,NULL);
  620. }
  621. //-------- check for data to move from input queue to irp-buffer
  622. if (extension->ReadPending && // we are given control to fill
  623. extension->NumberNeededForRead && // more to be filled
  624. extension->CurrentReadIrp) // rug not pulled out from our feet
  625. {
  626. if (extension->RxQ.QPut != extension->RxQ.QGet) // not empty
  627. {
  628. // move data from input queue to IRP buffer.
  629. extension->CountOnLastRead |=
  630. SerialGetCharsFromIntBuffer(extension);
  631. if (extension->NumberNeededForRead == 0) // IRP complete!
  632. {
  633. extension->CurrentReadIrp->IoStatus.Information =
  634. IoGetCurrentIrpStackLocation(
  635. extension->CurrentReadIrp
  636. )->Parameters.Read.Length;
  637. extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
  638. // We're finished with this read
  639. extension->ReadPending = FALSE;
  640. KeInsertQueueDpc( &extension->CompleteReadDpc, NULL, NULL );
  641. } // irp complete
  642. } // more data to read out of input queue
  643. } // end of Read completion
  644. wrote_some_data = 0;
  645. //-------- do BREAK handling
  646. if ( extension->TXHolding & SERIAL_TX_BREAK )
  647. {
  648. // Check if we need to start the break
  649. if(extension->DevStatus & COM_REQUEST_BREAK)
  650. {
  651. // Make sure Transmitter is empty before slamming BREAK
  652. // Check the bit twice in case of time between buf and txshr load
  653. if( (sGetChanStatusLo(extension->ChP) & TXSHRMT) &&
  654. (sGetChanStatusLo(extension->ChP) & TXSHRMT) )
  655. {
  656. sSendBreak(extension->ChP);
  657. extension->DevStatus &= ~COM_REQUEST_BREAK;
  658. }
  659. }
  660. }
  661. else if (extension->WriteBelongsToIsr == 1) // its ours to process
  662. {
  663. //----- Not holding due to BREAK so try to enqueue Tx data
  664. if (extension->WriteLength)
  665. {
  666. wrote_some_data = 1;
  667. if (extension->Option & OPTION_RS485_SOFTWARE_TOGGLE)
  668. {
  669. if ((extension->DTRRTSStatus & SERIAL_RTS_STATE) == 0)
  670. {
  671. sSetRTS(extension->ChP);
  672. extension->DTRRTSStatus |= SERIAL_RTS_STATE;
  673. }
  674. }
  675. extension->ISR_Flags |= TX_NOT_EMPTY; // use to detect fifo empty
  676. // Send it all ,WriteTxBlk will chk fifo
  677. wCount = sWriteTxBlk( extension->ChP,
  678. (PUCHAR)((extension->CurrentWriteIrp)->AssociatedIrp.SystemBuffer)+
  679. (extension->CurrentWriteIrp)->IoStatus.Information,
  680. extension->WriteLength);
  681. extension->OurStats.TransmittedCount += wCount;
  682. extension->WriteLength -= wCount;
  683. (extension->CurrentWriteIrp)->IoStatus.Information += wCount;
  684. if(!extension->WriteLength)//No more to write Close the DPC call
  685. {
  686. if (!extension->port_config->WaitOnTx)
  687. {
  688. extension->WriteBelongsToIsr = 2;
  689. KeInsertQueueDpc( &extension->CompleteWriteDpc, NULL, NULL );
  690. }
  691. }
  692. } // if (extension->WriteLength) // data to write
  693. } // end if !TXholding and WriteBelongsToIsr == 1
  694. if (!wrote_some_data)
  695. {
  696. if (extension->ISR_Flags & TX_NOT_EMPTY)
  697. {
  698. //----- check for EV_TXEMPTY condition
  699. // and no pending writes
  700. // check to see if tx-fifo truely empty
  701. // need to check twice due to hardware quirks
  702. if ( (sGetTxCnt(extension->ChP) == 0) &&
  703. (sGetChanStatusLo(extension->ChP) & TXSHRMT) )
  704. {
  705. if (IsListEmpty(&extension->WriteQueue))
  706. {
  707. extension->ISR_Flags &= ~TX_NOT_EMPTY;
  708. // do we have an ev_txempty thing to take care of?
  709. if (extension->IrpMaskLocation &&
  710. (extension->IsrWaitMask & SERIAL_EV_TXEMPTY) )
  711. {
  712. // app has wait irp pending
  713. if (extension->CurrentWaitIrp)
  714. {
  715. extension->HistoryMask |= SERIAL_EV_TXEMPTY;
  716. }
  717. }
  718. if (extension->Option & OPTION_RS485_SOFTWARE_TOGGLE)
  719. {
  720. if ((extension->DTRRTSStatus & SERIAL_RTS_STATE) != 0)
  721. {
  722. extension->DTRRTSStatus &= ~SERIAL_RTS_STATE;
  723. sClrRTS(extension->ChP);
  724. }
  725. }
  726. } // no more write irps queued up
  727. // see if we need to finish waitontx write irp
  728. if (extension->port_config->WaitOnTx)
  729. {
  730. if (extension->WriteBelongsToIsr == 1) // its ours to process
  731. {
  732. extension->WriteBelongsToIsr = 2;
  733. KeInsertQueueDpc( &extension->CompleteWriteDpc, NULL, NULL );
  734. }
  735. }
  736. } // tx fifo went empty
  737. } // TX_NOT_EMPTY
  738. } // !wrote_some_data
  739. // Tell the app about any Wait events that have occurred if needed
  740. if (extension->WaitIsISRs && extension->HistoryMask)
  741. {
  742. #ifdef COMMENT_OUT
  743. if (Driver.TraceOptions & 8) // trace output data
  744. {
  745. char str[20];
  746. Sprintf(str, "ISR Event:%xH\n", extension->HistoryMask);
  747. q_put(&Driver.DebugQ, (BYTE *) str, strlen(str));
  748. }
  749. #endif
  750. *extension->IrpMaskLocation = extension->HistoryMask;
  751. // Done with these
  752. extension->WaitIsISRs = 0;
  753. //extension->IrpMaskLocation = NULL;
  754. extension->HistoryMask = 0;
  755. extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  756. KeInsertQueueDpc(&extension->CommWaitDpc,NULL,NULL);
  757. }
  758. }
  759. /*-----------------------------------------------------------------------------
  760. Function : RocketRead
  761. Purpose: Moves data from Rocket's Rx FIFO to RxIn of dev's extension
  762. NOTES: The error checking assumes that if no replacement is required,
  763. the errored chars are ignored.
  764. The RXMATCH feature is used for EventChar detection.
  765. Return: None
  766. |-----------------------------------------------------------------------------*/
  767. static void RocketRead(PSERIAL_DEVICE_EXTENSION extension)
  768. {
  769. int WrapCount; // Number of bytes in wrap (2 stage copy)
  770. int RxFree;
  771. int sCount;
  772. unsigned int ChanStatus;
  773. unsigned int StatusWord;
  774. int OriginalCount; // Used to determine if Rx event occurred
  775. // Save off the original Rx buff ptr. Test later for Rx event
  776. OriginalCount = extension->RxQ.QPut;
  777. // Get count before reading status
  778. // NOTE: Should always have a count if we entered this code
  779. sCount = sGetRxCnt(extension->ChP);
  780. if (sCount == 0)
  781. {
  782. //GTrace("Error, RXF_TRIG lied");
  783. return;
  784. }
  785. // Have count, now get status
  786. ChanStatus = sGetChanStatus(extension->ChP) &
  787. (STATMODE | RXFOVERFL | RXBREAK |
  788. RXFRAME | RX2MATCH | RX1MATCH | RXPARITY);
  789. // Make sure we're in statmode if errors are pending in the FIFO
  790. if (ChanStatus)
  791. {
  792. if (ChanStatus & RX1MATCH) // Must signal Rx Match immediately
  793. {
  794. if (extension->IsrWaitMask & SERIAL_EV_RXFLAG)
  795. extension->HistoryMask |= SERIAL_EV_RXFLAG;
  796. ChanStatus &= ~RX1MATCH;
  797. }
  798. if (ChanStatus)
  799. sEnRxStatusMode(extension->ChP);
  800. }
  801. // See how much space we have in RxBuf (host side buffer)
  802. RxFree = q_room(&extension->RxQ);
  803. if (RxFree > 20) // plenty of space in RX queue
  804. {
  805. RxFree -= 20; // leave some space for virtual insertion stuff
  806. extension->ReadByIsr++; // Increment statistics Read flag
  807. //------ Adjust count to maximum we can put in RxIn buffer
  808. if (RxFree < sCount)
  809. sCount = RxFree;
  810. }
  811. else // no more room in server buffer input queue
  812. {
  813. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_RX80FULL);
  814. // No room in host side buffer, only do the software flow ctl check
  815. // check for overflow
  816. if (ChanStatus & RXFOVERFL)
  817. {
  818. // extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
  819. extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
  820. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_ERR);
  821. ++extension->OurStats.BufferOverrunErrorCount;
  822. }
  823. goto FlowControlCheck;
  824. }
  825. //--------------------------- Attempt to read any pending data
  826. // ChanStatus indicates any pending errors or matches
  827. if (ChanStatus)
  828. {
  829. // Loop on reading Rocket FIFO
  830. // sCount represents Rocket data, RxFree represents host buffer
  831. while(sCount)
  832. {
  833. // Get stat byte and data
  834. StatusWord = sReadRxWord( sGetTxRxDataIO(extension->ChP));
  835. sCount--;
  836. ++extension->OurStats.ReceivedCount; // keep status
  837. switch(StatusWord & (STMPARITYH | STMFRAMEH | STMBREAKH) )
  838. {
  839. case STMPARITYH:
  840. {
  841. if (extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)
  842. {
  843. q_put_one(&extension->RxQ,
  844. extension->SpecialChars.ErrorChar);
  845. }
  846. else // queue the character received(add 12-03-96)
  847. {
  848. q_put_one(&extension->RxQ, (UCHAR)StatusWord);
  849. }
  850. extension->ErrorWord |= SERIAL_ERROR_PARITY;
  851. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_ERR);
  852. ++extension->OurStats.ParityErrorCount;
  853. break;
  854. }
  855. case STMFRAMEH:
  856. {
  857. if (extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)
  858. {
  859. q_put_one(&extension->RxQ,
  860. extension->SpecialChars.ErrorChar);
  861. }
  862. else // queue the character received(add 12-03-96)
  863. {
  864. q_put_one(&extension->RxQ, (UCHAR)StatusWord);
  865. }
  866. extension->ErrorWord |= SERIAL_ERROR_FRAMING;
  867. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_ERR);
  868. ++extension->OurStats.FrameErrorCount;
  869. break;
  870. }
  871. // PARITY can be set along with BREAK, BREAK overrides PARITY
  872. case ( STMBREAKH | STMPARITYH ):
  873. case STMBREAKH:
  874. {
  875. if (extension->HandFlow.FlowReplace & SERIAL_BREAK_CHAR)
  876. {
  877. q_put_one(&extension->RxQ,
  878. extension->SpecialChars.BreakChar);
  879. }
  880. extension->ErrorWord |= SERIAL_ERROR_BREAK;
  881. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_BREAK);
  882. break;
  883. }
  884. default:
  885. {
  886. if (extension->TXHolding & ST_XOFF_FAKE)
  887. {
  888. if ((UCHAR)StatusWord == extension->SpecialChars.XonChar)
  889. {
  890. extension->TXHolding &= ~ST_XOFF_FAKE;
  891. extension->TXHolding &= ~SERIAL_TX_XOFF;
  892. sEnTransmit(extension->ChP); // Start up the transmitter
  893. sDisRxCompare2(extension->ChP); // turn off match
  894. sEnTxSoftFlowCtl(extension->ChP); // turn on Tx software flow control
  895. // override an actual XOFF from remote
  896. sClrTxXOFF(extension->ChP);
  897. }
  898. else
  899. { q_put_one(&extension->RxQ, (UCHAR)StatusWord); } // queue normal char
  900. }
  901. else
  902. { q_put_one(&extension->RxQ, (UCHAR)StatusWord); } // queue normal char
  903. if (extension->escapechar != 0)
  904. {
  905. if ((UCHAR)StatusWord == extension->escapechar)
  906. {
  907. // Modem status escape convention for virtual port
  908. // support, escape the escape char.
  909. { q_put_one(&extension->RxQ, SERIAL_LSRMST_ESCAPE); }
  910. }
  911. }
  912. }
  913. } // end switch
  914. //------ check for near overflow condition due to insertions
  915. if (q_room(&extension->RxQ) < 10)
  916. sCount = 0; // stop reading hardware!
  917. } // end while sCount
  918. //--- if rx-data all read down, turn off slow status mode
  919. if(!(sGetChanStatusLo(extension->ChP) & RDA))
  920. {
  921. sDisRxStatusMode(extension->ChP);
  922. }
  923. // Overflow is reported immediately, statmode can't do it properly
  924. if (ChanStatus & RXFOVERFL)
  925. { extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
  926. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_ERR);
  927. ++extension->OurStats.SerialOverrunErrorCount;
  928. }
  929. } // end if ChanStatus
  930. else
  931. {
  932. //--------------------------------------------------------
  933. // No pending errors or matches in the FIFO, read the data normally (fast)
  934. // Check for wrap condition first
  935. WrapCount = q_room_put_till_wrap(&extension->RxQ);
  936. if (sCount > WrapCount) // then 2 moves required
  937. {
  938. // This will require a wrap
  939. sReadRxBlk(extension->ChP,
  940. extension->RxQ.QBase + extension->RxQ.QPut,
  941. WrapCount);
  942. // Do the second copy...
  943. sReadRxBlk(extension->ChP,
  944. extension->RxQ.QBase,
  945. sCount-WrapCount);
  946. #ifdef RING_FAKE
  947. if (extension->port_config->RingEmulate)
  948. {
  949. if ((extension->ModemStatus & SERIAL_DCD_STATE) == 0) // if CD off
  950. {
  951. ring_check(extension, extension->RxQ.QBase + extension->RxQ.QPut,
  952. WrapCount);
  953. ring_check(extension, extension->RxQ.QBase,
  954. sCount-WrapCount);
  955. }
  956. }
  957. #endif
  958. }
  959. else // only one move required
  960. {
  961. // no queue wrap required
  962. sReadRxBlk(extension->ChP,
  963. extension->RxQ.QBase + extension->RxQ.QPut,
  964. sCount);
  965. #ifdef RING_FAKE
  966. if (extension->port_config->RingEmulate)
  967. {
  968. if ((extension->ModemStatus & SERIAL_DCD_STATE) == 0) // if CD off
  969. {
  970. ring_check(extension, extension->RxQ.QBase + extension->RxQ.QPut,
  971. sCount);
  972. }
  973. }
  974. #endif
  975. }
  976. extension->RxQ.QPut = (extension->RxQ.QPut + sCount) % extension->RxQ.QSize;
  977. extension->OurStats.ReceivedCount += sCount;
  978. } // end fast read
  979. FlowControlCheck: ;
  980. ///////////////////////////////////////
  981. // Software and DTR input flow control checking
  982. if( (extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) ||
  983. (extension->HandFlow.ControlHandShake & SERIAL_DTR_HANDSHAKE )
  984. )
  985. {
  986. // check for flow control conditions
  987. if (extension->DevStatus & COM_RXFLOW_ON)
  988. {
  989. // do we need to stop Rx?
  990. if(sGetRxCnt(extension->ChP) >= RX_HIWATER)
  991. {
  992. if(extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE)
  993. {
  994. // send XOFF
  995. sWriteTxPrioByte(extension->ChP,
  996. extension->SpecialChars.XoffChar);
  997. extension->DevStatus &= ~COM_RXFLOW_ON;
  998. extension->RXHolding |= SERIAL_RX_XOFF;
  999. }
  1000. if(extension->HandFlow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
  1001. {
  1002. // drop DTR
  1003. sClrDTR(extension->ChP);
  1004. extension->DTRRTSStatus &= ~SERIAL_DTR_STATE;
  1005. extension->DevStatus &= ~COM_RXFLOW_ON;
  1006. extension->RXHolding |= SERIAL_RX_DSR;
  1007. }
  1008. }
  1009. }
  1010. else // Rx flow is stopped
  1011. {
  1012. // can we resume Rx?
  1013. if(sGetRxCnt(extension->ChP) <= RX_LOWATER)
  1014. {
  1015. if(extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE)
  1016. {
  1017. // send XON
  1018. sWriteTxPrioByte(extension->ChP,
  1019. extension->SpecialChars.XonChar);
  1020. extension->DevStatus |= COM_RXFLOW_ON;
  1021. extension->RXHolding &= ~SERIAL_RX_XOFF;
  1022. }
  1023. if(extension->HandFlow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
  1024. {
  1025. // raise DTR
  1026. sSetDTR(extension->ChP);
  1027. extension->DTRRTSStatus |= SERIAL_DTR_STATE;
  1028. extension->DevStatus |= COM_RXFLOW_ON;
  1029. extension->RXHolding &= ~SERIAL_RX_DSR;
  1030. }
  1031. }
  1032. }
  1033. } // end of software and DTR input flow control check
  1034. // Should we mark a Rx event?
  1035. if ( OriginalCount != extension->RxQ.QPut )
  1036. extension->HistoryMask|=(extension->IsrWaitMask & SERIAL_EV_RXCHAR);
  1037. }
  1038. #endif
  1039. #ifdef RING_FAKE
  1040. /*------------------------------------------------------------------------------
  1041. ring_check - scan the rx data for a modem "RING<CR>" or "2<CR>" string.
  1042. If found, trigger a emulated hardware RING signal.
  1043. |------------------------------------------------------------------------------*/
  1044. static void ring_check(PSERIAL_DEVICE_EXTENSION extension,
  1045. BYTE *data,
  1046. int len)
  1047. {
  1048. int i;
  1049. for (i=0; i<len; i++)
  1050. {
  1051. switch (data[i])
  1052. {
  1053. case '2':
  1054. if (len <= 2)
  1055. extension->ring_char = '2';
  1056. else extension->ring_char = 0;
  1057. break;
  1058. case 'R':
  1059. extension->ring_char = 'R';
  1060. break;
  1061. case 'I':
  1062. if (extension->ring_char == 'R')
  1063. extension->ring_char = 'I';
  1064. else extension->ring_char = 0;
  1065. break;
  1066. case 'N':
  1067. if (extension->ring_char == 'I')
  1068. extension->ring_char = 'N';
  1069. else extension->ring_char = 0;
  1070. break;
  1071. case 'G':
  1072. if (extension->ring_char == 'N')
  1073. extension->ring_char = 'G';
  1074. else extension->ring_char = 0;
  1075. break;
  1076. case 0xd:
  1077. if ( (extension->ring_char == 'G') ||
  1078. ((extension->ring_char == '2') && (len <= 2)) )
  1079. {
  1080. //MyKdPrint(D_Init,("RING!\n"))
  1081. // OK, look s like the data stream says a "RING" took place.
  1082. // so setup a timer which will cause a hardware RING to be made
  1083. // set to .5 sec for 10ms scanrate, .05sec for 1ms scanrate
  1084. extension->ring_timer = 50;
  1085. }
  1086. extension->ring_char = 0;
  1087. break;
  1088. default:
  1089. extension->ring_char = 0;
  1090. break;
  1091. }
  1092. }
  1093. }
  1094. #endif
  1095. /*-----------------------------------------------------------------------------
  1096. RocketRefresh - This runs every 255 ticks or so, in order to perform
  1097. background activities. We will go read the modem status, and update
  1098. the ModemCtl field. The monitor program reads this variable, and we
  1099. don't want to waste time reading it too often, so we just update it
  1100. occasionally here.
  1101. |-----------------------------------------------------------------------------*/
  1102. static void RocketRefresh(void)
  1103. {
  1104. PSERIAL_DEVICE_EXTENSION extension;
  1105. PSERIAL_DEVICE_EXTENSION board_ext;
  1106. #ifdef S_RK
  1107. board_ext = Driver.board_ext;
  1108. while (board_ext)
  1109. {
  1110. if ((!board_ext->FdoStarted) || (!board_ext->config->HardwareStarted))
  1111. {
  1112. board_ext = board_ext->board_ext;
  1113. continue;
  1114. }
  1115. extension = board_ext->port_ext;
  1116. while (extension)
  1117. {
  1118. // Read and update the modem status in the extension
  1119. SetExtensionModemStatus(extension);
  1120. extension = extension->port_ext; // next in chain
  1121. } // while port extension
  1122. board_ext = board_ext->board_ext;
  1123. } // while board extension
  1124. #endif
  1125. debug_poll(); // handle turn off of debug on inactivity timeout
  1126. }
  1127. #ifdef S_VS
  1128. /*-----------------------------------------------------------------------------
  1129. Function : VSRead
  1130. Purpose: Moves data from VS's Rx FIFO to RxIn of dev's extension
  1131. NOTES: The error checking assumes that if no replacement is required,
  1132. the errored chars are ignored.
  1133. The RXMATCH feature is used for EventChar detection.
  1134. Return: None
  1135. |-----------------------------------------------------------------------------*/
  1136. static void VSRead(PSERIAL_DEVICE_EXTENSION extension)
  1137. {
  1138. int WrapCount; // Number of bytes in wrap (2 stage copy)
  1139. int RxFree;
  1140. int sCount;
  1141. LONG OriginalCount; // Used to determine if Rx event occurred
  1142. // Save off the original Rx buff ptr. Test later for Rx event
  1143. OriginalCount = extension->RxQ.QPut;
  1144. // Get count before reading status
  1145. // NOTE: Should always have a count if we entered this code
  1146. sCount=PortGetRxCnt(extension->Port);
  1147. if (sCount == 0)
  1148. {
  1149. //MyTrace("Error, RXF_TRIG lied");
  1150. return;
  1151. }
  1152. // See how much space we have in RxBuf (host side buffer)
  1153. RxFree = q_room(&extension->RxQ);
  1154. // if no space in RxBuf, don't read from RocketPort
  1155. if (RxFree > 20) // plenty of space in RX queue
  1156. {
  1157. RxFree -= 20; // leave some space for virtual insertion stuff
  1158. extension->ReadByIsr++; // Increment statistics Read flag
  1159. //------ Adjust count to maximum we can put in RxIn buffer
  1160. if (RxFree < sCount)
  1161. sCount = RxFree;
  1162. }
  1163. else // no more room in server buffer input queue
  1164. {
  1165. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_RX80FULL);
  1166. // No room in host side buffer, only do the software flow ctl check
  1167. // check for overflow
  1168. if (extension->Port->esr_reg & ESR_OVERFLOW_ERROR)
  1169. {
  1170. // extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
  1171. extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
  1172. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_ERR);
  1173. extension->Port->esr_reg = 0; // reset to zero on read
  1174. ++extension->OurStats.BufferOverrunErrorCount;
  1175. }
  1176. goto FlowControlCheck;
  1177. }
  1178. //------ report any rx error conditions.
  1179. if (extension->Port->esr_reg)
  1180. {
  1181. if (extension->Port->esr_reg & ESR_OVERFLOW_ERROR)
  1182. {
  1183. extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
  1184. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_ERR);
  1185. ++extension->OurStats.SerialOverrunErrorCount;
  1186. }
  1187. else if (extension->Port->esr_reg & ESR_BREAK_ERROR)
  1188. {
  1189. extension->ErrorWord |= SERIAL_ERROR_BREAK;
  1190. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_BREAK);
  1191. }
  1192. else if (extension->Port->esr_reg & ESR_FRAME_ERROR)
  1193. {
  1194. extension->ErrorWord |= SERIAL_ERROR_FRAMING;
  1195. extension->HistoryMask |= (extension->IsrWaitMask & SERIAL_EV_ERR);
  1196. ++extension->OurStats.FrameErrorCount;
  1197. }
  1198. else if (extension->Port->esr_reg & ESR_PARITY_ERROR)
  1199. {
  1200. extension->ErrorWord |= SERIAL_ERROR_PARITY;
  1201. extension->HistoryMask |= (extension->IsrWaitMask&SERIAL_EV_ERR);
  1202. ++extension->OurStats.ParityErrorCount;
  1203. }
  1204. extension->Port->esr_reg = 0; // reset to zero on read
  1205. }
  1206. //--------------------------------------------------------
  1207. // No pending errors or matches in the FIFO, read the data normally (fast)
  1208. // Check for wrap condition first
  1209. WrapCount = q_room_put_till_wrap(&extension->RxQ);
  1210. if (sCount > WrapCount) // then 2 moves required
  1211. {
  1212. q_get(&extension->Port->QIn,
  1213. extension->RxQ.QBase + extension->RxQ.QPut,
  1214. WrapCount);
  1215. // Do the second copy...
  1216. q_get(&extension->Port->QIn,
  1217. extension->RxQ.QBase,
  1218. sCount-WrapCount);
  1219. if (extension->IsrWaitMask & SERIAL_EV_RXFLAG)
  1220. {
  1221. if (search_match(extension->RxQ.QBase + extension->RxQ.QPut,
  1222. WrapCount,extension->SpecialChars.EventChar))
  1223. extension->HistoryMask |= SERIAL_EV_RXFLAG;
  1224. if (search_match(extension->RxQ.QBase,
  1225. sCount-WrapCount,extension->SpecialChars.EventChar))
  1226. extension->HistoryMask |= SERIAL_EV_RXFLAG;
  1227. }
  1228. #ifdef RING_FAKE
  1229. if (extension->port_config->RingEmulate)
  1230. {
  1231. if ((extension->ModemStatus & SERIAL_DCD_STATE) == 0) // if CD off
  1232. {
  1233. ring_check(extension, extension->RxQ.QBase + extension->RxQ.QPut,
  1234. WrapCount);
  1235. ring_check(extension, extension->RxQ.QBase,
  1236. sCount-WrapCount);
  1237. }
  1238. }
  1239. #endif
  1240. }
  1241. else // only one move required
  1242. {
  1243. q_get(&extension->Port->QIn,
  1244. extension->RxQ.QBase + extension->RxQ.QPut,
  1245. sCount);
  1246. if (extension->IsrWaitMask & SERIAL_EV_RXFLAG)
  1247. {
  1248. if (search_match(extension->RxQ.QBase + extension->RxQ.QPut,
  1249. sCount,extension->SpecialChars.EventChar))
  1250. extension->HistoryMask |= SERIAL_EV_RXFLAG;
  1251. }
  1252. #ifdef RING_FAKE
  1253. if (extension->port_config->RingEmulate)
  1254. {
  1255. if ((extension->ModemStatus & SERIAL_DCD_STATE) == 0) // if CD off
  1256. {
  1257. ring_check(extension, extension->RxQ.QBase + extension->RxQ.QPut,
  1258. sCount);
  1259. }
  1260. }
  1261. #endif
  1262. }
  1263. extension->RxQ.QPut = (extension->RxQ.QPut + sCount) % extension->RxQ.QSize;
  1264. extension->OurStats.ReceivedCount += sCount;
  1265. extension->Port->Status |= S_UPDATE_ROOM;
  1266. #ifdef NEW_Q
  1267. extension->Port->nGetLocal += sCount;
  1268. #endif
  1269. FlowControlCheck: ;
  1270. //----- Should we mark a Rx event?
  1271. if ( OriginalCount != extension->RxQ.QPut )
  1272. extension->HistoryMask|=(extension->IsrWaitMask & SERIAL_EV_RXCHAR);
  1273. }
  1274. #ifndef USE_MEMCHR_SCAN
  1275. /*------------------------------------------------------------------
  1276. search_match -
  1277. |------------------------------------------------------------------*/
  1278. static int search_match(BYTE *buf, int count, BYTE eventchar)
  1279. {
  1280. int i;
  1281. for (i=0; i<count; i++)
  1282. {
  1283. if (buf[i] == eventchar)
  1284. return 1; // found
  1285. }
  1286. return 0; // not found
  1287. }
  1288. #endif
  1289. #endif