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.

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