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.

1031 lines
27 KiB

  1. /*
  2. ************************************************************************
  3. *
  4. * COMM.c
  5. *
  6. * Portions Copyright (C) 1996-2001 National Semiconductor Corp.
  7. * All rights reserved.
  8. * Copyright (C) 1996-2001 Microsoft Corporation. All Rights Reserved.
  9. *
  10. *
  11. *
  12. *************************************************************************
  13. */
  14. #include "nsc.h"
  15. #define MEDIA_BUSY_THRESHOLD (16)
  16. #define SYNC_SET_COMM_PORT(_intobj,_port,_index,_value) SyncWriteBankReg(_intobj,_port,0,_index,_value);
  17. #define SYNC_GET_COMM_PORT(_intobj,_port,_index) SyncReadBankReg(_intobj,_port,0,_index)
  18. /*
  19. *************************************************************************
  20. * SetCOMInterrupts
  21. *************************************************************************
  22. */
  23. VOID SetCOMInterrupts(IrDevice *thisDev, BOOLEAN enable)
  24. {
  25. UCHAR newMask;
  26. if (enable){
  27. if (thisDev->portInfo.SirWritePending){
  28. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  29. newMask = thisDev->FirIntMask;
  30. }
  31. else {
  32. newMask = XMIT_MODE_INTS_ENABLE;
  33. }
  34. }
  35. else {
  36. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  37. newMask = thisDev->FirIntMask;
  38. }
  39. else {
  40. newMask = RCV_MODE_INTS_ENABLE;
  41. }
  42. }
  43. }
  44. else {
  45. newMask = ALL_INTS_DISABLE;
  46. }
  47. SetCOMPort(thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, newMask);
  48. }
  49. VOID
  50. SyncSetInterruptMask(
  51. IrDevice *thisDev,
  52. BOOLEAN enable
  53. )
  54. {
  55. UCHAR newMask;
  56. if (enable){
  57. if (thisDev->portInfo.SirWritePending){
  58. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  59. newMask = thisDev->FirIntMask;
  60. }
  61. else {
  62. newMask = XMIT_MODE_INTS_ENABLE;
  63. }
  64. }
  65. else {
  66. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  67. newMask = thisDev->FirIntMask;
  68. }
  69. else {
  70. newMask = RCV_MODE_INTS_ENABLE;
  71. }
  72. }
  73. }
  74. else {
  75. newMask = ALL_INTS_DISABLE;
  76. }
  77. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, newMask);
  78. }
  79. /*
  80. *************************************************************************
  81. * DoOpen
  82. *************************************************************************
  83. *
  84. * Open COMM port
  85. *
  86. */
  87. BOOLEAN DoOpen(IrDevice *thisDev)
  88. {
  89. BOOLEAN result;
  90. DBGOUT(("DoOpen(%d)", thisDev->portInfo.ioBase));
  91. /*
  92. * This buffer gets swapped with the rcvBuffer data pointer
  93. * and must be the same size.
  94. */
  95. thisDev->portInfo.readBuf = LIST_ENTRY_TO_RCV_BUF(MyMemAlloc(RCV_BUFFER_SIZE, TRUE)); // Was FALSE -SWA
  96. if (!thisDev->portInfo.readBuf){
  97. return FALSE;
  98. }
  99. /*
  100. * The write buffer is also used as a DMA buffer.
  101. */
  102. thisDev->portInfo.writeBuf = MyMemAlloc(MAX_IRDA_DATA_SIZE * 8, TRUE);
  103. if (!thisDev->portInfo.writeBuf){
  104. return FALSE;
  105. }
  106. /*
  107. * Initialize send/receive FSMs before OpenCOM(), which enables rcv interrupts.
  108. */
  109. thisDev->portInfo.rcvState = STATE_INIT;
  110. thisDev->portInfo.SirWritePending = FALSE;
  111. //
  112. // the sir recieve will start automatically
  113. //
  114. thisDev->TransmitIsIdle= TRUE;
  115. NdisInitializeEvent(&thisDev->ReceiveStopped);
  116. NdisResetEvent(&thisDev->ReceiveStopped);
  117. NdisInitializeEvent(&thisDev->SendStoppedOnHalt);
  118. NdisResetEvent(&thisDev->SendStoppedOnHalt);
  119. result = OpenCOM(thisDev);
  120. DBGOUT(("DoOpen %s", (CHAR *)(result ? "succeeded" : "failed")));
  121. return result;
  122. }
  123. /*
  124. *************************************************************************
  125. * DoClose
  126. *************************************************************************
  127. *
  128. * Close COMM port
  129. *
  130. */
  131. VOID DoClose(IrDevice *thisDev)
  132. {
  133. DBGOUT(("DoClose(COM%d)", thisDev->portInfo.ioBase));
  134. if (thisDev->portInfo.readBuf){
  135. MyMemFree(RCV_BUF_TO_LIST_ENTRY(thisDev->portInfo.readBuf),
  136. RCV_BUFFER_SIZE, TRUE); // Was FALSE -SWA
  137. thisDev->portInfo.readBuf = NULL;
  138. }
  139. if (thisDev->portInfo.writeBuf){
  140. MyMemFree(thisDev->portInfo.writeBuf, MAX_IRDA_DATA_SIZE * 8, TRUE);
  141. thisDev->portInfo.writeBuf = NULL;
  142. }
  143. #if 0
  144. CloseCOM(thisDev);
  145. #endif
  146. }
  147. typedef struct _SYNC_SET_SPEED {
  148. PUCHAR PortBase;
  149. UINT BitsPerSecond;
  150. } SYNC_SET_SPEED, *PSYNC_SET_SPEED;
  151. VOID
  152. SyncSetUARTSpeed(
  153. PVOID Context
  154. )
  155. {
  156. PSYNC_SET_SPEED SyncContext=(PSYNC_SET_SPEED)Context;
  157. NdisRawWritePortUchar(SyncContext->PortBase+LINE_CONTROL_REG_OFFSET,0x83);
  158. NdisRawWritePortUchar(SyncContext->PortBase+XFER_REG_OFFSET, (UCHAR)(115200/SyncContext->BitsPerSecond));
  159. NdisRawWritePortUchar(SyncContext->PortBase+INT_ENABLE_REG_OFFSET, (UCHAR)((115200/SyncContext->BitsPerSecond)>>8));
  160. NdisRawWritePortUchar(SyncContext->PortBase+LINE_CONTROL_REG_OFFSET, 0x03);
  161. return;
  162. }
  163. /*
  164. *************************************************************************
  165. * SetUARTSpeed
  166. *************************************************************************
  167. *
  168. *
  169. */
  170. VOID SetUARTSpeed(IrDevice *thisDev, UINT bitsPerSec)
  171. {
  172. if (bitsPerSec <= MAX_SIR_SPEED){
  173. /*
  174. * Set speed in the standard UART divisor latch
  175. *
  176. * 1. Set up to access the divisor latch.
  177. *
  178. * 2. In divisor-latch mode:
  179. * the transfer register doubles as the low divisor latch
  180. * the int-enable register doubles as the hi divisor latch
  181. *
  182. * Set the divisor for the given speed.
  183. * The divisor divides the maximum Slow IR speed of 115200 bits/sec.
  184. *
  185. * 3. Take the transfer register out of divisor-latch mode.
  186. *
  187. */
  188. SYNC_SET_SPEED SyncContext;
  189. if (!bitsPerSec){
  190. bitsPerSec = 9600;
  191. }
  192. SyncContext.PortBase=thisDev->portInfo.ioBase;
  193. SyncContext.BitsPerSecond=bitsPerSec;
  194. //
  195. // since we are changeing the port bank, sync with the interrupt
  196. //
  197. NdisMSynchronizeWithInterrupt(
  198. &thisDev->interruptObj,
  199. SyncSetUARTSpeed,
  200. &SyncContext
  201. );
  202. NdisStallExecution(5000);
  203. }
  204. }
  205. /*
  206. *************************************************************************
  207. * SetSpeed
  208. *************************************************************************
  209. *
  210. *
  211. */
  212. BOOLEAN SetSpeed(IrDevice *thisDev)
  213. {
  214. UINT bitsPerSec = thisDev->linkSpeedInfo->bitsPerSec;
  215. BOOLEAN dongleSet, result = TRUE;
  216. // DbgPrint("nsc: setspeed %d\n",bitsPerSec);
  217. DBGOUT((" **** SetSpeed(%xh, %d bps) ***************************", thisDev->portInfo.ioBase, bitsPerSec));
  218. /*
  219. * Disable interrupts while changing speed.
  220. * (This is especially important for the ADAPTEC dongle;
  221. * we may get interrupted while setting command mode
  222. * between writing 0xff and reading 0xc3).
  223. */
  224. SyncSetInterruptMask(thisDev, FALSE);
  225. /*
  226. * First, set the UART's speed to 9600 baud.
  227. * Some of the dongles need to receive their command sequences at this speed.
  228. */
  229. SetUARTSpeed(thisDev, 9600);
  230. dongleSet = NSC_DEMO_SetSpeed(thisDev, thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
  231. //
  232. // debug info.
  233. //
  234. thisDev->portInfo.PacketsReceived_DEBUG = 0;
  235. if (!dongleSet){
  236. DBGERR(("Dongle set-speed failed"));
  237. result = FALSE;
  238. }
  239. /*
  240. * Now set the speed for the COM port
  241. */
  242. SetUARTSpeed(thisDev, bitsPerSec);
  243. thisDev->currentSpeed = bitsPerSec;
  244. DebugSpeed=bitsPerSec;
  245. SyncSetInterruptMask(thisDev, TRUE);
  246. return result;
  247. }
  248. /*
  249. *************************************************************************
  250. * StepSendFSM
  251. *************************************************************************
  252. *
  253. *
  254. * Step the send fsm to send a few more bytes of an IR frame.
  255. * Return TRUE only after an entire frame has been sent.
  256. *
  257. */
  258. BOOLEAN StepSendFSM(IrDevice *thisDev)
  259. {
  260. UINT i, bytesAtATime, startPos = thisDev->portInfo.writeBufPos;
  261. UCHAR lineStatReg;
  262. BOOLEAN result;
  263. UINT maxLoops;
  264. /*
  265. * Ordinarily, we want to fill the send FIFO once per interrupt.
  266. * However, at high speeds the interrupt latency is too slow and
  267. * we need to poll inside the ISR to send the whole packet during
  268. * the first interrupt.
  269. */
  270. if (thisDev->currentSpeed > 115200){
  271. maxLoops = REG_TIMEOUT_LOOPS;
  272. }
  273. else {
  274. maxLoops = REG_POLL_LOOPS;
  275. }
  276. /*
  277. * Write databytes as long as we have them and the UART's FIFO hasn't filled up.
  278. */
  279. while (thisDev->portInfo.writeBufPos < thisDev->portInfo.writeBufLen){
  280. /*
  281. * If this COM port has a FIFO, we'll send up to the FIFO size (16 bytes).
  282. * Otherwise, we can only send one byte at a time.
  283. */
  284. if (thisDev->portInfo.haveFIFO){
  285. bytesAtATime = MIN(FIFO_SIZE, (thisDev->portInfo.writeBufLen - thisDev->portInfo.writeBufPos));
  286. }
  287. else {
  288. bytesAtATime = 1;
  289. }
  290. /*
  291. * Wait for ready-to-send.
  292. */
  293. i = 0;
  294. do {
  295. lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
  296. } while (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY) && (++i < maxLoops));
  297. if (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY)){
  298. break;
  299. }
  300. /*
  301. * Send the next byte or FIFO-volume of bytes.
  302. */
  303. for (i = 0; i < bytesAtATime; i++){
  304. SetCOMPort( thisDev->portInfo.ioBase,
  305. XFER_REG_OFFSET,
  306. thisDev->portInfo.writeBuf[thisDev->portInfo.writeBufPos++]);
  307. }
  308. }
  309. /*
  310. * The return value will indicate whether we've sent the entire frame.
  311. */
  312. if (thisDev->portInfo.writeBufPos >= thisDev->portInfo.writeBufLen){
  313. if (thisDev->setSpeedAfterCurrentSendPacket){
  314. /*
  315. * We'll be changing speeds after this packet,
  316. * so poll until the packet bytes have been completely sent out the FIFO.
  317. * After the 16550 says that it is empty, there may still be one remaining
  318. * byte in the FIFO, so flush it out by sending one more BOF.
  319. */
  320. i = 0;
  321. do {
  322. lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
  323. } while (!(lineStatReg & 0x20) && (++i < REG_TIMEOUT_LOOPS));
  324. SetCOMPort(thisDev->portInfo.ioBase, XFER_REG_OFFSET, (UCHAR)SLOW_IR_EXTRA_BOF);
  325. i = 0;
  326. do {
  327. lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
  328. } while (!(lineStatReg & 0x20) && (++i < REG_TIMEOUT_LOOPS));
  329. }
  330. result = TRUE;
  331. }
  332. else {
  333. result = FALSE;
  334. }
  335. DBGOUT(("StepSendFSM wrote %d bytes (%s):", (UINT)(thisDev->portInfo.writeBufPos-startPos), (PUCHAR)(result ? "DONE" : "not done")));
  336. // DBGPRINTBUF(thisDev->portInfo.writeBuf+startPos, thisDev->portInfo.writeBufPos-startPos);
  337. return result;
  338. }
  339. /*
  340. *************************************************************************
  341. * StepReceiveFSM
  342. *************************************************************************
  343. *
  344. *
  345. * Step the receive fsm to read in a piece of an IR frame;
  346. * strip the BOFs and EOF, and eliminate escape sequences.
  347. * Return TRUE only after an entire frame has been read in.
  348. *
  349. */
  350. BOOLEAN StepReceiveFSM(IrDevice *thisDev)
  351. {
  352. UINT rawBufPos, rawBytesRead;
  353. BOOLEAN result;
  354. UCHAR thisch;
  355. PLIST_ENTRY pListEntry;
  356. DBGOUT(("StepReceiveFSM(%xh)", thisDev->portInfo.ioBase));
  357. /*
  358. * Read in and process groups of incoming bytes from the FIFO.
  359. * NOTE: We have to loop once more after getting MAX_RCV_DATA_SIZE
  360. * bytes so that we can see the 'EOF'; hence <= and not <.
  361. */
  362. while ((thisDev->portInfo.rcvState != STATE_SAW_EOF) && (thisDev->portInfo.readBufPos <= MAX_RCV_DATA_SIZE)){
  363. if (thisDev->portInfo.rcvState == STATE_CLEANUP){
  364. /*
  365. * We returned a complete packet last time, but we had read some
  366. * extra bytes, which we stored into the rawBuf after returning
  367. * the previous complete buffer to the user.
  368. * So instead of calling DoRcvDirect in this first execution of this loop,
  369. * we just use these previously-read bytes.
  370. * (This is typically only 1 or 2 bytes).
  371. */
  372. rawBytesRead = thisDev->portInfo.readBufPos;
  373. thisDev->portInfo.rcvState = STATE_INIT;
  374. thisDev->portInfo.readBufPos = 0;
  375. }
  376. else {
  377. rawBytesRead = DoRcvDirect(thisDev->portInfo.ioBase, thisDev->portInfo.rawBuf, FIFO_SIZE);
  378. if (rawBytesRead == (UINT)-1){
  379. /*
  380. * Receive error occurred. Go back to INIT state.
  381. */
  382. thisDev->portInfo.rcvState = STATE_INIT;
  383. thisDev->portInfo.readBufPos = 0;
  384. continue;
  385. }
  386. else if (rawBytesRead == 0){
  387. /*
  388. * No more receive bytes. Break out.
  389. */
  390. break;
  391. }
  392. }
  393. /*
  394. * Let the receive state machine process this group of characters
  395. * we got from the FIFO.
  396. *
  397. * NOTE: We have to loop once more after getting MAX_RCV_DATA_SIZE
  398. * bytes so that we can see the 'EOF'; hence <= and not <.
  399. */
  400. for (rawBufPos = 0;
  401. ((thisDev->portInfo.rcvState != STATE_SAW_EOF) &&
  402. (rawBufPos < rawBytesRead) &&
  403. (thisDev->portInfo.readBufPos <= MAX_RCV_DATA_SIZE));
  404. rawBufPos++){
  405. thisch = thisDev->portInfo.rawBuf[rawBufPos];
  406. switch (thisDev->portInfo.rcvState){
  407. case STATE_INIT:
  408. switch (thisch){
  409. case SLOW_IR_BOF:
  410. thisDev->portInfo.rcvState = STATE_GOT_BOF;
  411. break;
  412. case SLOW_IR_EOF:
  413. case SLOW_IR_ESC:
  414. default:
  415. /*
  416. * This is meaningless garbage. Scan past it.
  417. */
  418. break;
  419. }
  420. break;
  421. case STATE_GOT_BOF:
  422. switch (thisch){
  423. case SLOW_IR_BOF:
  424. break;
  425. case SLOW_IR_EOF:
  426. /*
  427. * Garbage
  428. */
  429. DBGERR(("EOF in absorbing-BOFs state in DoRcv"));
  430. thisDev->portInfo.rcvState = STATE_INIT;
  431. break;
  432. case SLOW_IR_ESC:
  433. /*
  434. * Start of data.
  435. * Our first data byte happens to be an ESC sequence.
  436. */
  437. thisDev->portInfo.readBufPos = 0;
  438. thisDev->portInfo.rcvState = STATE_ESC_SEQUENCE;
  439. break;
  440. default:
  441. thisDev->portInfo.readBuf[0] = thisch;
  442. thisDev->portInfo.readBufPos = 1;
  443. thisDev->portInfo.rcvState = STATE_ACCEPTING;
  444. break;
  445. }
  446. break;
  447. case STATE_ACCEPTING:
  448. switch (thisch){
  449. case SLOW_IR_BOF:
  450. /*
  451. * Meaningless garbage
  452. */
  453. DBGOUT(("WARNING: BOF during accepting state in DoRcv"));
  454. thisDev->portInfo.rcvState = STATE_INIT;
  455. thisDev->portInfo.readBufPos = 0;
  456. break;
  457. case SLOW_IR_EOF:
  458. if (thisDev->portInfo.readBufPos <
  459. IR_ADDR_SIZE+IR_CONTROL_SIZE+SLOW_IR_FCS_SIZE){
  460. thisDev->portInfo.rcvState = STATE_INIT;
  461. thisDev->portInfo.readBufPos = 0;
  462. }
  463. else {
  464. thisDev->portInfo.rcvState = STATE_SAW_EOF;
  465. }
  466. break;
  467. case SLOW_IR_ESC:
  468. thisDev->portInfo.rcvState = STATE_ESC_SEQUENCE;
  469. break;
  470. default:
  471. thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch;
  472. break;
  473. }
  474. break;
  475. case STATE_ESC_SEQUENCE:
  476. switch (thisch){
  477. case SLOW_IR_EOF:
  478. case SLOW_IR_BOF:
  479. case SLOW_IR_ESC:
  480. /*
  481. * ESC + {EOF|BOF|ESC} is an abort sequence
  482. */
  483. DBGERR(("DoRcv - abort sequence; ABORTING IR PACKET: (got following packet + ESC,%xh)", (UINT)thisch));
  484. DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
  485. thisDev->portInfo.rcvState = STATE_INIT;
  486. thisDev->portInfo.readBufPos = 0;
  487. break;
  488. case SLOW_IR_EOF^SLOW_IR_ESC_COMP:
  489. case SLOW_IR_BOF^SLOW_IR_ESC_COMP:
  490. case SLOW_IR_ESC^SLOW_IR_ESC_COMP:
  491. thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch ^ SLOW_IR_ESC_COMP;
  492. thisDev->portInfo.rcvState = STATE_ACCEPTING;
  493. break;
  494. default:
  495. DBGERR(("Unnecessary escape sequence: (got following packet + ESC,%xh", (UINT)thisch));
  496. DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
  497. thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch ^ SLOW_IR_ESC_COMP;
  498. thisDev->portInfo.rcvState = STATE_ACCEPTING;
  499. break;
  500. }
  501. break;
  502. case STATE_SAW_EOF:
  503. default:
  504. DBGERR(("Illegal state in DoRcv"));
  505. thisDev->portInfo.readBufPos = 0;
  506. thisDev->portInfo.rcvState = STATE_INIT;
  507. return 0;
  508. }
  509. }
  510. }
  511. /*
  512. * Set result and do any post-cleanup.
  513. */
  514. switch (thisDev->portInfo.rcvState){
  515. case STATE_SAW_EOF:
  516. /*
  517. * We've read in the entire packet.
  518. * Queue it and return TRUE.
  519. */
  520. DBGOUT((" *** DoRcv returning with COMPLETE packet, read %d bytes ***", thisDev->portInfo.readBufPos));
  521. if (!IsListEmpty(&thisDev->rcvBufBuf))
  522. {
  523. QueueReceivePacket(thisDev, thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos, FALSE);
  524. // The protocol has our buffer. Get a new one.
  525. #if 1
  526. pListEntry = RemoveHeadList(&thisDev->rcvBufBuf);
  527. thisDev->portInfo.readBuf = LIST_ENTRY_TO_RCV_BUF(pListEntry);
  528. #else
  529. thisDev->portInfo.readBuf = (PVOID)RemoveHeadList(&thisDev->rcvBufBuf);
  530. #endif
  531. }
  532. else
  533. {
  534. // No new buffers were available. We just discard this packet.
  535. DBGERR(("No rcvBufBuf available, discarding packet\n"));
  536. }
  537. result = TRUE;
  538. if (rawBufPos < rawBytesRead){
  539. /*
  540. * This is ugly.
  541. * We have some more unprocessed bytes in the raw buffer.
  542. * Move these to the beginning of the raw buffer
  543. * go to the CLEANUP state, which indicates that these
  544. * bytes be used up during the next call.
  545. * (This is typically only 1 or 2 bytes).
  546. * Note: We can't just leave these in the raw buffer because
  547. * we might be supporting connections to multiple COM ports.
  548. */
  549. memcpy(thisDev->portInfo.rawBuf, &thisDev->portInfo.rawBuf[rawBufPos], rawBytesRead-rawBufPos);
  550. thisDev->portInfo.readBufPos = rawBytesRead-rawBufPos;
  551. thisDev->portInfo.rcvState = STATE_CLEANUP;
  552. }
  553. else {
  554. thisDev->portInfo.rcvState = STATE_INIT;
  555. }
  556. break;
  557. default:
  558. if (thisDev->portInfo.readBufPos > MAX_RCV_DATA_SIZE){
  559. DBGERR(("Overrun in DoRcv : read %d=%xh bytes:", thisDev->portInfo.readBufPos, thisDev->portInfo.readBufPos));
  560. DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
  561. thisDev->portInfo.readBufPos = 0;
  562. thisDev->portInfo.rcvState = STATE_INIT;
  563. }
  564. else {
  565. DBGOUT(("DoRcv returning with partial packet, read %d bytes", thisDev->portInfo.readBufPos));
  566. }
  567. result = FALSE;
  568. break;
  569. }
  570. return result;
  571. }
  572. /*
  573. *************************************************************************
  574. * COM_ISR
  575. *************************************************************************
  576. *
  577. *
  578. */
  579. VOID COM_ISR(IrDevice *thisDev, BOOLEAN *claimingInterrupt, BOOLEAN *requireDeferredCallback)
  580. {
  581. LONG NewCount;
  582. /*
  583. * Get the interrupt status register value.
  584. */
  585. UCHAR intId = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
  586. if (intId & INTID_INTERRUPT_NOT_PENDING){
  587. /*
  588. * This is NOT our interrupt.
  589. * Set carry bit to pass the interrupt to the next driver in the chain.
  590. */
  591. *claimingInterrupt = *requireDeferredCallback = FALSE;
  592. }
  593. else {
  594. /*
  595. * This is our interrupt
  596. */
  597. /*
  598. * In some odd situations, we can get interrupt bits that don't
  599. * get cleared; we don't want to loop forever in this case, so keep a counter.
  600. */
  601. UINT loops = 0;
  602. *claimingInterrupt = TRUE;
  603. *requireDeferredCallback = FALSE;
  604. while (!(intId & INTID_INTERRUPT_NOT_PENDING) && (loops++ < 0x10)){
  605. switch (intId & INTID_INTIDMASK){
  606. case INTID_MODEMSTAT_INT:
  607. DBGOUT(("COM INTERRUPT: modem status int"));
  608. GetCOMPort(thisDev->portInfo.ioBase, MODEM_STAT_REG_OFFSET);
  609. break;
  610. case INTID_XMITREG_INT:
  611. DBGOUT(("COM INTERRUPT: xmit reg empty"));
  612. if (thisDev->portInfo.SirWritePending){
  613. /*
  614. * Try to send a few more bytes
  615. */
  616. if (StepSendFSM(thisDev)){
  617. /*
  618. * There are no more bytes to send;
  619. * reset interrupts for receive mode.
  620. */
  621. thisDev->portInfo.SirWritePending = FALSE;
  622. InterlockedExchange(&thisDev->portInfo.IsrDoneWithPacket,1);
  623. //
  624. // this will unmask the receive interrupt
  625. //
  626. SetCOMInterrupts(thisDev, TRUE);
  627. /*
  628. * Request a DPC so that we can try
  629. * to send other pending write packets.
  630. */
  631. *requireDeferredCallback = TRUE;
  632. }
  633. }
  634. break;
  635. case INTID_RCVDATAREADY_INT:
  636. DBGOUT(("COM INTERRUPT: rcv data available!"));
  637. thisDev->nowReceiving = TRUE;
  638. NewCount=NdisInterlockedIncrement(&thisDev->RxInterrupts);
  639. if (!thisDev->mediaBusy && (NewCount > MEDIA_BUSY_THRESHOLD)){
  640. thisDev->mediaBusy = TRUE;
  641. thisDev->haveIndicatedMediaBusy = FALSE;
  642. *requireDeferredCallback = TRUE;
  643. }
  644. if (StepReceiveFSM(thisDev)){
  645. /*
  646. * The receive engine has accumulated an entire frame.
  647. * Request a deferred callback so we can deliver the frame
  648. * when not in interrupt context.
  649. */
  650. *requireDeferredCallback = TRUE;
  651. thisDev->nowReceiving = FALSE;
  652. }
  653. break;
  654. case INTID_RCVLINESTAT_INT:
  655. DBGOUT(("COM INTERRUPT: rcv line stat int!"));
  656. break;
  657. }
  658. /*
  659. * After we service each interrupt condition, we read the line status register.
  660. * This clears the current interrupt, and a new interrupt may then appear in
  661. * the interrupt-id register.
  662. */
  663. GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
  664. intId = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
  665. }
  666. }
  667. }
  668. /*
  669. *************************************************************************
  670. * OpenCOM
  671. *************************************************************************
  672. *
  673. * Initialize UART registers
  674. *
  675. */
  676. BOOLEAN OpenCOM(IrDevice *thisDev)
  677. {
  678. BOOLEAN dongleInit;
  679. UCHAR intIdReg;
  680. DBGOUT(("-> OpenCOM"));
  681. //
  682. // Make sure bank zero is selected
  683. //
  684. NdisRawWritePortUchar(thisDev->portInfo.ioBase+LCR_BSR_OFFSET, 03);
  685. /*
  686. * Disable all COM interrupts while setting up.
  687. */
  688. SyncSetInterruptMask(thisDev, FALSE);
  689. /*
  690. * Set request-to-send and clear data-terminal-ready.
  691. * Note: ** Bit 3 must be set to enable interrupts.
  692. */
  693. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, MODEM_CONTROL_REG_OFFSET, 0x0A);
  694. /*
  695. * Set dongle- or part-specific info to default
  696. */
  697. thisDev->portInfo.hwCaps.supportedSpeedsMask = ALL_SLOW_IRDA_SPEEDS;
  698. thisDev->portInfo.hwCaps.turnAroundTime_usec = DEFAULT_TURNAROUND_usec;
  699. thisDev->portInfo.hwCaps.extraBOFsRequired = 0;
  700. /*
  701. * Set the COM port speed to the default 9600 baud.
  702. * Some dongles can only receive cmd sequences at this speed.
  703. */
  704. SetUARTSpeed(thisDev, 9600);
  705. dongleInit = NSC_DEMO_Init( thisDev );
  706. /*
  707. * Set request-to-send and clear data-terminal-ready.
  708. * Note: ** Bit 3 must be set to enable interrupts.
  709. */
  710. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, MODEM_CONTROL_REG_OFFSET, 0x0A);
  711. if (!dongleInit){
  712. DBGERR(("Dongle-specific init failed in OpenCOM"));
  713. return FALSE;
  714. }
  715. /*
  716. * Set speed to default for the entire part.
  717. * (This is redundant in most, but not all, cases.)
  718. */
  719. thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];;
  720. SetSpeed(thisDev);
  721. /*
  722. * Clear the FIFO control register
  723. */
  724. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x00);
  725. /*
  726. * Set up the FIFO control register to use both read and write FIFOs (if 16650),
  727. * and with a receive FIFO trigger level of 1 byte.
  728. */
  729. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x07);
  730. /*
  731. * Check whether we're running on a 16550,which has a 16-byte write FIFO.
  732. * In this case, we'll be able to blast up to 16 bytes at a time.
  733. */
  734. intIdReg = SYNC_GET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
  735. thisDev->portInfo.haveFIFO = (BOOLEAN)((intIdReg & 0xC0) == 0xC0);
  736. /*
  737. * Start out in receive mode.
  738. * We always want to be in receive mode unless we're transmitting a frame.
  739. */
  740. SyncSetInterruptMask(thisDev, TRUE);
  741. DBGOUT(("OpenCOM succeeded"));
  742. return TRUE;
  743. }
  744. #if 1
  745. /*
  746. *************************************************************************
  747. * CloseCOM
  748. *************************************************************************
  749. *
  750. */
  751. VOID CloseCOM(IrDevice *thisDev)
  752. {
  753. /*
  754. * Do special deinit for dongles.
  755. * Some dongles can only rcv cmd sequences at 9600, so set this speed first.
  756. */
  757. thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];;
  758. SetSpeed(thisDev);
  759. NSC_DEMO_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
  760. SyncSetInterruptMask(thisDev, FALSE);
  761. }
  762. #endif
  763. /*
  764. *************************************************************************
  765. * DoRcvDirect
  766. *************************************************************************
  767. *
  768. * Read up to maxBytes bytes from the UART's receive FIFO.
  769. * Return the number of bytes read or (UINT)-1 if an error occurred.
  770. *
  771. */
  772. UINT DoRcvDirect(PUCHAR ioBase, UCHAR *data, UINT maxBytes)
  773. {
  774. USHORT bytesRead;
  775. UCHAR lineStatReg;
  776. UINT i;
  777. BOOLEAN goodChar;
  778. for (bytesRead = 0; bytesRead < maxBytes; bytesRead++){
  779. /*
  780. * Wait for data-ready
  781. */
  782. i = 0;
  783. do {
  784. lineStatReg = GetCOMPort(ioBase, LINE_STAT_REG_OFFSET);
  785. /*
  786. * The UART reports framing and break errors as the effected
  787. * characters appear on the stack. We drop these characters,
  788. * which will probably result in a bad frame checksum.
  789. */
  790. if (lineStatReg & (LINESTAT_BREAK | LINESTAT_FRAMINGERROR)){
  791. UCHAR badch = GetCOMPort(ioBase, XFER_REG_OFFSET);
  792. DBGERR(("Bad rcv %02xh, LSR=%02xh", (UINT)badch, (UINT)lineStatReg));
  793. return (UINT)-1;
  794. }
  795. else if (lineStatReg & LINESTAT_DATAREADY){
  796. if (lineStatReg & LINESTAT_OVERRUNERROR) {
  797. DBGERR(("Overrun"));
  798. }
  799. goodChar = TRUE;
  800. }
  801. else {
  802. /*
  803. * No input char ready
  804. */
  805. goodChar = FALSE;
  806. }
  807. } while (!goodChar && (++i < REG_POLL_LOOPS));
  808. if (!goodChar){
  809. break;
  810. }
  811. /*
  812. * Read in the next data byte
  813. */
  814. data[bytesRead] = GetCOMPort(ioBase, XFER_REG_OFFSET);
  815. }
  816. return bytesRead;
  817. }
  818. /*
  819. *************************************************************************
  820. * GetCOMPort
  821. *************************************************************************
  822. */
  823. UCHAR GetCOMPort(PUCHAR comBase, comPortRegOffset portOffset)
  824. {
  825. UCHAR val;
  826. #if DBG
  827. {
  828. UCHAR TempVal;
  829. //
  830. // This code assumes that bank 0 is current, we will make sure of that
  831. //
  832. NdisRawReadPortUchar(comBase+LCR_BSR_OFFSET, &TempVal);
  833. ASSERT((TempVal & BKSE) == 0);
  834. }
  835. #endif
  836. NdisRawReadPortUchar(comBase+portOffset, &val);
  837. return val;
  838. }
  839. /*
  840. *************************************************************************
  841. * SetCOMPort
  842. *************************************************************************
  843. */
  844. VOID SetCOMPort(PUCHAR comBase, comPortRegOffset portOffset, UCHAR val)
  845. {
  846. #if DBG
  847. UCHAR TempVal;
  848. //
  849. // This code assumes that bank 0 is current, we will make sure of that
  850. //
  851. NdisRawReadPortUchar(comBase+LCR_BSR_OFFSET, &TempVal);
  852. ASSERT((TempVal & BKSE) == 0);
  853. #endif
  854. NdisRawWritePortUchar(comBase+portOffset, val);
  855. }