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.

768 lines
24 KiB

  1. /*
  2. ************************************************************************
  3. *
  4. * NSCFIR.C
  5. *
  6. *
  7. * Portions Copyright (C) 1996-2001 National Semiconductor Corp.
  8. * All rights reserved.
  9. * Copyright (C) 1996-2001 Microsoft Corporation. All Rights Reserved.
  10. *
  11. *
  12. *
  13. *************************************************************************
  14. */
  15. #include "nsc.h"
  16. #include "nsctypes.h"
  17. //#include "dma.h"
  18. VOID NSC_FIR_ISR(IrDevice *thisDev, BOOLEAN *claimingInterrupt,
  19. BOOLEAN *requireDeferredCallback)
  20. {
  21. LOG("==> NSC_FIR_ISR", 0);
  22. DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: ==> NSC_FIR_ISR(0x%x)\n", thisDev));
  23. thisDev->InterruptMask = NSC_ReadBankReg(thisDev->portInfo.ioBase, 0, 1);
  24. thisDev->InterruptStatus = NSC_ReadBankReg(thisDev->portInfo.ioBase, 0, 2) & thisDev->FirIntMask;
  25. thisDev->AuxStatus = NSC_ReadBankReg(thisDev->portInfo.ioBase, 0, 7);
  26. thisDev->LineStatus = NSC_ReadBankReg(thisDev->portInfo.ioBase, 0, 5);
  27. LOG("InterruptMask: ", thisDev->InterruptMask);
  28. LOG("InterruptStatus: ", thisDev->InterruptStatus);
  29. LOG("AuxStatus: ", thisDev->AuxStatus);
  30. LOG("LineStatus: ", thisDev->LineStatus);
  31. DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: InterruptMask = 0x%x\n", thisDev->InterruptMask));
  32. DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: InterruptStatus = 0x%x\n", thisDev->InterruptStatus));
  33. DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: AuxStatus = 0x%x\n", thisDev->AuxStatus));
  34. DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: LineStatus = 0x%x\n", thisDev->LineStatus));
  35. if (thisDev->InterruptStatus) {
  36. //
  37. // After seeing the first packet switch the interrupt
  38. // to timer and use the DMA counter to decide if receptions
  39. // have stopped.
  40. //
  41. if (thisDev->InterruptStatus & LS_EV) {
  42. //
  43. // Got a link status interrupt
  44. //
  45. if (thisDev->LineStatus & LSR_FR_END) {
  46. //
  47. // The frame end status is set
  48. //
  49. if (!thisDev->FirTransmitPending) {
  50. //
  51. // we weren't tansmitting
  52. //
  53. // thisDev->IntMask = 0x90;
  54. //
  55. // Enable the Timer
  56. //
  57. // NSC_WriteBankReg(thisDev->portInfo.ioBase, 4, 2, 0x01);
  58. // thisDev->LastReadDMACount = thisDev->rcvDmaOffset;
  59. }
  60. }
  61. if (thisDev->LineStatus & LSR_OE) {
  62. DBGERR(("rx ov"));
  63. // DbgBreakPoint();
  64. }
  65. }
  66. if (thisDev->InterruptStatus & TMR_EV){
  67. //
  68. // Disable Timer during call to DPC bit.
  69. //
  70. NSC_WriteBankReg(thisDev->portInfo.ioBase, 4, 2, 0x00);
  71. NSC_WriteBankReg(thisDev->portInfo.ioBase, 0, 7, 0x80);
  72. }
  73. *claimingInterrupt = TRUE;
  74. *requireDeferredCallback = TRUE;
  75. SetCOMInterrupts(thisDev, FALSE);
  76. if (thisDev->UIR_ModuleId >= 0x16 )
  77. {
  78. // This is for the Frame stop mode when the ISR is interrupted
  79. // after every Frame Tx
  80. //
  81. if ((thisDev->AuxStatus & 0x08)
  82. && (thisDev->InterruptStatus & 0x04)
  83. && (thisDev->FirTransmitPending == TRUE))
  84. {
  85. if (thisDev->LineStatus&0x40)
  86. {
  87. NSC_WriteBankReg(thisDev->portInfo.ioBase, 0, 7, 0x40);
  88. DBGERR(("FIR: Transmit underrun\n"));
  89. }
  90. }
  91. }
  92. }
  93. else {
  94. *claimingInterrupt = FALSE;
  95. *requireDeferredCallback = FALSE;
  96. }
  97. LOG("claimingInterrupt = ", *claimingInterrupt);
  98. LOG("requireDeferredCallback = ", *requireDeferredCallback);
  99. DEBUGFIR(DBG_ISR|DBG_OUT, ("NSC: <== NSC_FIR_ISR\n"));
  100. }
  101. typedef struct {
  102. IrDevice *thisDev;
  103. ULONG_PTR Offset;
  104. ULONG_PTR Length;
  105. } DMASPACE;
  106. void SkipNonDmaBuffers(PLIST_ENTRY Head, PLIST_ENTRY *Entry)
  107. {
  108. while (Head!=*Entry)
  109. {
  110. rcvBuffer *rcvBuf = CONTAINING_RECORD(*Entry,
  111. rcvBuffer,
  112. listEntry);
  113. if (rcvBuf->isDmaBuf)
  114. {
  115. break;
  116. }
  117. else
  118. {
  119. *Entry = (*Entry)->Flink;
  120. }
  121. }
  122. }
  123. //
  124. // We have two lists of buffers which occupy our DMA space. We
  125. // want to walk this list and find the largest space for putting
  126. // new packets.
  127. //
  128. rcvBuffer *GetNextPacket(DMASPACE *Space,
  129. PLIST_ENTRY *CurrFull,
  130. PLIST_ENTRY *CurrPend)
  131. {
  132. rcvBuffer *Result = NULL;
  133. SkipNonDmaBuffers(&Space->thisDev->rcvBufFull, CurrFull);
  134. SkipNonDmaBuffers(&Space->thisDev->rcvBufPend, CurrPend);
  135. if (*CurrFull==&Space->thisDev->rcvBufFull)
  136. {
  137. // Full list is finished.
  138. if (*CurrPend!=&Space->thisDev->rcvBufPend)
  139. {
  140. // Any entry on the pend list is valid. Take the
  141. // next one and advance the pointer.
  142. Result = CONTAINING_RECORD(*CurrPend,
  143. rcvBuffer,
  144. listEntry);
  145. *CurrPend = (*CurrPend)->Flink;
  146. }
  147. else
  148. {
  149. // Both lists are finished. We will return NULL.
  150. }
  151. }
  152. else
  153. {
  154. if (*CurrPend==&Space->thisDev->rcvBufPend)
  155. {
  156. // Pend list is finished. Take anything from the
  157. // Full list, advance the pointer.
  158. Result = CONTAINING_RECORD(*CurrFull,
  159. rcvBuffer,
  160. listEntry);
  161. *CurrFull = (*CurrFull)->Flink;
  162. }
  163. else
  164. {
  165. // Both list have valid entries. Compare the two and take the
  166. // one that appears in the buffer first.
  167. rcvBuffer *Full, *Pend;
  168. Full = CONTAINING_RECORD(*CurrFull,
  169. rcvBuffer,
  170. listEntry);
  171. Pend = CONTAINING_RECORD(*CurrPend,
  172. rcvBuffer,
  173. listEntry);
  174. if (Full->dataBuf < Pend->dataBuf)
  175. {
  176. // Full is the winner. Take it.
  177. Result = Full;
  178. *CurrFull = (*CurrFull)->Flink;
  179. }
  180. else
  181. {
  182. // Pend is the winner. Take it.
  183. Result = Pend;
  184. *CurrPend = (*CurrPend)->Flink;
  185. }
  186. }
  187. }
  188. if (Result)
  189. {
  190. ASSERT(Result->isDmaBuf);
  191. }
  192. return Result;
  193. }
  194. BOOLEAN SynchronizedFindLargestSpace(IN PVOID Context)
  195. {
  196. DMASPACE *Space = Context;
  197. IrDevice *thisDev = Space->thisDev;
  198. BOOLEAN Result;
  199. PLIST_ENTRY Full, Pend;
  200. rcvBuffer *Current = NULL;
  201. ASSERT(sizeof(ULONG)==sizeof(PVOID));
  202. if (IsListEmpty(&thisDev->rcvBufFull) && IsListEmpty(&thisDev->rcvBufPend))
  203. {
  204. Space->Offset = (ULONG_PTR)thisDev->portInfo.dmaReadBuf;
  205. Space->Length = RCV_DMA_SIZE;
  206. }
  207. else
  208. {
  209. ULONG_PTR EndOfLast;
  210. ULONG_PTR ThisSpace;
  211. Full = thisDev->rcvBufFull.Flink;
  212. Pend = thisDev->rcvBufPend.Flink;
  213. Space->Length = 0;
  214. EndOfLast = Space->Offset = (ULONG_PTR)thisDev->portInfo.dmaReadBuf;
  215. Current = GetNextPacket(Space, &Full, &Pend);
  216. while (Current)
  217. {
  218. // It's possible to get a packet that is from SIR. If so, skip it.
  219. if (Current->isDmaBuf)
  220. {
  221. ASSERT((ULONG_PTR)Current->dataBuf >= EndOfLast);
  222. ThisSpace = (ULONG_PTR)Current->dataBuf - EndOfLast;
  223. // ASSERT the pointer is actually in our DMA buffer.
  224. ASSERT(Current->dataBuf >= thisDev->portInfo.dmaReadBuf ||
  225. Current->dataBuf < thisDev->portInfo.dmaReadBuf+RCV_DMA_SIZE);
  226. if (ThisSpace > Space->Length)
  227. {
  228. Space->Offset = EndOfLast;
  229. Space->Length = ThisSpace;
  230. }
  231. EndOfLast = (ULONG_PTR)Current->dataBuf + Current->dataLen;
  232. }
  233. Current = GetNextPacket(Space, &Full, &Pend);
  234. }
  235. // Now we do one more calculation for the space after the end of the list.
  236. ThisSpace = (ULONG_PTR)thisDev->portInfo.dmaReadBuf + RCV_DMA_SIZE - (ULONG_PTR)EndOfLast;
  237. if (ThisSpace > Space->Length)
  238. {
  239. Space->Offset = EndOfLast;
  240. Space->Length = ThisSpace;
  241. }
  242. // Round off to start DMA on 4 byte boundary
  243. Space->Length -= 4 - (Space->Offset & 3);
  244. Space->Offset = (Space->Offset+3) & (~3);
  245. }
  246. // We want space relative to start of buffer.
  247. Space->Offset -= (ULONG_PTR)thisDev->portInfo.dmaReadBuf;
  248. Result = (Space->Length >= MAX_RCV_DATA_SIZE + FAST_IR_FCS_SIZE);
  249. if (!Result)
  250. {
  251. DEBUGFIR(DBG_ERR, ("NSC: ERROR: Not enough space to DMA full packet %x\n", thisDev));
  252. }
  253. return Result;
  254. }
  255. BOOLEAN FindLargestSpace(IN IrDevice *thisDev,
  256. OUT PULONG_PTR pOffset,
  257. OUT PULONG_PTR pLength)
  258. {
  259. DMASPACE Space;
  260. BOOLEAN Result;
  261. Space.Offset = 0;
  262. Space.Length = 0;
  263. Space.thisDev = thisDev;
  264. // NdisAcquireSpinLock(&thisDev->QueueLock);
  265. Result = NdisMSynchronizeWithInterrupt(
  266. &thisDev->interruptObj,
  267. SynchronizedFindLargestSpace,
  268. &Space
  269. );
  270. // NdisReleaseSpinLock(&thisDev->QueueLock);
  271. *pOffset = Space.Offset;
  272. *pLength = Space.Length;
  273. return Result;
  274. }
  275. void FIR_DeliverFrames(IrDevice *thisDev)
  276. {
  277. UCHAR frameStat;
  278. NDIS_STATUS stat;
  279. ULONG rcvFrameSize;
  280. PUCHAR NewFrame;
  281. ULONG_PTR LastReadDMACount, EndOfData;
  282. BOOLEAN resetDma = FALSE, OverflowOccurred = FALSE;
  283. BOOLEAN Discarding = thisDev->DiscardNextPacketSet;
  284. const UINT fcsSize = ( thisDev->currentSpeed >= MIN_FIR_SPEED) ?
  285. FAST_IR_FCS_SIZE : MEDIUM_IR_FCS_SIZE;
  286. LOG("==> FIR_DeliverFrames", 0);
  287. DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: ==> FIR_DeliverFrames(0x%x)\n", thisDev));
  288. LastReadDMACount = NdisMReadDmaCounter(thisDev->DmaHandle);
  289. // Check for data received since the last time we were here.
  290. // We also check for data in fifo. If there is some, we wait, as long
  291. // as the DMA still has room to capture data.
  292. if ((LastReadDMACount > 0)
  293. &&
  294. ((LastReadDMACount < thisDev->LastReadDMACount) || (SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 2, 7) & 0x3f))) {
  295. //
  296. // if there are still bytes remaining in out transfer and we transfered something since
  297. // the last interrupt or there are still bytes in the fifo, then set a timer
  298. //
  299. thisDev->LastReadDMACount = LastReadDMACount;
  300. //
  301. // Set Timer Enable bit for another Timeout.
  302. //
  303. thisDev->FirIntMask = 0x90;
  304. SyncWriteBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 4, 2, 0x01);
  305. LOG("<== FIR_DeliverFrames-Early Return", 1);
  306. DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: <== FIR_DeliverFrames\n"));
  307. return;
  308. }
  309. RegStats.RxDPC_Window++;
  310. stat=CompleteDmaTransferFromDevice(&thisDev->DmaUtil);
  311. if (stat != NDIS_STATUS_SUCCESS) {
  312. DBGERR(("NdisMCompleteDmaTransfer failed: %d\n", stat));
  313. ASSERT(0);
  314. }
  315. thisDev->FirReceiveDmaActive=FALSE;
  316. thisDev->DiscardNextPacketSet = FALSE;
  317. // Get the exact count.
  318. LastReadDMACount = NdisMReadDmaCounter(thisDev->DmaHandle);
  319. EndOfData = thisDev->rcvDmaOffset + thisDev->rcvDmaSize - LastReadDMACount;
  320. SyncGetFifoStatus(
  321. &thisDev->interruptObj,
  322. thisDev->portInfo.ioBase,
  323. &frameStat,
  324. &rcvFrameSize
  325. );
  326. if (frameStat == 0) DBGERR(("fdf no frames in fifo"));
  327. LOG("frameStat: ", (UINT) frameStat);
  328. DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: frameStat = %xh\n", (UINT) frameStat));
  329. while ((frameStat & 0x80) && thisDev->rcvPktOffset < EndOfData) {
  330. /*
  331. * This status byte is valid; see what else it says...
  332. * Also mask off indeterminate bit.
  333. */
  334. frameStat &= ~0xA0;
  335. /*
  336. * Whether the frame is good or bad, we must read the counter
  337. * FIFO to synchronize it with the frame status FIFO.
  338. */
  339. if (Discarding)
  340. {
  341. DbgPrint("nsc: disc stat=%02x, lost=%d\n",frameStat,rcvFrameSize);
  342. // Do nothing
  343. }
  344. else if (frameStat) {
  345. /*
  346. * Some rcv error occurred. Reset DMA.
  347. */
  348. LOG("*** RCV ERR: framStat in FIR_DeliverFrames:",
  349. frameStat);
  350. // DbgPrint("nsc: stat=%02x, lost=%d\n",frameStat,rcvFrameSize);
  351. DEBUGFIR(DBG_RX|DBG_ERR, ("NSC: RCV ERR: frameStat=%xh FrameSize=%d \n",
  352. (UINT)frameStat,rcvFrameSize));
  353. if (frameStat & 0x40) {
  354. if (frameStat & 0x01) {
  355. RegStats.StatusFIFOOverflows++;
  356. }
  357. if (frameStat & 0x02) {
  358. RegStats.ReceiveFIFOOverflows++;
  359. }
  360. RegStats.MissedPackets += rcvFrameSize;
  361. }
  362. else{
  363. if (frameStat & 0x01) {
  364. RegStats.StatusFIFOOverflows++;
  365. }
  366. if (frameStat & 0x02) {
  367. RegStats.ReceiveFIFOOverflows++;
  368. }
  369. if (frameStat & 0x04) {
  370. RegStats.ReceiveCRCErrors++;
  371. }
  372. if (frameStat & 0x08) {
  373. }
  374. if (frameStat & 0x10) {
  375. }
  376. LOG("Bytes Lost:",rcvFrameSize);
  377. ASSERT((thisDev->rcvPktOffset + rcvFrameSize)<= RCV_DMA_SIZE);
  378. /* Advance pointer past bad packet. */
  379. thisDev->rcvPktOffset += rcvFrameSize;
  380. }
  381. }
  382. else if (thisDev->rcvPktOffset + rcvFrameSize > EndOfData && !(frameStat&0x40))
  383. {
  384. DBGERR(("Packet won't fit in received data!\n"));
  385. DBGERR(("rcvPktOffset:%x rcvFrameSize:%x LastReadDmaCount:%x\n",
  386. thisDev->rcvPktOffset,
  387. rcvFrameSize,
  388. LastReadDMACount));
  389. DBGERR(("rcvDmaOffset:%x rcvDmaSize:%x EndOfData:%x\n",
  390. thisDev->rcvDmaOffset, thisDev->rcvDmaSize, EndOfData));
  391. // This packet will actually show up at the beginning of the
  392. // *next* DMA. We have inadvertently read the status early.
  393. // Save it for next time and get out.
  394. break;
  395. }
  396. else {
  397. DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: *** >>> FIR_DeliverFrames DMA offset 0x%x:\n",
  398. thisDev->rcvDmaOffset));
  399. NewFrame = thisDev->portInfo.dmaReadBuf +
  400. thisDev->rcvPktOffset;
  401. /* Step offset for next buffer. */
  402. thisDev->rcvPktOffset += rcvFrameSize;
  403. ASSERT(thisDev->rcvPktOffset < RCV_DMA_SIZE);
  404. /* Chop off FCS */
  405. rcvFrameSize -= fcsSize;
  406. if (rcvFrameSize <= MAX_NDIS_DATA_SIZE &&
  407. rcvFrameSize >= IR_ADDR_SIZE + IR_CONTROL_SIZE)
  408. {
  409. //
  410. // Queue this rcv packet. Move Newframe pointer
  411. // into RxDMA buffer.
  412. //
  413. RegStats.ReceivedPackets++;
  414. RegStats.RxWindow++;
  415. QueueReceivePacket(thisDev, NewFrame, rcvFrameSize, TRUE);
  416. }
  417. else {
  418. LOG("Error: invalid packet size "
  419. "in FIR_DeliverFrames", rcvFrameSize);
  420. DEBUGFIR(DBG_RX|DBG_ERR, ("NSC: invalid packet size in FIR_DeliverFrames; %xh > %xh\n", rcvFrameSize, MAX_RCV_DATA_SIZE));
  421. //
  422. // Discard the rest of the packets.
  423. //
  424. while (SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 5, 5)&0x80)
  425. {
  426. SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 5, 6);
  427. SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 5, 7);
  428. }
  429. thisDev->DiscardNextPacketSet = TRUE;
  430. }
  431. }
  432. SyncGetFifoStatus(
  433. &thisDev->interruptObj,
  434. thisDev->portInfo.ioBase,
  435. &frameStat,
  436. &rcvFrameSize
  437. );
  438. LOG("frameStat: ", (UINT) frameStat);
  439. DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: frameStat = %xh\n", (UINT) frameStat));
  440. // Clear the line status register, of any past events.
  441. thisDev->LineStatus =
  442. SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 0, 5);
  443. }
  444. thisDev->FirIntMask = 0x04;
  445. SetupRecv(thisDev);
  446. LOG("<== FIR_DeliverFrames", 1);
  447. DEBUGFIR(DBG_RX|DBG_OUT, ("NSC: <== FIR_DeliverFrames\n"));
  448. }
  449. BOOLEAN NSC_Setup(IrDevice *thisDev)
  450. {
  451. NDIS_DMA_DESCRIPTION DMAChannelDcr;
  452. NDIS_STATUS stat;
  453. thisDev->rcvDmaOffset = 0;
  454. /*
  455. * Because we enable rcv DMA while SIR receives may still be
  456. * going on, we need to keep a separate receive buffer for DMA.
  457. * This buffer gets swapped with the rcvBuffer data pointer
  458. * and must be the same size.
  459. */
  460. thisDev->portInfo.dmaReadBuf = MyMemAlloc(RCV_DMA_SIZE, TRUE);
  461. if (!thisDev->portInfo.dmaReadBuf){
  462. return FALSE;
  463. }
  464. NdisAllocateBufferPool(&stat, &thisDev->dmaBufferPoolHandle, 2);
  465. if (stat != NDIS_STATUS_SUCCESS){
  466. LOG("Error: NdisAllocateBufferPool failed in NSC_Setup", 0);
  467. DEBUGFIR(DBG_ERR, ("NSC: NdisAllocateBufferPool failed in NSC_Setup\n"));
  468. return FALSE;
  469. }
  470. NdisAllocateBuffer(&stat, &thisDev->rcvDmaBuffer,
  471. thisDev->dmaBufferPoolHandle,
  472. thisDev->portInfo.dmaReadBuf,
  473. RCV_DMA_SIZE);
  474. if (stat != NDIS_STATUS_SUCCESS) {
  475. LOG("Error: NdisAllocateBuffer failed (rcv) in NSC_Setup", 0);
  476. DEBUGFIR(DBG_ERR, ("NSC: NdisAllocateBuffer failed (rcv) in NSC_Setup\n"));
  477. return FALSE;
  478. }
  479. NdisAllocateBuffer(&stat, &thisDev->xmitDmaBuffer,
  480. thisDev->dmaBufferPoolHandle,
  481. thisDev->portInfo.writeBuf,
  482. MAX_IRDA_DATA_SIZE);
  483. if (stat != NDIS_STATUS_SUCCESS) {
  484. LOG("NdisAllocateBuffer failed (xmit) in NSC_Setup", 0);
  485. DEBUGFIR(DBG_ERR, ("NSC: NdisAllocateBuffer failed (xmit) in NSC_Setup\n"));
  486. return FALSE;
  487. }
  488. /*
  489. * Initialize rcv DMA channel
  490. */
  491. DMAChannelDcr.DemandMode = TRUE;
  492. DMAChannelDcr.AutoInitialize = FALSE;
  493. DMAChannelDcr.DmaChannelSpecified = FALSE;
  494. DMAChannelDcr.DmaWidth = Width8Bits;
  495. DMAChannelDcr.DmaSpeed = Compatible;
  496. DMAChannelDcr.DmaPort = 0;
  497. DMAChannelDcr.DmaChannel = thisDev->portInfo.DMAChannel; // 0;
  498. stat = NdisMRegisterDmaChannel(&thisDev->DmaHandle,
  499. thisDev->ndisAdapterHandle,
  500. thisDev->portInfo.DMAChannel,
  501. FALSE, &DMAChannelDcr, RCV_DMA_SIZE);
  502. if (stat != NDIS_STATUS_SUCCESS) {
  503. DEBUGFIR(DBG_ERR, ("NSC: NdisMRegisterDmaChannel failed\n"));
  504. DbgBreakPoint();
  505. return FALSE;
  506. }
  507. InitializeDmaUtil(
  508. &thisDev->DmaUtil,
  509. thisDev->DmaHandle
  510. );
  511. return TRUE;
  512. }
  513. void NSC_Shutdown(IrDevice *thisDev)
  514. {
  515. if (thisDev->DmaHandle){
  516. NdisMDeregisterDmaChannel(thisDev->DmaHandle);
  517. thisDev->DmaHandle = NULL;
  518. }
  519. if (thisDev->xmitDmaBuffer){
  520. NdisFreeBuffer( thisDev->xmitDmaBuffer);
  521. thisDev->xmitDmaBuffer = NULL;
  522. }
  523. if (thisDev->rcvDmaBuffer){
  524. NdisFreeBuffer(thisDev->rcvDmaBuffer);
  525. thisDev->rcvDmaBuffer = NULL;
  526. }
  527. if (thisDev->dmaBufferPoolHandle){
  528. NdisFreeBufferPool(thisDev->dmaBufferPoolHandle);
  529. thisDev->dmaBufferPoolHandle = NULL;
  530. }
  531. if (thisDev->portInfo.dmaReadBuf){
  532. MyMemFree(thisDev->portInfo.dmaReadBuf, RCV_DMA_SIZE, TRUE);
  533. thisDev->portInfo.dmaReadBuf = NULL;
  534. }
  535. }
  536. BOOLEAN NdisToFirPacket(IrDevice *thisDev, PNDIS_PACKET Packet,
  537. UCHAR *irPacketBuf, UINT irPacketBufLen, UINT *irPacketLen)
  538. {
  539. PNDIS_BUFFER ndisBuf;
  540. UINT ndisPacketBytes = 0;
  541. UINT ndisPacketLen;
  542. LOG("==> NdisToFirPacket", 0);
  543. DEBUGFIR(DBG_OUT, ("NSC: ==> NdisToFirPacket(0x%x)\n", thisDev));
  544. /*
  545. * Get the packet's entire length and its first NDIS buffer
  546. */
  547. NdisQueryPacket(Packet, NULL, NULL, &ndisBuf, &ndisPacketLen);
  548. LOG("NdisToFirPacket, number of bytes:", ndisPacketLen);
  549. DEBUGFIR(DBG_OUT, ("NSC: NdisToFirPacket, number of bytes: %d\n", ndisPacketLen));
  550. /*
  551. * Make sure that the packet is big enough to be legal.
  552. * It consists of an A, C, and variable-length I field.
  553. */
  554. if (ndisPacketLen < IR_ADDR_SIZE + IR_CONTROL_SIZE){
  555. LOG("Error: packet too short in ", ndisPacketLen);
  556. DEBUGFIR(DBG_ERR, ("NSC: packet too short in NdisToFirPacket (%d bytes)\n", ndisPacketLen));
  557. return FALSE;
  558. }
  559. /*
  560. * Make sure that we won't overwrite our contiguous buffer.
  561. */
  562. if (ndisPacketLen > irPacketBufLen){
  563. /*
  564. * The packet is too large
  565. * Tell the caller to retry with a packet size large
  566. * enough to get past this stage next time.
  567. */
  568. LOG("Error: packet too large in ", ndisPacketLen);
  569. DEBUGFIR(DBG_ERR, ("NSC: Packet too large in NdisToIrPacket (%d=%xh bytes), MAX_IRDA_DATA_SIZE=%d, irPacketBufLen=%d.\n",
  570. ndisPacketLen, ndisPacketLen, MAX_IRDA_DATA_SIZE, irPacketBufLen));
  571. *irPacketLen = ndisPacketLen;
  572. return FALSE;
  573. }
  574. /*
  575. * Read the NDIS packet into a contiguous buffer.
  576. * We have to do this in two steps so that we can compute the
  577. * FCS BEFORE applying escape-byte transparency.
  578. */
  579. while (ndisBuf) {
  580. UCHAR *bufData;
  581. UINT bufLen;
  582. NdisQueryBuffer(ndisBuf, (PVOID *)&bufData, &bufLen);
  583. if (bufData==NULL || (ndisPacketBytes + bufLen > ndisPacketLen)){
  584. /*
  585. * Packet was corrupt -- it misreported its size.
  586. */
  587. *irPacketLen = 0;
  588. ASSERT(0);
  589. return FALSE;
  590. }
  591. NdisMoveMemory((PVOID)(irPacketBuf+ndisPacketBytes),
  592. (PVOID)bufData, (ULONG)bufLen);
  593. ndisPacketBytes += bufLen;
  594. NdisGetNextBuffer(ndisBuf, &ndisBuf);
  595. }
  596. LOG("Ir Command byte ", (UINT)*(irPacketBuf+1));
  597. /*
  598. * Do a sanity check on the length of the packet.
  599. */
  600. if (ndisPacketBytes != ndisPacketLen){
  601. /*
  602. * Packet was corrupt -- it misreported its size.
  603. */
  604. LOG("Error: Packet corrupt in NdisToIrPacket "
  605. "(buffer lengths don't add up to packet length)", 0);
  606. DEBUGFIR(DBG_ERR, ("NSC: Packet corrupt in NdisToIrPacket (buffer lengths don't add up to packet length).\n"));
  607. *irPacketLen = 0;
  608. return FALSE;
  609. }
  610. #ifdef DBG_ADD_PKT_ID
  611. if (addPktIdOn){
  612. static USHORT uniqueId = 0;
  613. DEBUGFIR(DBG_OUT, ("NSC: *** --> SEND PKT ID: %xh\n", (UINT)uniqueId));
  614. LOG("ID: Send (FIR) Pkt id:", uniqueId);
  615. *(USHORT *)(irPacketBuf+ndisPacketBytes) = uniqueId++;
  616. ndisPacketBytes += sizeof(USHORT);
  617. }
  618. #endif
  619. *irPacketLen = ndisPacketBytes;
  620. LOG("<== NdisToFirPacket", 0);
  621. DEBUGFIR(DBG_OUT, ("NSC: <== NdisToFirPacket\n"));
  622. return TRUE;
  623. }