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.

1030 lines
28 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. #include "comm.tmh"
  16. #define MEDIA_BUSY_THRESHOLD (16)
  17. #define SYNC_SET_COMM_PORT(_intobj,_port,_index,_value) SyncWriteBankReg(_intobj,_port,0,_index,_value);
  18. #define SYNC_GET_COMM_PORT(_intobj,_port,_index) SyncReadBankReg(_intobj,_port,0,_index)
  19. /*
  20. *************************************************************************
  21. * SetCOMInterrupts
  22. *************************************************************************
  23. */
  24. VOID SetCOMInterrupts(IrDevice *thisDev, BOOLEAN enable)
  25. {
  26. UCHAR newMask;
  27. if (enable){
  28. if (thisDev->portInfo.SirWritePending){
  29. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  30. newMask = thisDev->FirIntMask;
  31. }
  32. else {
  33. newMask = XMIT_MODE_INTS_ENABLE;
  34. }
  35. }
  36. else {
  37. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  38. newMask = thisDev->FirIntMask;
  39. }
  40. else {
  41. newMask = RCV_MODE_INTS_ENABLE;
  42. }
  43. }
  44. }
  45. else {
  46. newMask = ALL_INTS_DISABLE;
  47. }
  48. SetCOMPort(thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, newMask);
  49. }
  50. VOID
  51. SyncSetInterruptMask(
  52. IrDevice *thisDev,
  53. BOOLEAN enable
  54. )
  55. {
  56. UCHAR newMask;
  57. if (enable){
  58. if (thisDev->portInfo.SirWritePending){
  59. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  60. newMask = thisDev->FirIntMask;
  61. }
  62. else {
  63. newMask = XMIT_MODE_INTS_ENABLE;
  64. }
  65. }
  66. else {
  67. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  68. newMask = thisDev->FirIntMask;
  69. }
  70. else {
  71. newMask = RCV_MODE_INTS_ENABLE;
  72. }
  73. }
  74. }
  75. else {
  76. newMask = ALL_INTS_DISABLE;
  77. }
  78. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, newMask);
  79. }
  80. /*
  81. *************************************************************************
  82. * DoOpen
  83. *************************************************************************
  84. *
  85. * Open COMM port
  86. *
  87. */
  88. BOOLEAN DoOpen(IrDevice *thisDev)
  89. {
  90. BOOLEAN result;
  91. DBGOUT(("DoOpen(%d)", thisDev->portInfo.ioBase));
  92. /*
  93. * This buffer gets swapped with the rcvBuffer data pointer
  94. * and must be the same size.
  95. */
  96. thisDev->portInfo.readBuf = LIST_ENTRY_TO_RCV_BUF(NscMemAlloc(RCV_BUFFER_SIZE)); // Was FALSE -SWA
  97. if (!thisDev->portInfo.readBuf){
  98. return FALSE;
  99. }
  100. /*
  101. * The write buffer is also used as a DMA buffer.
  102. */
  103. thisDev->portInfo.writeComBuffer = NscMemAlloc(MAX_IRDA_DATA_SIZE );
  104. if (!thisDev->portInfo.writeComBuffer){
  105. return FALSE;
  106. }
  107. /*
  108. * Initialize send/receive FSMs before OpenCOM(), which enables rcv interrupts.
  109. */
  110. thisDev->portInfo.rcvState = STATE_INIT;
  111. thisDev->portInfo.SirWritePending = FALSE;
  112. //
  113. // the sir recieve will start automatically
  114. //
  115. thisDev->TransmitIsIdle= TRUE;
  116. NdisInitializeEvent(&thisDev->ReceiveStopped);
  117. NdisResetEvent(&thisDev->ReceiveStopped);
  118. NdisInitializeEvent(&thisDev->SendStoppedOnHalt);
  119. NdisResetEvent(&thisDev->SendStoppedOnHalt);
  120. result = OpenCOM(thisDev);
  121. DBGOUT(("DoOpen %s", (CHAR *)(result ? "succeeded" : "failed")));
  122. return result;
  123. }
  124. /*
  125. *************************************************************************
  126. * DoClose
  127. *************************************************************************
  128. *
  129. * Close COMM port
  130. *
  131. */
  132. VOID DoClose(IrDevice *thisDev)
  133. {
  134. DBGOUT(("DoClose(COM%d)", thisDev->portInfo.ioBase));
  135. if (thisDev->portInfo.readBuf){
  136. NscMemFree(RCV_BUF_TO_LIST_ENTRY(thisDev->portInfo.readBuf));
  137. thisDev->portInfo.readBuf = NULL;
  138. }
  139. if (thisDev->portInfo.writeComBuffer){
  140. NscMemFree(thisDev->portInfo.writeComBuffer);
  141. thisDev->portInfo.writeComBuffer = 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.writeComBufferPos;
  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.writeComBufferPos < thisDev->portInfo.writeComBufferLen){
  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.writeComBufferLen - thisDev->portInfo.writeComBufferPos));
  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.writeComBuffer[thisDev->portInfo.writeComBufferPos++]);
  307. }
  308. }
  309. /*
  310. * The return value will indicate whether we've sent the entire frame.
  311. */
  312. if (thisDev->portInfo.writeComBufferPos >= thisDev->portInfo.writeComBufferLen){
  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.writeComBufferPos-startPos), (PUCHAR)(result ? "DONE" : "not done")));
  336. // DBGPRINTBUF(thisDev->portInfo.writeComBuffer+startPos, thisDev->portInfo.writeComBufferPos-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=0, rawBytesRead=0;
  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. pListEntry = RemoveHeadList(&thisDev->rcvBufBuf);
  526. thisDev->portInfo.readBuf = LIST_ENTRY_TO_RCV_BUF(pListEntry);
  527. }
  528. else
  529. {
  530. // No new buffers were available. We just discard this packet.
  531. DBGERR(("No rcvBufBuf available, discarding packet\n"));
  532. }
  533. result = TRUE;
  534. if (rawBufPos < rawBytesRead){
  535. /*
  536. * This is ugly.
  537. * We have some more unprocessed bytes in the raw buffer.
  538. * Move these to the beginning of the raw buffer
  539. * go to the CLEANUP state, which indicates that these
  540. * bytes be used up during the next call.
  541. * (This is typically only 1 or 2 bytes).
  542. * Note: We can't just leave these in the raw buffer because
  543. * we might be supporting connections to multiple COM ports.
  544. */
  545. memcpy(thisDev->portInfo.rawBuf, &thisDev->portInfo.rawBuf[rawBufPos], rawBytesRead-rawBufPos);
  546. thisDev->portInfo.readBufPos = rawBytesRead-rawBufPos;
  547. thisDev->portInfo.rcvState = STATE_CLEANUP;
  548. }
  549. else {
  550. thisDev->portInfo.rcvState = STATE_INIT;
  551. }
  552. break;
  553. default:
  554. if (thisDev->portInfo.readBufPos > MAX_RCV_DATA_SIZE){
  555. DBGERR(("Overrun in DoRcv : read %d=%xh bytes:", thisDev->portInfo.readBufPos, thisDev->portInfo.readBufPos));
  556. DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
  557. thisDev->portInfo.readBufPos = 0;
  558. thisDev->portInfo.rcvState = STATE_INIT;
  559. }
  560. else {
  561. DBGOUT(("DoRcv returning with partial packet, read %d bytes", thisDev->portInfo.readBufPos));
  562. }
  563. result = FALSE;
  564. break;
  565. }
  566. return result;
  567. }
  568. /*
  569. *************************************************************************
  570. * COM_ISR
  571. *************************************************************************
  572. *
  573. *
  574. */
  575. VOID COM_ISR(IrDevice *thisDev, BOOLEAN *claimingInterrupt, BOOLEAN *requireDeferredCallback)
  576. {
  577. LONG NewCount;
  578. /*
  579. * Get the interrupt status register value.
  580. */
  581. UCHAR intId = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
  582. if (intId & INTID_INTERRUPT_NOT_PENDING){
  583. /*
  584. * This is NOT our interrupt.
  585. * Set carry bit to pass the interrupt to the next driver in the chain.
  586. */
  587. *claimingInterrupt = *requireDeferredCallback = FALSE;
  588. }
  589. else {
  590. /*
  591. * This is our interrupt
  592. */
  593. /*
  594. * In some odd situations, we can get interrupt bits that don't
  595. * get cleared; we don't want to loop forever in this case, so keep a counter.
  596. */
  597. UINT loops = 0;
  598. *claimingInterrupt = TRUE;
  599. *requireDeferredCallback = FALSE;
  600. while (!(intId & INTID_INTERRUPT_NOT_PENDING) && (loops++ < 0x10)){
  601. switch (intId & INTID_INTIDMASK){
  602. case INTID_MODEMSTAT_INT:
  603. DBGOUT(("COM INTERRUPT: modem status int"));
  604. GetCOMPort(thisDev->portInfo.ioBase, MODEM_STAT_REG_OFFSET);
  605. break;
  606. case INTID_XMITREG_INT:
  607. DBGOUT(("COM INTERRUPT: xmit reg empty"));
  608. if (thisDev->portInfo.SirWritePending){
  609. /*
  610. * Try to send a few more bytes
  611. */
  612. if (StepSendFSM(thisDev)){
  613. /*
  614. * There are no more bytes to send;
  615. * reset interrupts for receive mode.
  616. */
  617. thisDev->portInfo.SirWritePending = FALSE;
  618. InterlockedExchange(&thisDev->portInfo.IsrDoneWithPacket,1);
  619. //
  620. // this will unmask the receive interrupt
  621. //
  622. SetCOMInterrupts(thisDev, TRUE);
  623. /*
  624. * Request a DPC so that we can try
  625. * to send other pending write packets.
  626. */
  627. *requireDeferredCallback = TRUE;
  628. }
  629. }
  630. break;
  631. case INTID_RCVDATAREADY_INT:
  632. DBGOUT(("COM INTERRUPT: rcv data available!"));
  633. thisDev->nowReceiving = TRUE;
  634. NewCount=NdisInterlockedIncrement(&thisDev->RxInterrupts);
  635. if (!thisDev->mediaBusy && (NewCount > MEDIA_BUSY_THRESHOLD)){
  636. thisDev->mediaBusy = TRUE;
  637. thisDev->haveIndicatedMediaBusy = FALSE;
  638. *requireDeferredCallback = TRUE;
  639. }
  640. if (StepReceiveFSM(thisDev)){
  641. /*
  642. * The receive engine has accumulated an entire frame.
  643. * Request a deferred callback so we can deliver the frame
  644. * when not in interrupt context.
  645. */
  646. *requireDeferredCallback = TRUE;
  647. thisDev->nowReceiving = FALSE;
  648. }
  649. break;
  650. case INTID_RCVLINESTAT_INT:
  651. DBGOUT(("COM INTERRUPT: rcv line stat int!"));
  652. break;
  653. }
  654. /*
  655. * After we service each interrupt condition, we read the line status register.
  656. * This clears the current interrupt, and a new interrupt may then appear in
  657. * the interrupt-id register.
  658. */
  659. GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
  660. intId = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
  661. }
  662. }
  663. }
  664. /*
  665. *************************************************************************
  666. * OpenCOM
  667. *************************************************************************
  668. *
  669. * Initialize UART registers
  670. *
  671. */
  672. BOOLEAN OpenCOM(IrDevice *thisDev)
  673. {
  674. BOOLEAN dongleInit;
  675. UCHAR intIdReg;
  676. DBGOUT(("-> OpenCOM"));
  677. //
  678. // Make sure bank zero is selected
  679. //
  680. NdisRawWritePortUchar(thisDev->portInfo.ioBase+LCR_BSR_OFFSET, 03);
  681. /*
  682. * Disable all COM interrupts while setting up.
  683. */
  684. SyncSetInterruptMask(thisDev, FALSE);
  685. /*
  686. * Set request-to-send and clear data-terminal-ready.
  687. * Note: ** Bit 3 must be set to enable interrupts.
  688. */
  689. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, MODEM_CONTROL_REG_OFFSET, 0x0A);
  690. /*
  691. * Set dongle- or part-specific info to default
  692. */
  693. thisDev->portInfo.hwCaps.supportedSpeedsMask = ALL_SLOW_IRDA_SPEEDS;
  694. thisDev->portInfo.hwCaps.turnAroundTime_usec = DEFAULT_TURNAROUND_usec;
  695. thisDev->portInfo.hwCaps.extraBOFsRequired = 0;
  696. /*
  697. * Set the COM port speed to the default 9600 baud.
  698. * Some dongles can only receive cmd sequences at this speed.
  699. */
  700. SetUARTSpeed(thisDev, 9600);
  701. dongleInit = NSC_DEMO_Init( thisDev );
  702. /*
  703. * Set request-to-send and clear data-terminal-ready.
  704. * Note: ** Bit 3 must be set to enable interrupts.
  705. */
  706. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, MODEM_CONTROL_REG_OFFSET, 0x0A);
  707. if (!dongleInit){
  708. DBGERR(("Dongle-specific init failed in OpenCOM"));
  709. return FALSE;
  710. }
  711. /*
  712. * Set speed to default for the entire part.
  713. * (This is redundant in most, but not all, cases.)
  714. */
  715. thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];;
  716. SetSpeed(thisDev);
  717. /*
  718. * Clear the FIFO control register
  719. */
  720. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x00);
  721. /*
  722. * Set up the FIFO control register to use both read and write FIFOs (if 16650),
  723. * and with a receive FIFO trigger level of 1 byte.
  724. */
  725. SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x07);
  726. /*
  727. * Check whether we're running on a 16550,which has a 16-byte write FIFO.
  728. * In this case, we'll be able to blast up to 16 bytes at a time.
  729. */
  730. intIdReg = SYNC_GET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
  731. thisDev->portInfo.haveFIFO = (BOOLEAN)((intIdReg & 0xC0) == 0xC0);
  732. /*
  733. * Start out in receive mode.
  734. * We always want to be in receive mode unless we're transmitting a frame.
  735. */
  736. SyncSetInterruptMask(thisDev, TRUE);
  737. DBGOUT(("OpenCOM succeeded"));
  738. return TRUE;
  739. }
  740. #if 1
  741. /*
  742. *************************************************************************
  743. * CloseCOM
  744. *************************************************************************
  745. *
  746. */
  747. VOID CloseCOM(IrDevice *thisDev)
  748. {
  749. /*
  750. * Do special deinit for dongles.
  751. * Some dongles can only rcv cmd sequences at 9600, so set this speed first.
  752. */
  753. thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];;
  754. SetSpeed(thisDev);
  755. NSC_DEMO_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
  756. SyncSetInterruptMask(thisDev, FALSE);
  757. }
  758. #endif
  759. /*
  760. *************************************************************************
  761. * DoRcvDirect
  762. *************************************************************************
  763. *
  764. * Read up to maxBytes bytes from the UART's receive FIFO.
  765. * Return the number of bytes read or (UINT)-1 if an error occurred.
  766. *
  767. */
  768. UINT DoRcvDirect(PUCHAR ioBase, UCHAR *data, UINT maxBytes)
  769. {
  770. USHORT bytesRead;
  771. UCHAR lineStatReg;
  772. UINT i;
  773. BOOLEAN goodChar;
  774. for (bytesRead = 0; bytesRead < maxBytes; bytesRead++){
  775. /*
  776. * Wait for data-ready
  777. */
  778. i = 0;
  779. do {
  780. lineStatReg = GetCOMPort(ioBase, LINE_STAT_REG_OFFSET);
  781. /*
  782. * The UART reports framing and break errors as the effected
  783. * characters appear on the stack. We drop these characters,
  784. * which will probably result in a bad frame checksum.
  785. */
  786. if (lineStatReg & (LINESTAT_BREAK | LINESTAT_FRAMINGERROR)){
  787. UCHAR badch = GetCOMPort(ioBase, XFER_REG_OFFSET);
  788. DBGERR(("Bad rcv %02xh, LSR=%02xh", (UINT)badch, (UINT)lineStatReg));
  789. return (UINT)-1;
  790. }
  791. else if (lineStatReg & LINESTAT_DATAREADY){
  792. if (lineStatReg & LINESTAT_OVERRUNERROR) {
  793. DBGERR(("Overrun"));
  794. }
  795. goodChar = TRUE;
  796. }
  797. else {
  798. /*
  799. * No input char ready
  800. */
  801. goodChar = FALSE;
  802. }
  803. } while (!goodChar && (++i < REG_POLL_LOOPS));
  804. if (!goodChar){
  805. break;
  806. }
  807. /*
  808. * Read in the next data byte
  809. */
  810. data[bytesRead] = GetCOMPort(ioBase, XFER_REG_OFFSET);
  811. }
  812. return bytesRead;
  813. }
  814. /*
  815. *************************************************************************
  816. * GetCOMPort
  817. *************************************************************************
  818. */
  819. UCHAR GetCOMPort(PUCHAR comBase, comPortRegOffset portOffset)
  820. {
  821. UCHAR val;
  822. #if DBG
  823. {
  824. UCHAR TempVal;
  825. //
  826. // This code assumes that bank 0 is current, we will make sure of that
  827. //
  828. NdisRawReadPortUchar(comBase+LCR_BSR_OFFSET, &TempVal);
  829. ASSERT((TempVal & BKSE) == 0);
  830. }
  831. #endif
  832. NdisRawReadPortUchar(comBase+portOffset, &val);
  833. return val;
  834. }
  835. /*
  836. *************************************************************************
  837. * SetCOMPort
  838. *************************************************************************
  839. */
  840. VOID SetCOMPort(PUCHAR comBase, comPortRegOffset portOffset, UCHAR val)
  841. {
  842. #if DBG
  843. UCHAR TempVal;
  844. //
  845. // This code assumes that bank 0 is current, we will make sure of that
  846. //
  847. NdisRawReadPortUchar(comBase+LCR_BSR_OFFSET, &TempVal);
  848. ASSERT((TempVal & BKSE) == 0);
  849. #endif
  850. NdisRawWritePortUchar(comBase+portOffset, val);
  851. }