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.

2475 lines
74 KiB

  1. /*
  2. ************************************************************************
  3. *
  4. * NSC.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 "nsc.tmh"
  17. /*
  18. * We keep a linked list of device objects
  19. */
  20. /* This fuction sets up the device for Recv */
  21. void SetupRecv(IrDevice *thisDev);
  22. //
  23. // Debug Counters
  24. //
  25. DebugCounters RegStats = {0,0,0,0,0,0,0,0,0};
  26. ULONG DebugSpeed=0;
  27. #ifdef RECEIVE_PACKET_LOGGING
  28. typedef struct {
  29. UCHAR Data[12];
  30. } DATA_BITS;
  31. typedef struct {
  32. USHORT Tag;
  33. USHORT Line;
  34. union {
  35. struct {
  36. PNDIS_PACKET Packet;
  37. PVOID DmaBuffer;
  38. ULONG Length;
  39. } Packet;
  40. struct {
  41. PLIST_ENTRY Head;
  42. PLIST_ENTRY Entry;
  43. } List;
  44. struct {
  45. PVOID Start;
  46. ULONG Offset;
  47. ULONG Length;
  48. } Dma;
  49. struct {
  50. ULONG Length;
  51. } Discard;
  52. DATA_BITS Data;
  53. };
  54. } RCV_LOG;
  55. #define CHAIN_PACKET_TAG 'CP'
  56. #define UNCHAIN_PACKET_TAG 'UP'
  57. #define ADD_HEAD_LIST_TAG 'HA'
  58. #define ADD_TAIL_LIST_TAG 'TA'
  59. #define REMOVE_HEAD_LIST_TAG 'HR'
  60. #define REMOVE_ENTRY_TAG 'ER'
  61. #define DMA_TAG 'MD'
  62. #define DATA_TAG 'AD'
  63. #define DATA2_TAG '2D'
  64. #define DISCARD_TAG 'XX'
  65. #define NUM_RCV_LOG 256
  66. ULONG RcvLogIndex = 0;
  67. RCV_LOG RcvLog[NUM_RCV_LOG];
  68. BOOLEAN SyncGetRcvLogEntry(PVOID Context)
  69. {
  70. *(ULONG*)Context = RcvLogIndex++;
  71. RcvLogIndex &= NUM_RCV_LOG-1;
  72. return TRUE;
  73. }
  74. ULONG GetRcvLogEntry(IrDevice *thisDev)
  75. {
  76. ULONG Entry;
  77. NdisAcquireSpinLock(&thisDev->QueueLock);
  78. NdisMSynchronizeWithInterrupt(&thisDev->interruptObj, SyncGetRcvLogEntry, &Entry);
  79. NdisReleaseSpinLock(&thisDev->QueueLock);
  80. return Entry;
  81. }
  82. #define LOG_InsertHeadList(d, h, e) \
  83. { \
  84. ULONG i = GetRcvLogEntry(d); \
  85. RcvLog[i].Tag = ADD_HEAD_LIST_TAG; \
  86. RcvLog[i].Line = __LINE__; \
  87. RcvLog[i].List.Head = (h); \
  88. RcvLog[i].List.Entry = (PLIST_ENTRY)(e); \
  89. }
  90. #define LOG_InsertTailList(d, h, e) \
  91. { \
  92. ULONG i = GetRcvLogEntry(d); \
  93. RcvLog[i].Tag = ADD_TAIL_LIST_TAG; \
  94. RcvLog[i].Line = __LINE__; \
  95. RcvLog[i].List.Head = (h); \
  96. RcvLog[i].List.Entry = (PLIST_ENTRY)(e); \
  97. }
  98. #define LOG_RemoveHeadList(d, h, e) \
  99. { \
  100. ULONG i = GetRcvLogEntry(d); \
  101. RcvLog[i].Tag = REMOVE_HEAD_LIST_TAG; \
  102. RcvLog[i].Line = __LINE__; \
  103. RcvLog[i].List.Head = (h); \
  104. RcvLog[i].List.Entry = (PLIST_ENTRY)(e); \
  105. }
  106. #define LOG_RemoveEntryList(d, e) \
  107. { \
  108. ULONG i = GetRcvLogEntry(d); \
  109. RcvLog[i].Tag = REMOVE_ENTRY_TAG; \
  110. RcvLog[i].Line = __LINE__; \
  111. RcvLog[i].List.Head = NULL; \
  112. RcvLog[i].List.Entry = (PLIST_ENTRY)(e); \
  113. }
  114. #define LOG_PacketChain(d, p) \
  115. { \
  116. PNDIS_BUFFER NdisBuffer; \
  117. PVOID Address; \
  118. ULONG Len; \
  119. ULONG i = GetRcvLogEntry(d); \
  120. RcvLog[i].Tag = CHAIN_PACKET_TAG; \
  121. RcvLog[i].Line = __LINE__; \
  122. NdisQueryPacket((p), NULL, NULL, &NdisBuffer, NULL); \
  123. NdisQueryBufferSafe(NdisBuffer, &Address, &Len,NormalPagePriority); \
  124. RcvLog[i].Packet.Packet = (p); \
  125. RcvLog[i].Packet.DmaBuffer = Address; \
  126. RcvLog[i].Packet.Length = Len; \
  127. }
  128. #define LOG_PacketUnchain(d, p) \
  129. { \
  130. PNDIS_BUFFER NdisBuffer; \
  131. PVOID Address; \
  132. ULONG Len; \
  133. ULONG i = GetRcvLogEntry(d); \
  134. RcvLog[i].Tag = UNCHAIN_PACKET_TAG; \
  135. RcvLog[i].Line = __LINE__; \
  136. NdisQueryPacket((p), NULL, NULL, &NdisBuffer, NULL); \
  137. NdisQueryBufferSafe(NdisBuffer, &Address, &Len,NormalPagePriority); \
  138. RcvLog[i].Packet.Packet = (p); \
  139. RcvLog[i].Packet.DmaBuffer = Address; \
  140. RcvLog[i].Packet.Length = Len; \
  141. }
  142. #define LOG_Dma(d) \
  143. { \
  144. ULONG i = GetRcvLogEntry(d); \
  145. RcvLog[i].Tag = DMA_TAG; \
  146. RcvLog[i].Line = __LINE__; \
  147. RcvLog[i].Dma.Start = (d)->rcvDmaBuffer; \
  148. RcvLog[i].Dma.Offset = (d)->rcvDmaOffset; \
  149. RcvLog[i].Dma.Length = (d)->rcvDmaSize; \
  150. }
  151. #define LOG_Data(d,s) \
  152. { \
  153. ULONG i = GetRcvLogEntry(d); \
  154. RcvLog[i].Tag = DATA_TAG; \
  155. RcvLog[i].Line = ((USHORT)(s))&0xffff; \
  156. RcvLog[i].Data = *(DATA_BITS*)(s); \
  157. }
  158. #define LOG_Data2(d,s) \
  159. { \
  160. ULONG i = GetRcvLogEntry(d); \
  161. RcvLog[i].Tag = DATA2_TAG; \
  162. RcvLog[i].Line = ((USHORT)(s))&0xffff; \
  163. RcvLog[i].Data = *(DATA_BITS*)(s); \
  164. }
  165. #define LOG_Discard(d,s) \
  166. { \
  167. ULONG i = GetRcvLogEntry(d); \
  168. RcvLog[i].Tag = DISCARD_TAG; \
  169. RcvLog[i].Line = __LINE__; \
  170. RcvLog[i].Discard.Length = (s); \
  171. }
  172. void DumpNdisPacket(PNDIS_PACKET Packet, UINT Line)
  173. {
  174. UINT PhysBufCnt, BufCnt, TotLen, Len;
  175. PNDIS_BUFFER NdisBuffer;
  176. PVOID Address;
  177. DbgPrint("Badly formed NDIS packet at line %d\n", Line);
  178. NdisQueryPacket(Packet, &PhysBufCnt, &BufCnt, &NdisBuffer, &TotLen);
  179. DbgPrint("Packet:%08X PhysBufCnt:%d BufCnt:%d TotLen:%d\n",
  180. Packet, PhysBufCnt, BufCnt, TotLen);
  181. while (NdisBuffer)
  182. {
  183. NdisQueryBufferSafe(NdisBuffer, &Address, &Len,NormalPagePriority);
  184. DbgPrint(" Buffer:%08X Address:%08X Length:%d\n",
  185. NdisBuffer, Address, Len);
  186. NdisGetNextBuffer(NdisBuffer, &NdisBuffer);
  187. }
  188. ASSERT(0);
  189. }
  190. #define VerifyNdisPacket(p, b) \
  191. { \
  192. UINT BufCnt; \
  193. \
  194. NdisQueryPacket((p), NULL, &BufCnt, NULL, NULL); \
  195. if (BufCnt>(b)) \
  196. { \
  197. DumpNdisPacket((p), __LINE__); \
  198. } \
  199. }
  200. #else
  201. #define VerifyNdisPacket(p,b)
  202. #define LOG_InsertHeadList(d, h, e)
  203. #define LOG_InsertTailList(d, h, e)
  204. #define LOG_RemoveHeadList(d, h, e)
  205. #define LOG_RemoveEntryList(d, e)
  206. #define LOG_PacketChain(d, p)
  207. #define LOG_PacketUnchain(d, p)
  208. #define LOG_Dma(d)
  209. #define LOG_Data(d,s)
  210. #define LOG_Data2(d,s)
  211. #define LOG_Discard(d,s)
  212. #endif
  213. BOOLEAN
  214. VerifyHardware(
  215. IrDevice *thisDev
  216. );
  217. /*
  218. *************************************************************************
  219. * MiniportCheckForHang
  220. *************************************************************************
  221. *
  222. * Reports the state of the network interface card.
  223. *
  224. */
  225. BOOLEAN MiniportCheckForHang(NDIS_HANDLE MiniportAdapterContext)
  226. {
  227. IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
  228. // LOG("==> MiniportCheckForHang");
  229. DBGOUT(("==> MiniportCheckForHang(0x%x)", MiniportAdapterContext));
  230. // We have seen cases where we hang sending at high speeds. This occurs only
  231. // on very old revisions of the NSC hardware.
  232. // This is an attempt to kick us off again.
  233. NdisDprAcquireSpinLock(&thisDev->QueueLock);
  234. if (thisDev->FirTransmitPending) {
  235. switch (thisDev->HangChk)
  236. {
  237. case 0:
  238. break;
  239. default:
  240. DBGERR(("NSCIRDA: CheckForHang--we appear hung\n"));
  241. LOG_ERROR("CheckForHang--we appear hung\n");
  242. // Issue a soft reset to the transmitter & receiver.
  243. SyncWriteBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 0, 2, 0x06);
  244. //
  245. // turn the timer on and let it gnerate an interrupt
  246. //
  247. thisDev->FirIntMask = 0x90;
  248. SyncWriteBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 4, 2, 0x01);
  249. SyncSetInterruptMask(thisDev, TRUE);
  250. break;
  251. }
  252. thisDev->HangChk++;
  253. }
  254. NdisDprReleaseSpinLock(&thisDev->QueueLock);
  255. // LOG("<== MiniportCheckForHang");
  256. DBGOUT(("<== MiniportCheckForHang(0x%x)", MiniportAdapterContext));
  257. return FALSE;
  258. }
  259. /*
  260. *************************************************************************
  261. * MiniportHalt
  262. *************************************************************************
  263. *
  264. * Halts the network interface card.
  265. *
  266. */
  267. VOID MiniportHalt(IN NDIS_HANDLE MiniportAdapterContext)
  268. {
  269. IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
  270. LOG("==> MiniportHalt");
  271. DBGOUT(("==> MiniportHalt(0x%x)", MiniportAdapterContext));
  272. thisDev->hardwareStatus = NdisHardwareStatusClosing;
  273. NdisAcquireSpinLock(&thisDev->QueueLock);
  274. thisDev->Halting=TRUE;
  275. if (thisDev->PacketsSentToProtocol > 0) {
  276. //
  277. // wait for all the packets to come back from the protocol
  278. //
  279. NdisReleaseSpinLock(&thisDev->QueueLock);
  280. NdisWaitEvent(&thisDev->ReceiveStopped, 1*60*1000);
  281. NdisAcquireSpinLock(&thisDev->QueueLock);
  282. }
  283. if (!thisDev->TransmitIsIdle) {
  284. //
  285. // wait for all the packets to be transmitted
  286. //
  287. NdisReleaseSpinLock(&thisDev->QueueLock);
  288. NdisWaitEvent(&thisDev->SendStoppedOnHalt,1*60*1000);
  289. NdisAcquireSpinLock(&thisDev->QueueLock);
  290. }
  291. if (thisDev->FirReceiveDmaActive) {
  292. thisDev->FirReceiveDmaActive=FALSE;
  293. //
  294. // receive dma is running, stop it
  295. //
  296. CompleteDmaTransferFromDevice(
  297. &thisDev->DmaUtil
  298. );
  299. }
  300. //
  301. // which back to SIR mode
  302. //
  303. CloseCOM(thisDev);
  304. SyncSetInterruptMask(thisDev, FALSE);
  305. NdisReleaseSpinLock(&thisDev->QueueLock);
  306. //
  307. // release the interrupt
  308. //
  309. NdisMDeregisterInterrupt(&thisDev->interruptObj);
  310. #if DBG
  311. NdisZeroMemory(&thisDev->interruptObj,sizeof(thisDev->interruptObj));
  312. #endif
  313. //
  314. // release fir related resources including dma channel
  315. //
  316. NSC_Shutdown(thisDev);
  317. //
  318. // release sir related buffers
  319. //
  320. DoClose(thisDev);
  321. if (thisDev->portInfo.ConfigIoBasePhysAddr) {
  322. NdisMDeregisterIoPortRange(thisDev->ndisAdapterHandle,
  323. thisDev->portInfo.ConfigIoBasePhysAddr,
  324. 2,
  325. (PVOID)thisDev->portInfo.ConfigIoBaseAddr);
  326. }
  327. NdisMDeregisterIoPortRange(thisDev->ndisAdapterHandle,
  328. thisDev->portInfo.ioBasePhys,
  329. ((thisDev->CardType==PUMA108)?16:8),
  330. (PVOID)thisDev->portInfo.ioBase);
  331. //
  332. // free the device block
  333. //
  334. FreeDevice(thisDev);
  335. LOG("<== MiniportHalt");
  336. DBGOUT(("<== MiniportHalt(0x%x)", MiniportAdapterContext));
  337. }
  338. void InterlockedInsertBufferSorted(PLIST_ENTRY Head,
  339. rcvBuffer *rcvBuf,
  340. PNDIS_SPIN_LOCK Lock)
  341. {
  342. PLIST_ENTRY ListEntry;
  343. NdisAcquireSpinLock(Lock);
  344. if (IsListEmpty(Head))
  345. {
  346. InsertHeadList(Head, &rcvBuf->listEntry);
  347. }
  348. else
  349. {
  350. BOOLEAN EntryInserted = FALSE;
  351. for (ListEntry = Head->Flink;
  352. ListEntry != Head;
  353. ListEntry = ListEntry->Flink)
  354. {
  355. rcvBuffer *temp = CONTAINING_RECORD(ListEntry,
  356. rcvBuffer,
  357. listEntry);
  358. if (temp->dataBuf > rcvBuf->dataBuf)
  359. {
  360. // We found one that comes after ours.
  361. // We need to insert before it
  362. InsertTailList(ListEntry, &rcvBuf->listEntry);
  363. EntryInserted = TRUE;
  364. break;
  365. }
  366. }
  367. if (!EntryInserted)
  368. {
  369. // We didn't find an entry on the last who's address was later
  370. // than our buffer. We go at the end.
  371. InsertTailList(Head, &rcvBuf->listEntry);
  372. }
  373. }
  374. NdisReleaseSpinLock(Lock);
  375. }
  376. /*
  377. *************************************************************************
  378. * DeliverFullBuffers
  379. *************************************************************************
  380. *
  381. * Deliver received packets to the protocol.
  382. * Return TRUE if delivered at least one frame.
  383. *
  384. */
  385. VOID
  386. DeliverFullBuffers(IrDevice *thisDev)
  387. {
  388. PLIST_ENTRY ListEntry;
  389. LOG("==> DeliverFullBuffers");
  390. DBGOUT(("==> DeliverFullBuffers(0x%x)", thisDev));
  391. /*
  392. * Deliver all full rcv buffers
  393. */
  394. for (
  395. ListEntry = NDISSynchronizedRemoveHeadList(&thisDev->rcvBufFull,
  396. &thisDev->interruptObj);
  397. ListEntry;
  398. ListEntry = NDISSynchronizedRemoveHeadList(&thisDev->rcvBufFull,
  399. &thisDev->interruptObj)
  400. )
  401. {
  402. rcvBuffer *rcvBuf = CONTAINING_RECORD(ListEntry,
  403. rcvBuffer,
  404. listEntry);
  405. NDIS_STATUS stat;
  406. PNDIS_BUFFER packetBuf;
  407. SLOW_IR_FCS_TYPE fcs;
  408. VerifyNdisPacket(rcvBuf->packet, 0);
  409. if (thisDev->currentSpeed <= MAX_SIR_SPEED) {
  410. /*
  411. * The packet we have already has had BOFs,
  412. * EOF, and * escape-sequences removed. It
  413. * contains an FCS code at the end, which we
  414. * need to verify and then remove before
  415. * delivering the frame. We compute the FCS
  416. * on the packet with the packet FCS attached;
  417. * this should produce the constant value
  418. * GOOD_FCS.
  419. */
  420. fcs = ComputeFCS(rcvBuf->dataBuf,
  421. rcvBuf->dataLen);
  422. if (fcs != GOOD_FCS) {
  423. /*
  424. * FCS Error. Drop this frame.
  425. */
  426. LOG("Error: Bad FCS in DeliverFullBuffers %x", fcs);
  427. DBGERR(("Bad FCS in DeliverFullBuffers 0x%x!=0x%x.",
  428. (UINT)fcs, (UINT) GOOD_FCS));
  429. rcvBuf->state = STATE_FREE;
  430. DBGSTAT(("Dropped %d/%d pkts; BAD FCS (%xh!=%xh):",
  431. ++thisDev->packetsDropped,
  432. thisDev->packetsDropped +
  433. thisDev->packetsRcvd, fcs,
  434. GOOD_FCS));
  435. DBGPRINTBUF(rcvBuf->dataBuf,
  436. rcvBuf->dataLen);
  437. if (!rcvBuf->isDmaBuf)
  438. {
  439. NDISSynchronizedInsertTailList(&thisDev->rcvBufBuf,
  440. RCV_BUF_TO_LIST_ENTRY(rcvBuf->dataBuf),
  441. &thisDev->interruptObj);
  442. }
  443. rcvBuf->dataBuf = NULL;
  444. rcvBuf->isDmaBuf = FALSE;
  445. VerifyNdisPacket(rcvBuf->packet, 0);
  446. NDISSynchronizedInsertHeadList(&thisDev->rcvBufFree,
  447. &rcvBuf->listEntry,
  448. &thisDev->interruptObj);
  449. //break;
  450. continue;
  451. }
  452. /* Remove the FCS from the end of the packet. */
  453. rcvBuf->dataLen -= SLOW_IR_FCS_SIZE;
  454. }
  455. #ifdef DBG_ADD_PKT_ID
  456. if (addPktIdOn) {
  457. /* Remove dbg packet id. */
  458. USHORT uniqueId;
  459. rcvBuf->dataLen -= sizeof(USHORT);
  460. uniqueId = *(USHORT *)(rcvBuf->dataBuf+
  461. rcvBuf->dataLen);
  462. DBGOUT(("ID: RCVing packet %xh **",
  463. (UINT)uniqueId));
  464. LOG("ID: Rcv Pkt id: %xh", uniqueId);
  465. }
  466. #endif
  467. /*
  468. * The packet array is set up with its NDIS_PACKET.
  469. * Now we need to allocate a single NDIS_BUFFER for
  470. * the NDIS_PACKET and set the NDIS_BUFFER to the
  471. * part of dataBuf that we want to deliver.
  472. */
  473. NdisAllocateBuffer(&stat, &packetBuf,
  474. thisDev->bufferPoolHandle,
  475. (PVOID)rcvBuf->dataBuf, rcvBuf->dataLen);
  476. if (stat != NDIS_STATUS_SUCCESS){
  477. LOG("Error: NdisAllocateBuffer failed");
  478. DBGERR(("NdisAllocateBuffer failed"));
  479. ASSERT(0);
  480. break;
  481. }
  482. VerifyNdisPacket(rcvBuf->packet, 0);
  483. NdisChainBufferAtFront(rcvBuf->packet, packetBuf);
  484. LOG_PacketChain(thisDev, rcvBuf->packet);
  485. VerifyNdisPacket(rcvBuf->packet, 1);
  486. /*
  487. * Fix up some other packet fields.
  488. */
  489. NDIS_SET_PACKET_HEADER_SIZE(rcvBuf->packet,
  490. IR_ADDR_SIZE+IR_CONTROL_SIZE);
  491. DBGPKT(("Indicating rcv packet 0x%x.", rcvBuf->packet));
  492. /*
  493. * Indicate to the protocol that another packet is
  494. * ready. Set the rcv buffer's state to PENDING first
  495. * to avoid a race condition with NDIS's call to the
  496. * return packet handler.
  497. */
  498. NdisAcquireSpinLock(&thisDev->QueueLock);
  499. if (thisDev->Halting) {
  500. //
  501. // the adapter is being halted, stop sending packets up
  502. //
  503. NdisReleaseSpinLock(&thisDev->QueueLock);
  504. if (!rcvBuf->isDmaBuf) {
  505. NDISSynchronizedInsertTailList(&thisDev->rcvBufBuf,
  506. RCV_BUF_TO_LIST_ENTRY(rcvBuf->dataBuf),
  507. &thisDev->interruptObj);
  508. }
  509. rcvBuf->dataBuf = NULL;
  510. rcvBuf->isDmaBuf = FALSE;
  511. VerifyNdisPacket(rcvBuf->packet, 0);
  512. NDISSynchronizedInsertHeadList(&thisDev->rcvBufFree,
  513. &rcvBuf->listEntry,
  514. &thisDev->interruptObj);
  515. //
  516. // free the buffer we chained to the packet
  517. //
  518. packetBuf=NULL;
  519. NdisUnchainBufferAtFront(rcvBuf->packet, &packetBuf);
  520. if (packetBuf){
  521. NdisFreeBuffer(packetBuf);
  522. }
  523. continue;
  524. }
  525. //
  526. // increment the count of packets sent to the protocol
  527. //
  528. NdisInterlockedIncrement(&thisDev->PacketsSentToProtocol);
  529. NdisReleaseSpinLock(&thisDev->QueueLock);
  530. rcvBuf->state = STATE_PENDING;
  531. *(rcvBuffer **)rcvBuf->packet->MiniportReserved = rcvBuf;
  532. InterlockedInsertBufferSorted(
  533. &thisDev->rcvBufPend,
  534. rcvBuf,
  535. &thisDev->QueueLock
  536. );
  537. VerifyNdisPacket(rcvBuf->packet, 1);
  538. LOG_Data2(thisDev, rcvBuf->dataBuf);
  539. NDIS_SET_PACKET_STATUS(rcvBuf->packet,STATUS_SUCCESS);
  540. NdisMIndicateReceivePacket(thisDev->ndisAdapterHandle,
  541. &rcvBuf->packet, 1);
  542. /*
  543. * The packet is being delivered asynchronously.
  544. * Leave the rcv buffer's state as PENDING;
  545. * we'll get a callback when the transfer is
  546. */
  547. LOG("Indicated rcv complete (Async) bytes: %d",
  548. rcvBuf->dataLen);
  549. DBGSTAT(("Rcv Pending. Rcvd %d packets",
  550. ++thisDev->packetsRcvd));
  551. }
  552. LOG("<== DeliverFullBuffers");
  553. DBGOUT(("<== DeliverFullBuffers"));
  554. return ;
  555. }
  556. /*
  557. *************************************************************************
  558. * MiniportHandleInterrupt
  559. *************************************************************************
  560. *
  561. *
  562. * This is the deferred interrupt processing routine (DPC) which is
  563. * optionally called following an interrupt serviced by MiniportISR.
  564. *
  565. */
  566. VOID MiniportHandleInterrupt(NDIS_HANDLE MiniportAdapterContext)
  567. {
  568. IrDevice *thisDev = CONTEXT_TO_DEV( MiniportAdapterContext);
  569. PNDIS_PACKET PacketToComplete=NULL;
  570. NDIS_STATUS PacketStatus=NDIS_STATUS_SUCCESS;
  571. BOOLEAN SpeedChange=FALSE;
  572. LOG("==> MiniportHandleInterrupt");
  573. DBGOUT(("==> MiniportHandleInterrupt(0x%x)", MiniportAdapterContext));
  574. /*
  575. * If we have just started receiving a packet, indicate media-busy
  576. * to the protocol.
  577. */
  578. if (thisDev->mediaBusy && !thisDev->haveIndicatedMediaBusy) {
  579. if (thisDev->currentSpeed > MAX_SIR_SPEED) {
  580. LOG("Error: MiniportHandleInterrupt is in wrong state %d",
  581. thisDev->currentSpeed);
  582. DBGERR(("MiniportHandleInterrupt is in wrong state: speed is 0x%x",
  583. thisDev->currentSpeed));
  584. ASSERT(0);
  585. }
  586. NdisMIndicateStatus(thisDev->ndisAdapterHandle,
  587. NDIS_STATUS_MEDIA_BUSY, NULL, 0);
  588. NdisMIndicateStatusComplete(thisDev->ndisAdapterHandle);
  589. thisDev->haveIndicatedMediaBusy = TRUE;
  590. }
  591. NdisDprAcquireSpinLock(&thisDev->QueueLock);
  592. if (thisDev->currentSpeed > MAX_SIR_SPEED) {
  593. //
  594. // fir speed
  595. //
  596. //
  597. // disable any other
  598. //
  599. thisDev->FirIntMask = 0x00;
  600. if (thisDev->FirTransmitPending) {
  601. ASSERT(thisDev->CurrentPacket != NULL);
  602. thisDev->FirTransmitPending=FALSE;
  603. //
  604. // we seem to be transmitting now
  605. //
  606. {
  607. ULONG CurrentDMACount;
  608. UCHAR BytesInFifo;
  609. ULONG LoopCount=0;
  610. CurrentDMACount = NdisMReadDmaCounter(thisDev->DmaHandle);
  611. if (CurrentDMACount > 0) {
  612. LOG_ERROR("FIR send: Dma Count was not zero: %d\n\n", CurrentDMACount);
  613. #if DBG
  614. DbgPrint("FIR send: Count was not zero: %d\n\n", CurrentDMACount);
  615. #endif
  616. }
  617. //
  618. // see if the fifo is empty yet
  619. //
  620. BytesInFifo=SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, BANK_2, TXFLV_OFFSET) & 0x3f;
  621. if (BytesInFifo > 0) {
  622. LOG_ERROR("FIR send: Bytes still in fifo: %d", BytesInFifo);
  623. while ((BytesInFifo > 0) && (LoopCount < 64)) {
  624. BytesInFifo=SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, BANK_2, TXFLV_OFFSET) & 0x3f;
  625. LoopCount++;
  626. }
  627. LOG_ERROR("FIR send: Bytes still in fifo after loop: %d, loops=%d", BytesInFifo,LoopCount);
  628. }
  629. }
  630. PacketStatus=CompleteDmaTransferToDevice(
  631. &thisDev->DmaUtil
  632. );
  633. if (PacketStatus != NDIS_STATUS_SUCCESS) {
  634. DBGERR(("NdisMCompleteDmaTransfer failed: %d\n", PacketStatus));
  635. #if DBG
  636. DbgBreakPoint();
  637. #endif
  638. }
  639. /*
  640. * Check for Tx underrun.
  641. */
  642. if (SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 0, ASCR_OFFSET) & ASCR_TXUR) {
  643. USHORT TransmitCurrentCount;
  644. //
  645. // for debugging purposes, see where we were in the frame when it stopped
  646. //
  647. TransmitCurrentCount = SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, BANK_4, TFRCCL_OFFSET);
  648. TransmitCurrentCount |= ((USHORT)SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, BANK_4, TFRCCH_OFFSET)) << 8;
  649. //
  650. // reset the fifo's
  651. //
  652. SyncWriteBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 0, 2, 0x07);
  653. //
  654. // clear the tx underrun
  655. //
  656. SyncWriteBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 0, ASCR_OFFSET, ASCR_TXUR);
  657. RegStats.TxUnderruns++;
  658. PacketStatus = NDIS_STATUS_FAILURE;
  659. LOG_ERROR("MiniportDpc: Transmit Underrun: tx current count=%d",TransmitCurrentCount);
  660. DEBUGFIR(DBG_TX|DBG_ERR, ("NSC: FIR_MegaSendComplete: Transmit Underrun\n"));
  661. }
  662. PacketToComplete=thisDev->CurrentPacket;
  663. thisDev->CurrentPacket=NULL;
  664. } else {
  665. if (thisDev->FirReceiveDmaActive) {
  666. FIR_DeliverFrames(thisDev);
  667. } else {
  668. DBGERR(("MiniportHandleInterrupt: fir: not sending and not RX state"));
  669. LOG_ERROR("MiniportHandleInterrupt: fir: not sending and not RX state %02x",thisDev->InterruptStatus);
  670. }
  671. }
  672. } else {
  673. //
  674. // in SIR mode
  675. //
  676. if (thisDev->CurrentPacket != NULL) {
  677. //
  678. //
  679. UINT TransmitComplete=InterlockedExchange(&thisDev->portInfo.IsrDoneWithPacket,0);
  680. if (TransmitComplete) {
  681. PacketToComplete=thisDev->CurrentPacket;
  682. thisDev->CurrentPacket=NULL;
  683. }
  684. }
  685. }
  686. thisDev->setSpeedAfterCurrentSendPacket = FALSE;
  687. if (PacketToComplete != NULL) {
  688. if (thisDev->lastPacketAtOldSpeed == PacketToComplete) {
  689. thisDev->lastPacketAtOldSpeed=NULL;
  690. SpeedChange=TRUE;
  691. DBGERR(("defered set speed\n"));
  692. SetSpeed(thisDev);
  693. }
  694. }
  695. NdisDprReleaseSpinLock(&thisDev->QueueLock);
  696. if (PacketToComplete != NULL) {
  697. ProcessSendQueue(thisDev);
  698. NdisMSendComplete(thisDev->ndisAdapterHandle, PacketToComplete, PacketStatus);
  699. }
  700. //
  701. // send any received packets to irda.sys
  702. //
  703. DeliverFullBuffers(thisDev);
  704. SyncSetInterruptMask(thisDev, TRUE);
  705. LOG("<== MiniportHandleInterrupt");
  706. DBGOUT(("<== MiniportHandleInterrupt"));
  707. }
  708. /*
  709. *************************************************************************
  710. * GetPnPResources
  711. *************************************************************************
  712. *
  713. *
  714. */
  715. BOOLEAN GetPnPResources(IrDevice *thisDev, NDIS_HANDLE WrapperConfigurationContext)
  716. {
  717. NDIS_STATUS stat;
  718. BOOLEAN result = FALSE;
  719. /*
  720. * We should only need 2 adapter resources (2 IO and 1 interrupt),
  721. * but I've seen devices get extra resources.
  722. * So give the NdisMQueryAdapterResources call room for 10 resources.
  723. */
  724. #define RESOURCE_LIST_BUF_SIZE (sizeof(NDIS_RESOURCE_LIST) + (10*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)))
  725. UCHAR buf[RESOURCE_LIST_BUF_SIZE];
  726. PNDIS_RESOURCE_LIST resList = (PNDIS_RESOURCE_LIST)buf;
  727. UINT bufSize = RESOURCE_LIST_BUF_SIZE;
  728. NdisMQueryAdapterResources(&stat, WrapperConfigurationContext, resList, &bufSize);
  729. if (stat == NDIS_STATUS_SUCCESS){
  730. PCM_PARTIAL_RESOURCE_DESCRIPTOR resDesc;
  731. BOOLEAN haveIRQ = FALSE,
  732. haveIOAddr = FALSE,
  733. haveDma = FALSE;
  734. UINT i;
  735. for (resDesc = resList->PartialDescriptors, i = 0;
  736. i < resList->Count;
  737. resDesc++, i++){
  738. switch (resDesc->Type){
  739. case CmResourceTypePort:
  740. if (thisDev->CardType==PC87108 &&
  741. (resDesc->u.Port.Start.LowPart==0xEA ||
  742. resDesc->u.Port.Start.LowPart==0x398 ||
  743. resDesc->u.Port.Start.LowPart==0x150))
  744. {
  745. // This is an eval board and this is the config io base address
  746. thisDev->portInfo.ConfigIoBasePhysAddr = resDesc->u.Port.Start.LowPart;
  747. }
  748. else if (thisDev->CardType==PC87308 &&
  749. (resDesc->u.Port.Start.LowPart==0x2E ||
  750. resDesc->u.Port.Start.LowPart==0x15C))
  751. {
  752. // This is an eval board and this is the config io base address
  753. thisDev->portInfo.ConfigIoBasePhysAddr = resDesc->u.Port.Start.LowPart;
  754. }
  755. else if (thisDev->CardType==PC87338 &&
  756. (resDesc->u.Port.Start.LowPart==0x2E ||
  757. resDesc->u.Port.Start.LowPart==0x398 ||
  758. resDesc->u.Port.Start.LowPart==0x15C))
  759. {
  760. // This is an eval board and this is the config io base address
  761. thisDev->portInfo.ConfigIoBasePhysAddr = resDesc->u.Port.Start.LowPart;
  762. }
  763. else
  764. {
  765. if (haveIOAddr){
  766. /*
  767. * The *PNP0510 chip on the IBM ThinkPad 760EL
  768. * gets an extra IO range assigned to it.
  769. * So only pick up the first IO port range;
  770. * ignore this subsequent one.
  771. */
  772. DBGERR(("Ignoring extra PnP IO base %xh because already using %xh.",
  773. (UINT)resDesc->u.Port.Start.LowPart,
  774. (UINT)thisDev->portInfo.ioBasePhys));
  775. }
  776. else {
  777. thisDev->portInfo.ioBasePhys = resDesc->u.Port.Start.LowPart;
  778. haveIOAddr = TRUE;
  779. DBGOUT(("Got UART IO addr: %xh.", thisDev->portInfo.ioBasePhys));
  780. }
  781. }
  782. break;
  783. case CmResourceTypeInterrupt:
  784. if (haveIRQ){
  785. DBGERR(("Ignoring second PnP IRQ %xh because already using %xh.",
  786. (UINT)resDesc->u.Interrupt.Level, thisDev->portInfo.irq));
  787. }
  788. else {
  789. thisDev->portInfo.irq = resDesc->u.Interrupt.Level;
  790. haveIRQ = TRUE;
  791. DBGOUT(("Got PnP IRQ: %d.", thisDev->portInfo.irq));
  792. }
  793. break;
  794. case CmResourceTypeDma:
  795. if (haveDma){
  796. DBGERR(("Ignoring second DMA address %d because already using %d.",
  797. (UINT)resDesc->u.Dma.Channel, (UINT)thisDev->portInfo.DMAChannel));
  798. }
  799. else {
  800. ASSERT(!(resDesc->u.Dma.Channel&0xffffff00));
  801. thisDev->portInfo.DMAChannel = (UCHAR)resDesc->u.Dma.Channel;
  802. haveDma = TRUE;
  803. DBGOUT(("Got DMA channel: %d.", thisDev->portInfo.DMAChannel));
  804. }
  805. break;
  806. }
  807. }
  808. result = (haveIOAddr && haveIRQ && haveDma);
  809. }
  810. return result;
  811. }
  812. /*
  813. *************************************************************************
  814. * Configure
  815. *************************************************************************
  816. *
  817. * Read configurable parameters out of the system registry.
  818. *
  819. */
  820. BOOLEAN Configure(
  821. IrDevice *thisDev,
  822. NDIS_HANDLE WrapperConfigurationContext
  823. )
  824. {
  825. //
  826. // Status of Ndis calls.
  827. //
  828. NDIS_STATUS Status;
  829. //
  830. // The handle for reading from the registry.
  831. //
  832. NDIS_HANDLE ConfigHandle;
  833. //
  834. // The value read from the registry.
  835. //
  836. PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
  837. //
  838. // String names of all the parameters that will be read.
  839. //
  840. NDIS_STRING CardTypeStr = CARDTYPE;
  841. NDIS_STRING Dongle_A_TypeStr = DONGLE_A_TYPE;
  842. NDIS_STRING Dongle_B_TypeStr = DONGLE_B_TYPE;
  843. NDIS_STRING MaxConnectRateStr = MAXCONNECTRATE;
  844. UINT Valid_DongleTypes[] = VALID_DONGLETYPES;
  845. DBGOUT(("Configure(0x%x)", thisDev));
  846. NdisOpenConfiguration(&Status, &ConfigHandle, WrapperConfigurationContext);
  847. if (Status != NDIS_STATUS_SUCCESS){
  848. DBGERR(("NdisOpenConfiguration failed in Configure()"));
  849. return FALSE;
  850. }
  851. //
  852. // Read Ir108 Configuration I/O base Address
  853. //
  854. //DbgBreakPoint();
  855. NdisReadConfiguration(
  856. &Status,
  857. &ReturnedValue,
  858. ConfigHandle,
  859. &CardTypeStr,
  860. NdisParameterHexInteger
  861. );
  862. if (Status != NDIS_STATUS_SUCCESS){
  863. DBGERR(("NdisReadConfiguration failed in accessing CardType."));
  864. NdisCloseConfiguration(ConfigHandle);
  865. return FALSE;
  866. }
  867. thisDev->CardType = (UCHAR)ReturnedValue->ParameterData.IntegerData;
  868. if (!GetPnPResources(thisDev, WrapperConfigurationContext)){
  869. DBGERR(("GetPnPResources failed\n"));
  870. NdisCloseConfiguration(ConfigHandle);
  871. return FALSE;
  872. }
  873. // Read Dongle type constant Number.
  874. //
  875. NdisReadConfiguration(&Status,
  876. &ReturnedValue,
  877. ConfigHandle,
  878. &Dongle_A_TypeStr,
  879. NdisParameterInteger);
  880. if (Status != NDIS_STATUS_SUCCESS){
  881. DBGERR(("NdisReadConfiguration failed in accessing DongleType (0x%x).",Status));
  882. }
  883. thisDev->DonglesSupported = 1;
  884. thisDev->DongleTypes[0] =
  885. (UCHAR)Valid_DongleTypes[(UCHAR)ReturnedValue->ParameterData.IntegerData];
  886. // Read Dongle type constant Number.
  887. //
  888. NdisReadConfiguration(&Status,
  889. &ReturnedValue,
  890. ConfigHandle,
  891. &Dongle_B_TypeStr,
  892. NdisParameterInteger);
  893. if (Status != NDIS_STATUS_SUCCESS){
  894. DBGERR(("NdisReadConfiguration failed in accessing DongleType (0x%x).",
  895. Status));
  896. }
  897. thisDev->DongleTypes[1] = (UCHAR)Valid_DongleTypes[(UCHAR)ReturnedValue->ParameterData.IntegerData];
  898. thisDev->DonglesSupported++;
  899. // Read MaxConnectRate.
  900. //
  901. NdisReadConfiguration(&Status,
  902. &ReturnedValue,
  903. ConfigHandle,
  904. &MaxConnectRateStr,
  905. NdisParameterInteger);
  906. if (Status != NDIS_STATUS_SUCCESS){
  907. DBGERR(("NdisReadConfiguration failed in accessing MaxConnectRate (0x%x).",Status));
  908. thisDev->AllowedSpeedMask = ALL_IRDA_SPEEDS;
  909. }
  910. else
  911. {
  912. thisDev->AllowedSpeedMask = 0;
  913. switch (ReturnedValue->ParameterData.IntegerData)
  914. {
  915. default:
  916. case 4000000:
  917. thisDev->AllowedSpeedMask |= NDIS_IRDA_SPEED_4M;
  918. case 1152000:
  919. thisDev->AllowedSpeedMask |= NDIS_IRDA_SPEED_1152K;
  920. case 115200:
  921. thisDev->AllowedSpeedMask |= NDIS_IRDA_SPEED_115200;
  922. case 57600:
  923. thisDev->AllowedSpeedMask |= NDIS_IRDA_SPEED_57600;
  924. case 38400:
  925. thisDev->AllowedSpeedMask |= NDIS_IRDA_SPEED_38400;
  926. case 19200:
  927. thisDev->AllowedSpeedMask |= NDIS_IRDA_SPEED_19200;
  928. case 9600:
  929. thisDev->AllowedSpeedMask |= NDIS_IRDA_SPEED_9600 | NDIS_IRDA_SPEED_2400;
  930. break;
  931. }
  932. }
  933. NdisCloseConfiguration(ConfigHandle);
  934. DBGOUT(("Configure done: ConfigIO=0x%x UartIO=0x%x irq=%d DMA=%d",
  935. thisDev->portInfo.ConfigIoBaseAddr,thisDev->portInfo.ioBase,
  936. thisDev->portInfo.irq,thisDev->portInfo.DMAChannel));
  937. return TRUE;
  938. }
  939. /*
  940. *************************************************************************
  941. * MiniportInitialize
  942. *************************************************************************
  943. *
  944. *
  945. * Initializes the network interface card.
  946. *
  947. *
  948. *
  949. */
  950. NDIS_STATUS MiniportInitialize ( PNDIS_STATUS OpenErrorStatus,
  951. PUINT SelectedMediumIndex,
  952. PNDIS_MEDIUM MediumArray,
  953. UINT MediumArraySize,
  954. NDIS_HANDLE NdisAdapterHandle,
  955. NDIS_HANDLE WrapperConfigurationContext
  956. )
  957. {
  958. UINT mediumIndex;
  959. IrDevice *thisDev = NULL;
  960. NDIS_STATUS retStat, result = NDIS_STATUS_SUCCESS;
  961. DBGOUT(("MiniportInitialize()"));
  962. /*
  963. * Search the passed-in array of supported media for the IrDA medium.
  964. */
  965. for (mediumIndex = 0; mediumIndex < MediumArraySize; mediumIndex++){
  966. if (MediumArray[mediumIndex] == NdisMediumIrda){
  967. break;
  968. }
  969. }
  970. if (mediumIndex < MediumArraySize){
  971. *SelectedMediumIndex = mediumIndex;
  972. }
  973. else {
  974. /*
  975. * Didn't see the IrDA medium
  976. */
  977. DBGERR(("Didn't see the IRDA medium in MiniportInitialize"));
  978. result = NDIS_STATUS_UNSUPPORTED_MEDIA;
  979. return result;
  980. }
  981. /*
  982. * Allocate a new device object to represent this connection.
  983. */
  984. thisDev = NewDevice();
  985. if (!thisDev){
  986. return NDIS_STATUS_NOT_ACCEPTED;
  987. }
  988. thisDev->hardwareStatus = NdisHardwareStatusInitializing;
  989. /*
  990. * Allocate resources for this connection.
  991. */
  992. if (!OpenDevice(thisDev)){
  993. DBGERR(("OpenDevice failed"));
  994. result = NDIS_STATUS_FAILURE;
  995. goto _initDone;
  996. }
  997. /*
  998. * Record the NDIS wrapper's handle for this adapter, which we use
  999. * when we call up to the wrapper.
  1000. * (This miniport's adapter handle is just thisDev, the pointer to the device object.).
  1001. */
  1002. DBGOUT(("NDIS handle: %xh <-> IRMINI handle: %xh", NdisAdapterHandle, thisDev));
  1003. thisDev->ndisAdapterHandle = NdisAdapterHandle;
  1004. /*
  1005. * Read the system registry to get parameters like COM port number, etc.
  1006. */
  1007. if (!Configure(thisDev, WrapperConfigurationContext)){
  1008. DBGERR(("Configure failed"));
  1009. result = NDIS_STATUS_FAILURE;
  1010. goto _initDone;
  1011. }
  1012. /*
  1013. * This call will associate our adapter handle with the wrapper's
  1014. * adapter handle. The wrapper will then always use our handle
  1015. * when calling us. We use a pointer to the device object as the context.
  1016. */
  1017. NdisMSetAttributesEx(NdisAdapterHandle,
  1018. (NDIS_HANDLE)thisDev,
  1019. 0,
  1020. NDIS_ATTRIBUTE_DESERIALIZE,
  1021. NdisInterfaceInternal);
  1022. /*
  1023. * Tell NDIS about the range of IO space that we'll be using.
  1024. * Puma uses Chip-select mode, so the ConfigIOBase address actually
  1025. * follows the regular io, so get both in one shot.
  1026. */
  1027. retStat = NdisMRegisterIoPortRange( (PVOID)&thisDev->portInfo.ioBase,
  1028. NdisAdapterHandle,
  1029. thisDev->portInfo.ioBasePhys,
  1030. ((thisDev->CardType==PUMA108)?16:8));
  1031. if (retStat != NDIS_STATUS_SUCCESS){
  1032. DBGERR(("NdisMRegisterIoPortRange failed"));
  1033. thisDev->portInfo.ioBase=NULL;
  1034. result = NDIS_STATUS_FAILURE;
  1035. goto _initDone;
  1036. }
  1037. if (thisDev->portInfo.ConfigIoBasePhysAddr)
  1038. {
  1039. /*
  1040. * Eval boards require a second IO range.
  1041. *
  1042. */
  1043. retStat = NdisMRegisterIoPortRange( (PVOID)&thisDev->portInfo.ConfigIoBaseAddr,
  1044. NdisAdapterHandle,
  1045. thisDev->portInfo.ConfigIoBasePhysAddr,
  1046. 2);
  1047. if (retStat != NDIS_STATUS_SUCCESS){
  1048. DBGERR(("NdisMRegisterIoPortRange config failed"));
  1049. thisDev->portInfo.ConfigIoBaseAddr=NULL;
  1050. result = NDIS_STATUS_FAILURE;
  1051. goto _initDone;
  1052. }
  1053. }
  1054. NdisMSleep(20);
  1055. //
  1056. // Set to Non-Extended mode
  1057. //
  1058. NSC_WriteBankReg(thisDev->portInfo.ioBase, 2, 2, 0x02);
  1059. //
  1060. // set to bank 0
  1061. //
  1062. NdisRawWritePortUchar(thisDev->portInfo.ioBase+LCR_BSR_OFFSET, 03);
  1063. //
  1064. // mask all ints, before attaching interrupt
  1065. //
  1066. NdisRawWritePortUchar(thisDev->portInfo.ioBase+INT_ENABLE_REG_OFFSET, 0);
  1067. /*
  1068. * Register an interrupt with NDIS.
  1069. */
  1070. retStat = NdisMRegisterInterrupt( (PNDIS_MINIPORT_INTERRUPT)&thisDev->interruptObj,
  1071. NdisAdapterHandle,
  1072. thisDev->portInfo.irq,
  1073. thisDev->portInfo.irq,
  1074. TRUE, // want ISR
  1075. TRUE, // MUST share interrupts
  1076. NdisInterruptLatched
  1077. );
  1078. if (retStat != NDIS_STATUS_SUCCESS){
  1079. DBGERR(("NdisMRegisterInterrupt failed"));
  1080. result = NDIS_STATUS_FAILURE;
  1081. goto _initDone;
  1082. }
  1083. thisDev->InterruptRegistered=TRUE;
  1084. {
  1085. LONG VerifyTries=5;
  1086. while (VerifyTries > 0) {
  1087. if (VerifyHardware(thisDev)) {
  1088. break;
  1089. }
  1090. #if DBG
  1091. DbgPrint("NSCIRDA: VerifiyHardware() failed, trying again, tries left=%d\n",VerifyTries);
  1092. #endif
  1093. VerifyTries--;
  1094. }
  1095. if ( VerifyTries == 0) {
  1096. result = NDIS_STATUS_FAILURE;
  1097. goto _initDone;
  1098. }
  1099. }
  1100. /*
  1101. * Open COMM communication channel.
  1102. * This will let the dongle driver update its capabilities from their default values.
  1103. */
  1104. if (!DoOpen(thisDev)){
  1105. DBGERR(("DoOpen failed"));
  1106. result = NDIS_STATUS_FAILURE;
  1107. goto _initDone;
  1108. }
  1109. /*
  1110. * Do special NSC setup
  1111. * (do this after comport resources, like read buf, have been allocated).
  1112. */
  1113. if (!NSC_Setup(thisDev)){
  1114. DBGERR(("NSC_Setup failed"));
  1115. NSC_Shutdown(thisDev);
  1116. result = NDIS_STATUS_FAILURE;
  1117. goto _initDone;
  1118. }
  1119. _initDone:
  1120. if (result == NDIS_STATUS_SUCCESS){
  1121. /*
  1122. * Add this device object to the beginning of our global list.
  1123. */
  1124. thisDev->hardwareStatus = NdisHardwareStatusReady;
  1125. DBGOUT(("MiniportInitialize succeeded"));
  1126. return result;
  1127. }
  1128. //
  1129. // init failed, release the resources
  1130. //
  1131. if (thisDev->InterruptRegistered) {
  1132. NdisMDeregisterInterrupt(&thisDev->interruptObj);
  1133. thisDev->InterruptRegistered=FALSE;
  1134. }
  1135. if (thisDev->portInfo.ioBase != NULL) {
  1136. NdisMDeregisterIoPortRange(
  1137. thisDev->ndisAdapterHandle,
  1138. thisDev->portInfo.ioBasePhys,
  1139. ((thisDev->CardType==PUMA108)?16:8),
  1140. (PVOID)thisDev->portInfo.ioBase
  1141. );
  1142. thisDev->portInfo.ioBase=NULL;
  1143. }
  1144. if (thisDev->portInfo.ConfigIoBaseAddr != NULL) {
  1145. NdisMDeregisterIoPortRange(
  1146. thisDev->ndisAdapterHandle,
  1147. thisDev->portInfo.ConfigIoBasePhysAddr,
  1148. 2,
  1149. (PVOID)thisDev->portInfo.ConfigIoBaseAddr
  1150. );
  1151. thisDev->portInfo.ConfigIoBaseAddr=NULL;
  1152. }
  1153. if (thisDev){
  1154. FreeDevice(thisDev);
  1155. }
  1156. DBGOUT(("MiniportInitialize failed"));
  1157. return result;
  1158. }
  1159. BOOLEAN
  1160. VerifyHardware(
  1161. IrDevice *thisDev
  1162. )
  1163. {
  1164. UCHAR TempValue;
  1165. LONG MilliSecondsToWait=500;
  1166. NdisMSleep(20);
  1167. //
  1168. // set to bank 0
  1169. //
  1170. NdisRawWritePortUchar(thisDev->portInfo.ioBase+LCR_BSR_OFFSET, 03);
  1171. //
  1172. // mask all ints, before attaching interrupt
  1173. //
  1174. NdisRawWritePortUchar(thisDev->portInfo.ioBase+INT_ENABLE_REG_OFFSET, 0);
  1175. NdisRawReadPortUchar(thisDev->portInfo.ioBase+INT_ENABLE_REG_OFFSET,&TempValue);
  1176. if (TempValue != 0) {
  1177. #if DBG
  1178. DbgPrint("NSCIRDA: After masking interrupts IER was not zero %x, base= %x\n",TempValue,thisDev->portInfo.ioBase);
  1179. #endif
  1180. return FALSE;
  1181. }
  1182. //
  1183. // reset the fifo's and enable the fifos
  1184. //
  1185. NdisRawWritePortUchar(thisDev->portInfo.ioBase+INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x7);
  1186. //
  1187. // read the interrupt ident reg, to see if the fifo's enabled
  1188. //
  1189. NdisRawReadPortUchar(thisDev->portInfo.ioBase+INT_ID_AND_FIFO_CNTRL_REG_OFFSET,&TempValue);
  1190. if ((TempValue & 0xc0) != 0xc0) {
  1191. #if DBG
  1192. DbgPrint("NSCIRDA: Fifo's not enabled in iir %x, base= %x\n",TempValue,thisDev->portInfo.ioBase);
  1193. #endif
  1194. return FALSE;
  1195. }
  1196. //
  1197. // bring up DTR and RTS, turn on the out pins
  1198. //
  1199. NdisRawWritePortUchar(thisDev->portInfo.ioBase+MODEM_CONTROL_REG_OFFSET, 0xf);
  1200. thisDev->GotTestInterrupt=FALSE;
  1201. thisDev->TestingInterrupt=TRUE;
  1202. //
  1203. // unmask the transmit holding register so an interrupt will be generated
  1204. //
  1205. NdisRawWritePortUchar(thisDev->portInfo.ioBase+INT_ENABLE_REG_OFFSET, 2);
  1206. while ((thisDev->GotTestInterrupt == FALSE) && (MilliSecondsToWait > 0)) {
  1207. NdisMSleep(1000);
  1208. MilliSecondsToWait--;
  1209. }
  1210. #if DBG
  1211. if (!thisDev->GotTestInterrupt) {
  1212. NdisRawReadPortUchar(thisDev->portInfo.ioBase+INT_ID_AND_FIFO_CNTRL_REG_OFFSET,&TempValue);
  1213. DbgPrint("NSCIRDA: Did not get interrupt while initializing, ier-%x, base= %x\n",TempValue,thisDev->portInfo.ioBase);
  1214. }
  1215. #endif
  1216. //
  1217. // mask all ints again;
  1218. //
  1219. NdisRawWritePortUchar(thisDev->portInfo.ioBase+INT_ENABLE_REG_OFFSET, 0);
  1220. thisDev->TestingInterrupt=FALSE;
  1221. return thisDev->GotTestInterrupt;
  1222. }
  1223. /*
  1224. *************************************************************************
  1225. * QueueReceivePacket
  1226. *************************************************************************
  1227. *
  1228. *
  1229. *
  1230. *
  1231. */
  1232. VOID QueueReceivePacket(IrDevice *thisDev, PUCHAR data, UINT dataLen, BOOLEAN IsFIR)
  1233. {
  1234. rcvBuffer *rcvBuf = NULL;
  1235. PLIST_ENTRY ListEntry;
  1236. /*
  1237. * Note: We cannot use a spinlock to protect the rcv buffer structures
  1238. * in an ISR. This is ok, since we used a sync-with-isr function
  1239. * the the deferred callback routine to access the rcv buffers.
  1240. */
  1241. LOG("==> QueueReceivePacket");
  1242. DBGOUT(("==> QueueReceivePacket(0x%x, 0x%lx, 0x%x)",
  1243. thisDev, data, dataLen));
  1244. LOG("QueueReceivePacket, len: %d ", dataLen);
  1245. if (!IsFIR)
  1246. {
  1247. // This function is called inside the ISR during SIR mode.
  1248. if (IsListEmpty(&thisDev->rcvBufFree))
  1249. {
  1250. ListEntry = NULL;
  1251. }
  1252. else
  1253. {
  1254. ListEntry = RemoveHeadList(&thisDev->rcvBufFree);
  1255. }
  1256. }
  1257. else
  1258. {
  1259. ListEntry = NDISSynchronizedRemoveHeadList(&thisDev->rcvBufFree,
  1260. &thisDev->interruptObj);
  1261. }
  1262. if (ListEntry)
  1263. {
  1264. rcvBuf = CONTAINING_RECORD(ListEntry,
  1265. rcvBuffer,
  1266. listEntry);
  1267. if (IsFIR)
  1268. {
  1269. LOG_Data(thisDev, data);
  1270. }
  1271. }
  1272. if (rcvBuf){
  1273. rcvBuf->dataBuf = data;
  1274. VerifyNdisPacket(rcvBuf->packet, 0);
  1275. rcvBuf->state = STATE_FULL;
  1276. rcvBuf->dataLen = dataLen;
  1277. if (!IsFIR)
  1278. {
  1279. rcvBuf->isDmaBuf = FALSE;
  1280. InsertTailList(&thisDev->rcvBufFull,
  1281. ListEntry);
  1282. }
  1283. else
  1284. {
  1285. rcvBuf->isDmaBuf = TRUE;
  1286. LOG_InsertTailList(thisDev, &thisDev->rcvBufFull, rcvBuf);
  1287. NDISSynchronizedInsertTailList(&thisDev->rcvBufFull,
  1288. ListEntry,
  1289. &thisDev->interruptObj);
  1290. }
  1291. }
  1292. LOG("<== QueueReceivePacket");
  1293. DBGOUT(("<== QueueReceivePacket"));
  1294. }
  1295. /*
  1296. *************************************************************************
  1297. * MiniportISR
  1298. *************************************************************************
  1299. *
  1300. *
  1301. * This is the miniport's interrupt service routine (ISR).
  1302. *
  1303. *
  1304. */
  1305. VOID MiniportISR(PBOOLEAN InterruptRecognized,
  1306. PBOOLEAN QueueMiniportHandleInterrupt,
  1307. NDIS_HANDLE MiniportAdapterContext)
  1308. {
  1309. IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
  1310. if (thisDev->TestingInterrupt) {
  1311. //
  1312. // we are testing to make sure the interrupt works
  1313. //
  1314. UCHAR TempValue;
  1315. //
  1316. // Read the interrupt identification register
  1317. //
  1318. NdisRawReadPortUchar(thisDev->portInfo.ioBase+INT_ID_AND_FIFO_CNTRL_REG_OFFSET,&TempValue);
  1319. //
  1320. // if the low bit is clear then an interrupt is pending
  1321. //
  1322. if ((TempValue & 1) == 0) {
  1323. //
  1324. // inform the test code that we got the interrupt
  1325. //
  1326. thisDev->GotTestInterrupt=TRUE;
  1327. thisDev->TestingInterrupt=FALSE;
  1328. //
  1329. // mask all ints again
  1330. //
  1331. NdisRawWritePortUchar(thisDev->portInfo.ioBase+INT_ENABLE_REG_OFFSET, 0);
  1332. DBGOUT(("NSCIRDA: Got test interrupt %x\n",TempValue))
  1333. *InterruptRecognized=TRUE;
  1334. *QueueMiniportHandleInterrupt=FALSE;
  1335. return;
  1336. }
  1337. //
  1338. // seems that our uart did not generate this interrupt
  1339. //
  1340. *InterruptRecognized=FALSE;
  1341. *QueueMiniportHandleInterrupt=FALSE;
  1342. return;
  1343. }
  1344. //LOG("==> MiniportISR", ++thisDev->interruptCount);
  1345. //DBGOUT(("==> MiniportISR(0x%x), interrupt #%d)", (UINT)thisDev,
  1346. // thisDev->interruptCount));
  1347. #if DBG
  1348. {
  1349. UCHAR TempVal;
  1350. //
  1351. // This code assumes that bank 0 is current, we will make sure of that
  1352. //
  1353. NdisRawReadPortUchar(thisDev->portInfo.ioBase+LCR_BSR_OFFSET, &TempVal);
  1354. ASSERT((TempVal & BKSE) == 0);
  1355. }
  1356. #endif
  1357. /*
  1358. * Service the interrupt.
  1359. */
  1360. if (thisDev->currentSpeed > MAX_SIR_SPEED){
  1361. NSC_FIR_ISR(thisDev, InterruptRecognized,
  1362. QueueMiniportHandleInterrupt);
  1363. }
  1364. else {
  1365. COM_ISR(thisDev, InterruptRecognized,
  1366. QueueMiniportHandleInterrupt);
  1367. }
  1368. LOG("<== MiniportISR");
  1369. DBGOUT(("<== MiniportISR"));
  1370. }
  1371. /*
  1372. *************************************************************************
  1373. * MiniportReset
  1374. *************************************************************************
  1375. *
  1376. *
  1377. * MiniportReset issues a hardware reset to the network interface card.
  1378. * The miniport driver also resets its software state.
  1379. *
  1380. *
  1381. */
  1382. NDIS_STATUS MiniportReset(PBOOLEAN AddressingReset, NDIS_HANDLE MiniportAdapterContext)
  1383. {
  1384. IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
  1385. NDIS_STATUS result = NDIS_STATUS_PENDING;
  1386. LIST_ENTRY TempList;
  1387. BOOLEAN SetSpeedNow=FALSE;
  1388. PNDIS_PACKET Packet;
  1389. DBGERR(("MiniportReset(0x%x)", MiniportAdapterContext));
  1390. InitializeListHead(&TempList);
  1391. NdisAcquireSpinLock(&thisDev->QueueLock);
  1392. thisDev->hardwareStatus = NdisHardwareStatusReset;
  1393. //
  1394. // un-queue all the send packets and put them on a temp list
  1395. //
  1396. while (!IsListEmpty(&thisDev->SendQueue)) {
  1397. PLIST_ENTRY ListEntry;
  1398. ListEntry=RemoveHeadList(&thisDev->SendQueue);
  1399. InsertTailList(&TempList,ListEntry);
  1400. }
  1401. //
  1402. // if there is a current send packet, then request a speed change after it completes
  1403. //
  1404. if (thisDev->CurrentPacket != NULL) {
  1405. //
  1406. // the current packet is now the last, chage speed after it is done
  1407. //
  1408. thisDev->lastPacketAtOldSpeed=thisDev->CurrentPacket;
  1409. } else {
  1410. //
  1411. // no current packet, change speed now
  1412. //
  1413. SetSpeedNow=TRUE;
  1414. }
  1415. //
  1416. // back to 9600
  1417. //
  1418. thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];
  1419. if (SetSpeedNow) {
  1420. //
  1421. // there are no packets being transmitted now, switch speeds now.
  1422. // otherwise the dpc will do it when the current send completes
  1423. //
  1424. SetSpeed(thisDev);
  1425. thisDev->TransmitIsIdle=FALSE;
  1426. }
  1427. NdisReleaseSpinLock(&thisDev->QueueLock);
  1428. if (SetSpeedNow) {
  1429. //
  1430. // the transmit was idle, but we change this to get the receive going again
  1431. //
  1432. ProcessSendQueue(thisDev);
  1433. }
  1434. //
  1435. // return all of these back to the protocol
  1436. //
  1437. while (!IsListEmpty(&TempList)) {
  1438. PLIST_ENTRY ListEntry;
  1439. ListEntry=RemoveHeadList(&TempList);
  1440. Packet= CONTAINING_RECORD(
  1441. ListEntry,
  1442. NDIS_PACKET,
  1443. MiniportReserved
  1444. );
  1445. NdisMSendComplete(thisDev->ndisAdapterHandle, Packet, NDIS_STATUS_RESET_IN_PROGRESS );
  1446. }
  1447. thisDev->hardwareStatus = NdisHardwareStatusReady;
  1448. NdisMResetComplete(thisDev->ndisAdapterHandle,
  1449. NDIS_STATUS_SUCCESS,
  1450. TRUE); // Addressing reset
  1451. *AddressingReset = TRUE;
  1452. DBGOUT(("MiniportReset done."));
  1453. return NDIS_STATUS_PENDING;
  1454. }
  1455. /*
  1456. *************************************************************************
  1457. * ReturnPacketHandler
  1458. *************************************************************************
  1459. *
  1460. * When NdisMIndicateReceivePacket returns asynchronously,
  1461. * the protocol returns ownership of the packet to the miniport via this function.
  1462. *
  1463. */
  1464. VOID ReturnPacketHandler(NDIS_HANDLE MiniportAdapterContext, PNDIS_PACKET Packet)
  1465. {
  1466. IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
  1467. rcvBuffer *rcvBuf;
  1468. LONG PacketsLeft;
  1469. DBGOUT(("ReturnPacketHandler(0x%x)", MiniportAdapterContext));
  1470. RegStats.ReturnPacketHandlerCalled++;
  1471. //
  1472. // MiniportReserved contains the pointer to our rcvBuffer
  1473. //
  1474. rcvBuf = *(rcvBuffer**) Packet->MiniportReserved;
  1475. VerifyNdisPacket(Packet, 1);
  1476. if (rcvBuf->state == STATE_PENDING){
  1477. PNDIS_BUFFER ndisBuf;
  1478. DBGPKT(("Reclaimed rcv packet 0x%x.", Packet));
  1479. LOG_RemoveEntryList(thisDev, rcvBuf);
  1480. NDISSynchronizedRemoveEntryList(&rcvBuf->listEntry, &thisDev->interruptObj);
  1481. LOG_PacketUnchain(thisDev, rcvBuf->packet);
  1482. NdisUnchainBufferAtFront(Packet, &ndisBuf);
  1483. if (ndisBuf){
  1484. NdisFreeBuffer(ndisBuf);
  1485. }
  1486. if (!rcvBuf->isDmaBuf)
  1487. {
  1488. NDISSynchronizedInsertTailList(&thisDev->rcvBufBuf,
  1489. RCV_BUF_TO_LIST_ENTRY(rcvBuf->dataBuf),
  1490. &thisDev->interruptObj);
  1491. // ASSERT the pointer is actually outside our FIR DMA buffer
  1492. ASSERT(rcvBuf->dataBuf < thisDev->dmaReadBuf ||
  1493. rcvBuf->dataBuf >= thisDev->dmaReadBuf+RCV_DMA_SIZE);
  1494. }
  1495. rcvBuf->dataBuf = NULL;
  1496. rcvBuf->state = STATE_FREE;
  1497. VerifyNdisPacket(rcvBuf->packet, 0);
  1498. NDISSynchronizedInsertHeadList(&thisDev->rcvBufFree,
  1499. &rcvBuf->listEntry,
  1500. &thisDev->interruptObj);
  1501. }
  1502. else {
  1503. LOG("Error: Packet in ReturnPacketHandler was not PENDING");
  1504. DBGERR(("Packet in ReturnPacketHandler was not PENDING."));
  1505. }
  1506. NdisAcquireSpinLock(&thisDev->QueueLock);
  1507. PacketsLeft=NdisInterlockedDecrement(&thisDev->PacketsSentToProtocol);
  1508. if (thisDev->Halting && (PacketsLeft == 0)) {
  1509. NdisSetEvent(&thisDev->ReceiveStopped);
  1510. }
  1511. NdisReleaseSpinLock(&thisDev->QueueLock);
  1512. VerifyNdisPacket(rcvBuf->packet, 1);
  1513. }
  1514. VOID
  1515. GivePacketToSirISR(
  1516. IrDevice *thisDev
  1517. )
  1518. {
  1519. thisDev->portInfo.writeComBufferPos = 0;
  1520. thisDev->portInfo.SirWritePending = TRUE;
  1521. thisDev->nowReceiving = FALSE;
  1522. SetCOMPort(thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, XMIT_MODE_INTS_ENABLE);
  1523. }
  1524. VOID
  1525. SendCurrentPacket(
  1526. IrDevice *thisDev
  1527. )
  1528. {
  1529. BOOLEAN Result;
  1530. PNDIS_PACKET FailedPacket=NULL;
  1531. NdisAcquireSpinLock(&thisDev->QueueLock);
  1532. thisDev->TransmitIsIdle=FALSE;
  1533. if (thisDev->CurrentPacket == thisDev->lastPacketAtOldSpeed){
  1534. thisDev->setSpeedAfterCurrentSendPacket = TRUE;
  1535. }
  1536. if (thisDev->currentSpeed > MAX_SIR_SPEED) {
  1537. //
  1538. // send via FIR
  1539. //
  1540. if (thisDev->FirReceiveDmaActive) {
  1541. thisDev->FirReceiveDmaActive=FALSE;
  1542. //
  1543. // receive dma is running, stop it
  1544. //
  1545. CompleteDmaTransferFromDevice(
  1546. &thisDev->DmaUtil
  1547. );
  1548. }
  1549. thisDev->HangChk=0;
  1550. thisDev->FirTransmitPending = TRUE;
  1551. //
  1552. // Use DMA swap bit to switch to DMA to Transmit.
  1553. //
  1554. SyncWriteBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 2, 2, 0x0B);
  1555. //
  1556. // Switch on the DMA interrupt to decide when
  1557. // transmission is complete.
  1558. //
  1559. thisDev->FirIntMask = 0x14;
  1560. SyncSetInterruptMask(thisDev, TRUE);
  1561. //
  1562. // Kick off the first transmit.
  1563. //
  1564. NdisToFirPacket(
  1565. thisDev->CurrentPacket,
  1566. (UCHAR *) thisDev->TransmitDmaBuffer,
  1567. MAX_IRDA_DATA_SIZE,
  1568. &thisDev->TransmitDmaLength
  1569. );
  1570. LOG_FIR("Sending packet %d",thisDev->TransmitDmaLength);
  1571. DEBUGFIR(DBG_PKT, ("NSC: Sending packet\n"));
  1572. DBGPRINTBUF(thisDev->TransmitDmaBuffer,thisDev->TransmitDmaLength);
  1573. {
  1574. UCHAR LsrValue;
  1575. //
  1576. // make sure the transmitter is empty before starting to send this frame
  1577. //
  1578. LsrValue=SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 0, LSR_OFFSET);
  1579. if ((LsrValue & (LSR_TXRDY | LSR_TXEMP)) != (LSR_TXRDY | LSR_TXEMP)) {
  1580. ULONG LoopCount=0;
  1581. while (((LsrValue & (LSR_TXRDY | LSR_TXEMP)) != (LSR_TXRDY | LSR_TXEMP)) && (LoopCount < 16)) {
  1582. LsrValue=SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 0, LSR_OFFSET);
  1583. LoopCount++;
  1584. }
  1585. LOG_ERROR("SendCurrentPacket: Looped %d times waiting for tx empty",LoopCount);
  1586. }
  1587. }
  1588. /* Setup Transmit DMA. */
  1589. StartDmaTransferToDevice(
  1590. &thisDev->DmaUtil,
  1591. thisDev->xmitDmaBuffer,
  1592. 0,
  1593. thisDev->TransmitDmaLength
  1594. );
  1595. #if 0
  1596. {
  1597. ULONG CurrentDMACount;
  1598. CurrentDMACount = NdisMReadDmaCounter(thisDev->DmaHandle);
  1599. LOG("SendCurrentPacket: dma count after start %d",CurrentDMACount);
  1600. }
  1601. #endif
  1602. SyncSetInterruptMask(thisDev, TRUE);
  1603. } else {
  1604. //
  1605. // SIR mode transfer
  1606. //
  1607. /*
  1608. * See if this was the last packet before we need to change
  1609. * speed.
  1610. */
  1611. /*
  1612. * Send one packet to the COMM port.
  1613. */
  1614. DBGPKT(("Sending packet 0x%x (0x%x).", thisDev->packetsSent++, thisDev->CurrentPacket));
  1615. /*
  1616. * Convert the NDIS packet to an IRDA packet.
  1617. */
  1618. Result = NdisToIrPacket(
  1619. thisDev->CurrentPacket,
  1620. (UCHAR *)thisDev->portInfo.writeComBuffer,
  1621. MAX_IRDA_DATA_SIZE,
  1622. &thisDev->portInfo.writeComBufferLen
  1623. );
  1624. if (Result){
  1625. LOG_SIR("Sending packet %d",thisDev->portInfo.writeComBufferLen);
  1626. NdisMSynchronizeWithInterrupt(
  1627. &thisDev->interruptObj,
  1628. GivePacketToSirISR,
  1629. thisDev
  1630. );
  1631. } else {
  1632. ASSERT(0);
  1633. FailedPacket=thisDev->CurrentPacket;
  1634. thisDev->CurrentPacket=NULL;
  1635. }
  1636. }
  1637. NdisReleaseSpinLock(&thisDev->QueueLock);
  1638. if (FailedPacket != NULL) {
  1639. NdisMSendComplete(thisDev->ndisAdapterHandle, FailedPacket, NDIS_STATUS_FAILURE );
  1640. ProcessSendQueue(thisDev);
  1641. }
  1642. return;
  1643. }
  1644. VOID
  1645. DelayedWrite(
  1646. IN PVOID SystemSpecific1,
  1647. IN PVOID FunctionContext,
  1648. IN PVOID SystemSpecific2,
  1649. IN PVOID SystemSpecific3
  1650. )
  1651. {
  1652. IrDevice *thisDev = FunctionContext;
  1653. #if DBG
  1654. ASSERT(thisDev->WaitingForTurnAroundTimer);
  1655. thisDev->WaitingForTurnAroundTimer=FALSE;
  1656. #endif
  1657. LOG("Turn around timer expired");
  1658. SendCurrentPacket(thisDev);
  1659. }
  1660. VOID
  1661. ProcessSendQueue(
  1662. IrDevice *thisDev
  1663. )
  1664. {
  1665. PNDIS_PACKET Packet=NULL;
  1666. PLIST_ENTRY ListEntry;
  1667. NdisAcquireSpinLock(&thisDev->QueueLock);
  1668. if (thisDev->CurrentPacket == NULL) {
  1669. //
  1670. // not currently processing a send
  1671. //
  1672. if (!IsListEmpty(&thisDev->SendQueue)) {
  1673. //
  1674. // we have some queue packets to process
  1675. //
  1676. ListEntry=RemoveHeadList(&thisDev->SendQueue);
  1677. Packet= CONTAINING_RECORD(
  1678. ListEntry,
  1679. NDIS_PACKET,
  1680. MiniportReserved
  1681. );
  1682. thisDev->CurrentPacket=Packet;
  1683. NdisReleaseSpinLock(&thisDev->QueueLock);
  1684. {
  1685. PNDIS_IRDA_PACKET_INFO packetInfo;
  1686. /*
  1687. * Enforce the minimum turnaround time that must transpire
  1688. * after the last receive.
  1689. */
  1690. packetInfo = GetPacketInfo(Packet);
  1691. //
  1692. // see if this packet is requesting a turnaround time or not
  1693. //
  1694. if (packetInfo->MinTurnAroundTime > 0) {
  1695. //
  1696. // Since we are using the timer to determine when the receive has ended,
  1697. // we must have waited atleast the timer timeout period before we indicated
  1698. // the packet to the protocol. Therefore, if that timeout was greater than
  1699. // the turn around time then we don't need to wait.
  1700. //
  1701. // this of course assumes that the protocol is not going to start sending
  1702. // in the middle of a receive. If it is, then the other station is not going to
  1703. // see the data anyway, so it does not matter much
  1704. //
  1705. // this saves us from waiting the 10ms or so for the time out since the OS timer
  1706. // resoltion is around 10ms.
  1707. //
  1708. // if the transfer ended because the DMA buffer filled up, then we will force a turnaround
  1709. //
  1710. // we don't do this SIR speeds
  1711. //
  1712. if ((packetInfo->MinTurnAroundTime > RECEIVE_TIMEOUT)
  1713. ||
  1714. thisDev->ForceTurnAroundTimeout
  1715. ||
  1716. (thisDev->currentSpeed <= MAX_SIR_SPEED) ) {
  1717. UINT usecToWait = packetInfo->MinTurnAroundTime;
  1718. UINT msecToWait;
  1719. msecToWait = (usecToWait<1000) ? 1 : (usecToWait+500)/1000;
  1720. #if DBG
  1721. thisDev->WaitingForTurnAroundTimer=TRUE;
  1722. #endif
  1723. NdisSetTimer(&thisDev->TurnaroundTimer, msecToWait);
  1724. thisDev->ForceTurnAroundTimeout=FALSE;
  1725. return;
  1726. }
  1727. }
  1728. }
  1729. SendCurrentPacket(thisDev);
  1730. NdisAcquireSpinLock(&thisDev->QueueLock);
  1731. }
  1732. }
  1733. if ((thisDev->CurrentPacket == NULL) && IsListEmpty(&thisDev->SendQueue)) {
  1734. //
  1735. // not currently processing a send
  1736. //
  1737. if (!thisDev->TransmitIsIdle) {
  1738. //
  1739. // We were not idle before
  1740. //
  1741. thisDev->TransmitIsIdle=TRUE;
  1742. if (thisDev->Halting) {
  1743. NdisSetEvent(&thisDev->SendStoppedOnHalt);
  1744. }
  1745. //
  1746. // restart receive
  1747. //
  1748. if (thisDev->currentSpeed > MAX_SIR_SPEED) {
  1749. //
  1750. // Start receive
  1751. //
  1752. thisDev->FirIntMask = 0x04;
  1753. SetupRecv(thisDev);
  1754. SyncSetInterruptMask(thisDev, TRUE);
  1755. } else {
  1756. //
  1757. // For SIR, the ISR switches back to receive for us
  1758. //
  1759. }
  1760. }
  1761. }
  1762. NdisReleaseSpinLock(&thisDev->QueueLock);
  1763. return;
  1764. }
  1765. /*
  1766. *************************************************************************
  1767. * SendPacketsHandler
  1768. *************************************************************************
  1769. *
  1770. * Send an array of packets simultaneously.
  1771. *
  1772. */
  1773. VOID SendPacketsHandler(NDIS_HANDLE MiniportAdapterContext,
  1774. PPNDIS_PACKET PacketArray, UINT NumberofPackets)
  1775. {
  1776. UINT i;
  1777. IrDevice *thisDev = CONTEXT_TO_DEV(MiniportAdapterContext);
  1778. DEBUGMSG(DBG_TRACE_TX, ("M"));
  1779. LOG("==> SendPacketsHandler");
  1780. DBGOUT(("==> SendPacketsHandler(0x%x)", MiniportAdapterContext));
  1781. LOG("Number of transmit Burst %d ", NumberofPackets);
  1782. ASSERT(!thisDev->Halting);
  1783. //
  1784. // NDIS gives us the PacketArray, but it is not ours to keep, so we have to take
  1785. // the packets out and store them elsewhere.
  1786. //
  1787. NdisAcquireSpinLock(&thisDev->QueueLock);
  1788. //
  1789. // all packets get queued
  1790. //
  1791. for (i = 0; i < NumberofPackets; i++) {
  1792. if (thisDev->Halting) {
  1793. //
  1794. // ndis should not send us more packets after calling the halt rountine.
  1795. // just make sure here
  1796. //
  1797. NdisReleaseSpinLock(&thisDev->QueueLock);
  1798. NdisMSendComplete(thisDev->ndisAdapterHandle, PacketArray[i], NDIS_STATUS_FAILURE );
  1799. NdisAcquireSpinLock(&thisDev->QueueLock);
  1800. } else {
  1801. InsertTailList(
  1802. &thisDev->SendQueue,
  1803. (PLIST_ENTRY)PacketArray[i]->MiniportReserved
  1804. );
  1805. }
  1806. }
  1807. NdisReleaseSpinLock(&thisDev->QueueLock);
  1808. ProcessSendQueue(thisDev);
  1809. LOG("<== SendPacketsHandler");
  1810. DBGOUT(("<== SendPacketsHandler"));
  1811. return ;
  1812. }
  1813. VOID
  1814. NscUloadHandler(
  1815. PDRIVER_OBJECT DriverObject
  1816. )
  1817. {
  1818. DBGOUT(("Unloading"));
  1819. WPP_CLEANUP(DriverObject);
  1820. return;
  1821. }
  1822. BOOLEAN AbortLoad = FALSE;
  1823. /*
  1824. *************************************************************************
  1825. * DriverEntry
  1826. *************************************************************************
  1827. *
  1828. * Only include if IRMINI is a stand-alone driver.
  1829. *
  1830. */
  1831. NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
  1832. #pragma NDIS_INIT_FUNCTION(DriverEntry)
  1833. NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
  1834. {
  1835. NTSTATUS result = STATUS_SUCCESS, stat;
  1836. NDIS_HANDLE wrapperHandle;
  1837. NDIS50_MINIPORT_CHARACTERISTICS info;
  1838. WPP_INIT_TRACING(DriverObject,RegistryPath);
  1839. LOG("==> DriverEntry");
  1840. DBGOUT(("==> DriverEntry"));
  1841. //DbgBreakPoint();
  1842. if (AbortLoad)
  1843. {
  1844. return STATUS_CANCELLED;
  1845. }
  1846. NdisZeroMemory(&info, sizeof(info));
  1847. NdisMInitializeWrapper( (PNDIS_HANDLE)&wrapperHandle,
  1848. DriverObject,
  1849. RegistryPath,
  1850. NULL
  1851. );
  1852. DBGOUT(("Wrapper handle is %xh", wrapperHandle));
  1853. info.MajorNdisVersion = (UCHAR)NDIS_MAJOR_VERSION;
  1854. info.MinorNdisVersion = (UCHAR)NDIS_MINOR_VERSION;
  1855. //info.Flags = 0;
  1856. info.CheckForHangHandler = MiniportCheckForHang;
  1857. info.HaltHandler = MiniportHalt;
  1858. info.InitializeHandler = MiniportInitialize;
  1859. info.QueryInformationHandler = MiniportQueryInformation;
  1860. info.ReconfigureHandler = NULL;
  1861. info.ResetHandler = MiniportReset;
  1862. info.SendHandler = NULL; //MiniportSend;
  1863. info.SetInformationHandler = MiniportSetInformation;
  1864. info.TransferDataHandler = NULL;
  1865. info.HandleInterruptHandler = MiniportHandleInterrupt;
  1866. info.ISRHandler = MiniportISR;
  1867. info.DisableInterruptHandler = NULL;
  1868. info.EnableInterruptHandler = NULL; //MiniportEnableInterrupt;
  1869. /*
  1870. * New NDIS 4.0 fields
  1871. */
  1872. info.ReturnPacketHandler = ReturnPacketHandler;
  1873. info.SendPacketsHandler = SendPacketsHandler;
  1874. info.AllocateCompleteHandler = NULL;
  1875. stat = NdisMRegisterMiniport( wrapperHandle,
  1876. (PNDIS_MINIPORT_CHARACTERISTICS)&info,
  1877. sizeof(info));
  1878. if (stat != NDIS_STATUS_SUCCESS){
  1879. DBGERR(("NdisMRegisterMiniport failed in DriverEntry"));
  1880. result = STATUS_UNSUCCESSFUL;
  1881. goto _entryDone;
  1882. }
  1883. NdisMRegisterUnloadHandler(
  1884. wrapperHandle,
  1885. NscUloadHandler
  1886. );
  1887. _entryDone:
  1888. DBGOUT(("DriverEntry %s", (PUCHAR)((result == NDIS_STATUS_SUCCESS) ? "succeeded" : "failed")));
  1889. LOG("<== DriverEntry");
  1890. DBGOUT(("<== DriverEntry"));
  1891. return result;
  1892. }
  1893. PNDIS_IRDA_PACKET_INFO GetPacketInfo(PNDIS_PACKET packet)
  1894. {
  1895. MEDIA_SPECIFIC_INFORMATION *mediaInfo;
  1896. UINT size;
  1897. NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(packet, &mediaInfo, &size);
  1898. return (PNDIS_IRDA_PACKET_INFO)mediaInfo->ClassInformation;
  1899. }
  1900. /* Setup for Recv */
  1901. // This function is always called at MIR & FIR speeds
  1902. void SetupRecv(IrDevice *thisDev)
  1903. {
  1904. NDIS_STATUS stat;
  1905. UINT FifoClear = 8;
  1906. UCHAR FifoStatus;
  1907. LOG("SetupRecv - Begin Rcv Setup");
  1908. FindLargestSpace(thisDev, &thisDev->rcvDmaOffset, &thisDev->rcvDmaSize);
  1909. // Drain the status fifo of any pending packets
  1910. //
  1911. FifoStatus=SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 5, FRM_ST);
  1912. while ((FifoStatus & 0x80) && FifoClear--) {
  1913. ULONG Size;
  1914. Size = SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 5, RFRL_L);
  1915. Size |= SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 5, RFRL_H);
  1916. LOG_Discard(thisDev, Size);
  1917. LOG_ERROR("SetupRecv: fifo %02x, %d",FifoStatus,Size);
  1918. FifoStatus=SyncReadBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 5, FRM_ST);
  1919. thisDev->DiscardNextPacketSet = TRUE;
  1920. }
  1921. thisDev->rcvPktOffset = thisDev->rcvDmaOffset;
  1922. //
  1923. // Use DMA swap bit to switch to DMA to Receive.
  1924. //
  1925. SyncWriteBankReg(&thisDev->interruptObj,thisDev->portInfo.ioBase, 2, 2, 0x03);
  1926. LOG_Dma(thisDev);
  1927. thisDev->FirReceiveDmaActive=TRUE;
  1928. if (thisDev->rcvDmaSize < 8192) {
  1929. LOG("SetupRecv small dma %d\n",(ULONG)thisDev->rcvDmaSize);
  1930. }
  1931. thisDev->LastReadDMACount = thisDev->rcvDmaSize;
  1932. stat=StartDmaTransferFromDevice(
  1933. &thisDev->DmaUtil,
  1934. thisDev->rcvDmaBuffer,
  1935. (ULONG)thisDev->rcvDmaOffset,
  1936. (ULONG)thisDev->rcvDmaSize
  1937. );
  1938. LOG("SetupRecv - Begin Rcv Setup: offset=%d, size =%d",(ULONG)thisDev->rcvDmaOffset,(ULONG)thisDev->rcvDmaSize);
  1939. if (stat != NDIS_STATUS_SUCCESS) {
  1940. thisDev->FirReceiveDmaActive=FALSE;
  1941. LOG("Error: NdisMSetupDmaTransfer failed in SetupRecv %x", stat);
  1942. DBGERR(("NdisMSetupDmaTransfer failed (%xh) in SetupRecv", (UINT)stat));
  1943. ASSERT(0);
  1944. }
  1945. LOG("SetupRecv - End Rcv Setup");
  1946. }