Windows NT 4.0 source code leak
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.

607 lines
12 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. command.c
  5. Abstract:
  6. This file contains the code for managing Command Blocks on the
  7. EtherLink's Command Queue.
  8. Author:
  9. Johnson R. Apacible (JohnsonA) 09-June-1991
  10. Environment:
  11. Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
  12. Revision History:
  13. --*/
  14. #include <ndis.h>
  15. //
  16. // So we can trace things...
  17. //
  18. #define STATIC
  19. #include <efilter.h>
  20. #include <elnkhw.h>
  21. #include <elnksw.h>
  22. BOOLEAN
  23. ElnkSyncStartCommandBlock(
  24. IN PVOID Context
  25. )
  26. /*++
  27. Routine Description:
  28. This function is used to synchronize with the ISR the starting of a
  29. command block.
  30. Arguments:
  31. see NDIS 3.0 spec.
  32. Notes:
  33. returns TRUE on success, else FALSE.
  34. --*/
  35. {
  36. PELNK_ADAPTER Adapter = (PELNK_ADAPTER)Context;
  37. IF_LOG('x');
  38. WRITE_ADAPTER_REGISTER(
  39. Adapter,
  40. OFFSET_SCB_CB,
  41. Adapter->TransmitInfo[Adapter->CommandToStart].CbOffset
  42. );
  43. WRITE_ADAPTER_REGISTER(
  44. Adapter,
  45. OFFSET_SCBCMD,
  46. CUC_START
  47. );
  48. ELNK_CA;
  49. return(TRUE);
  50. }
  51. VOID
  52. ElnkAssignPacketToCommandBlock(
  53. IN PELNK_ADAPTER Adapter,
  54. IN PNDIS_PACKET Packet,
  55. IN UINT CbIndex
  56. )
  57. /*++
  58. Routine Description:
  59. Given a packet and a pointer to a Command Block, assign all of the
  60. buffers in the packet to Command Block.
  61. Arguments:
  62. Adapter - The adapter that the packets are coming through.
  63. Packet - The packet whose buffers are to be assigned
  64. ring entries.
  65. CbIndex - The index of the Command Block to receive the
  66. packet's buffers.
  67. Return Value:
  68. None.
  69. --*/
  70. {
  71. //
  72. // Points to the reserved portion of the packet.
  73. //
  74. PELNK_RESERVED Reserved = PELNK_RESERVED_FROM_PACKET(Packet);
  75. //
  76. // Pointer to the actual transmit command block
  77. //
  78. PTRANSMIT_CB TransmitBlock = Adapter->TransmitInfo[CbIndex].CommandBlock;
  79. //
  80. // index for for loop
  81. //
  82. UINT i;
  83. //
  84. // Points to the current ndis buffer being walked.
  85. //
  86. PNDIS_BUFFER SourceBuffer;
  87. //
  88. // The total amount of data in the ndis packet.
  89. //
  90. UINT TotalVirtualLength;
  91. //
  92. // The virtual address of data in the current ndis buffer.
  93. //
  94. PVOID SourceData;
  95. //
  96. // The length in bytes of data of the current ndis buffer.
  97. //
  98. UINT SourceLength;
  99. //
  100. // The number of ndis buffers in the packet.
  101. //
  102. UINT NdisBufferCount;
  103. //
  104. // We record the owning packet information in the ring packet packet
  105. // structure.
  106. //
  107. Adapter->TransmitInfo[CbIndex].OwningPacket = Packet;
  108. Adapter->TransmitInfo[CbIndex].NextCommand = ELNK_EMPTY;
  109. Adapter->TransmitInfo[CbIndex].OwningOpenBinding = NULL;
  110. //
  111. // Initialize the various fields of the Command Block.
  112. //
  113. NdisWriteRegisterUshort(&TransmitBlock->Status, CB_STATUS_FREE);
  114. NdisWriteRegisterUshort(&TransmitBlock->NextCbOffset, ELNK_NULL);
  115. NdisWriteRegisterUshort(&TransmitBlock->Command, CB_TRANSMIT);
  116. NdisQueryPacket(
  117. Packet,
  118. NULL,
  119. &NdisBufferCount,
  120. &SourceBuffer,
  121. &TotalVirtualLength
  122. );
  123. NdisQueryBuffer(
  124. SourceBuffer,
  125. &SourceData,
  126. &SourceLength
  127. );
  128. ASSERT(SourceLength >= ELNK_HEADER_SIZE);
  129. #if 1
  130. //
  131. // Fill in fields of TFD
  132. //
  133. ELNK_MOVE_MEMORY_TO_SHARED_RAM(
  134. &TransmitBlock->Destination[0],
  135. SourceData,
  136. ETH_LENGTH_OF_ADDRESS
  137. );
  138. SourceData = (PVOID)((PUCHAR)SourceData + 2 * ETH_LENGTH_OF_ADDRESS);
  139. SourceLength -= 2 * ETH_LENGTH_OF_ADDRESS + sizeof(USHORT);
  140. NdisWriteRegisterUshort(&TransmitBlock->Length,
  141. (USHORT)(*((USHORT UNALIGNED *)SourceData))
  142. );
  143. SourceData = (PVOID)((PUCHAR)SourceData + sizeof(USHORT));
  144. if (SourceLength == 0) {
  145. NdisBufferCount--;
  146. NdisGetNextBuffer(
  147. SourceBuffer,
  148. &SourceBuffer
  149. );
  150. NdisQueryBuffer(
  151. SourceBuffer,
  152. &SourceData,
  153. &SourceLength
  154. );
  155. }
  156. #endif
  157. {
  158. //
  159. // Fill in the adapter buffer with the data from the users
  160. // buffers.
  161. //
  162. PVOID CurrentDestination = Adapter->TransmitInfo[CbIndex].Buffer;
  163. for (
  164. i = NdisBufferCount;
  165. i;
  166. i--
  167. ) {
  168. if (SourceLength) {
  169. ELNK_MOVE_MEMORY_TO_SHARED_RAM(
  170. CurrentDestination,
  171. SourceData,
  172. SourceLength
  173. );
  174. }
  175. CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
  176. if (i > 1) {
  177. NdisGetNextBuffer(
  178. SourceBuffer,
  179. &SourceBuffer
  180. );
  181. NdisQueryBuffer(
  182. SourceBuffer,
  183. &SourceData,
  184. &SourceLength
  185. );
  186. }
  187. }
  188. //
  189. // If the packet is less than the minimum Ethernet
  190. // packet size, then clear the remaining part of
  191. // the buffer up to the minimum packet size.
  192. //
  193. if (TotalVirtualLength < MINIMUM_ETHERNET_PACKET_SIZE) {
  194. NdisZeroMappedMemory(
  195. CurrentDestination,
  196. MINIMUM_ETHERNET_PACKET_SIZE - TotalVirtualLength
  197. );
  198. TotalVirtualLength = MINIMUM_ETHERNET_PACKET_SIZE;
  199. }
  200. NdisWriteRegisterUshort(
  201. &TransmitBlock->Tbd.Length,
  202. (USHORT)((TotalVirtualLength - ELNK_HEADER_SIZE) | TBD_END_OF_LIST)
  203. );
  204. }
  205. Reserved->CommandBlockIndex = CbIndex;
  206. }
  207. VOID
  208. ElnkSubmitCommandBlock(
  209. IN PELNK_ADAPTER Adapter,
  210. IN UINT CbIndex
  211. )
  212. /*++
  213. Routine Description:
  214. Submit a complete Command Block for execution by the Elnk.
  215. NOTE: This routine assumes that it is called with the lock held.
  216. Arguments:
  217. Adapter - The adapter that points to the ring entry structures.
  218. CbIndex - Holds the index of the Command Block to be submitted.
  219. Return Value:
  220. None.
  221. *--*/
  222. {
  223. //
  224. // Pointer to the most recently submitted Command Block.
  225. //
  226. PTRANSMIT_CB CommandBlock = Adapter->TransmitInfo[CbIndex].CommandBlock;
  227. //
  228. // Index of last command submitted
  229. //
  230. UINT PreviousCommandBlock = Adapter->LastPendingCommand;
  231. USHORT Command;
  232. IF_LOG('s');
  233. //
  234. // Set the Command Block to be the last command block
  235. //
  236. NdisReadRegisterUshort(&CommandBlock->Command, &Command);
  237. NdisWriteRegisterUshort(
  238. &CommandBlock->Command,
  239. (USHORT)(Command |(CB_COMMAND_END_OF_LIST | CB_COMMAND_INTERRUPT))
  240. );
  241. if ELNKDEBUG DPrint2("Submit: Command Block = %x\n",(Command |(CB_COMMAND_END_OF_LIST | CB_COMMAND_INTERRUPT)));
  242. //
  243. // Initialize our command timeout flag.
  244. //
  245. Adapter->TransmitInfo[CbIndex].Timeout = FALSE;
  246. //
  247. // Initialize the next command pointer
  248. //
  249. Adapter->TransmitInfo[CbIndex].NextCommand = ELNK_EMPTY;
  250. //
  251. // Update the pointer to the most recently submitted Command Block.
  252. //
  253. Adapter->LastPendingCommand = CbIndex;
  254. if (PreviousCommandBlock == ELNK_EMPTY) {
  255. if ELNKDEBUG DPrint1("Request sent\n");
  256. if (Adapter->FirstPendingCommand == ELNK_EMPTY ) {
  257. Adapter->FirstPendingCommand = CbIndex;
  258. }
  259. ELNK_WAIT;
  260. Adapter->CommandToStart = CbIndex;
  261. NdisSynchronizeWithInterrupt(
  262. &(Adapter->Interrupt),
  263. (PVOID)ElnkSyncStartCommandBlock,
  264. (PVOID)(Adapter)
  265. );
  266. } else {
  267. //
  268. // Queue the request
  269. //
  270. if ELNKDEBUG DPrint1("Request queued\n");
  271. Adapter->TransmitInfo[PreviousCommandBlock].NextCommand = CbIndex;
  272. }
  273. }
  274. VOID
  275. ElnkSubmitCommandBlockAndWait(
  276. IN PELNK_ADAPTER Adapter
  277. )
  278. /*++
  279. Routine Description:
  280. Submit a command block and wait till it's done. This is done for
  281. setups and configurations.
  282. NOTE: This routine assumes that it is called with the lock held.
  283. Arguments:
  284. Adapter - The adapter that points to the ring entry structures.
  285. Return Value:
  286. None.
  287. --*/
  288. {
  289. UINT i;
  290. USHORT Status;
  291. //
  292. // The value of our scb
  293. //
  294. USHORT Command;
  295. //
  296. // Points to our transmit CB
  297. //
  298. PNON_TRANSMIT_CB CommandBlock = Adapter->MulticastBlock;
  299. //
  300. // Set the Command Block to be the last command block
  301. //
  302. IF_LOG('W');
  303. NdisReadRegisterUshort(&CommandBlock->Command, &Command);
  304. NdisWriteRegisterUshort(&CommandBlock->Command, (USHORT)(Command | CB_COMMAND_END_OF_LIST));
  305. NdisWriteRegisterUshort(&CommandBlock->Status, CB_STATUS_FREE);
  306. if ELNKDEBUG
  307. DPrint2("Command Block requested = %x\n",Command | CB_COMMAND_END_OF_LIST);
  308. ELNK_WAIT;
  309. Adapter->CommandToStart = Adapter->NumberOfTransmitBuffers;
  310. NdisSynchronizeWithInterrupt(
  311. &(Adapter->Interrupt),
  312. (PVOID)ElnkSyncStartCommandBlock,
  313. (PVOID)(Adapter)
  314. );
  315. ELNK_WAIT;
  316. for (i = 0; i <= 20000 ; i++ ) {
  317. NdisReadRegisterUshort(&CommandBlock->Status, &Status);
  318. if (Status & CB_STATUS_COMPLETE) {
  319. break;
  320. }
  321. NdisStallExecution(50);
  322. }
  323. }
  324. BOOLEAN
  325. ElnkAcquireCommandBlock(
  326. IN PELNK_ADAPTER Adapter,
  327. OUT PUINT CbIndex
  328. )
  329. /*++
  330. Routine Description:
  331. Sees if a Command Block is available and if so returns its index.
  332. NOTE: This routine assumes that the lock is held.
  333. Arguments:
  334. Adapter - The adapter that points to the ring entry structures.
  335. CbIndex - will receive an index to a Command Block if one is
  336. available. This value is unpredicable if there is not a free
  337. Command Block.
  338. Return Value:
  339. Returns FALSE if there are no free Command Blocks.
  340. --*/
  341. {
  342. if ELNKDEBUG DPrint1("acquire CB\n");
  343. {
  344. if (Adapter->NumberOfAvailableCommandBlocks) {
  345. //
  346. // Return the Command Block pointer.
  347. //
  348. *CbIndex = Adapter->NextCommandBlock;
  349. //
  350. // Update the head of the Command Queue.
  351. //
  352. Adapter->NextCommandBlock++;
  353. if (Adapter->NextCommandBlock >= Adapter->NumberOfTransmitBuffers) {
  354. Adapter->NextCommandBlock = 0;
  355. }
  356. //
  357. // Update number of available Command Blocks.
  358. //
  359. Adapter->NumberOfAvailableCommandBlocks--;
  360. return TRUE;
  361. } else {
  362. Adapter->StageOpen = FALSE;
  363. return FALSE;
  364. }
  365. }
  366. }
  367. VOID
  368. ElnkRelinquishCommandBlock(
  369. IN PELNK_ADAPTER Adapter,
  370. IN UINT CbIndex
  371. )
  372. /*++
  373. Routine Description:
  374. Relinquish the Command Block resource. If this is a "public"
  375. Command Block, then update the TransmitQueue. If this is a
  376. "private" Command Block, then free its memory.
  377. NOTE: This routine assumes that the lock is held.
  378. Arguments:
  379. Adapter - The adapter that owns the Command Block.
  380. CbIndex - The index of the Command Block to relinquish.
  381. Return Value:
  382. None.
  383. --*/
  384. {
  385. PTRANSMIT_CB CommandBlock = Adapter->TransmitInfo[CbIndex].CommandBlock;
  386. //
  387. // Point the adapter's first pending command to the
  388. // next command on the command queue.
  389. //
  390. if ELNKDEBUG DPrint1("relinquish CB\n");
  391. Adapter->FirstPendingCommand = Adapter->TransmitInfo[CbIndex].NextCommand;
  392. //
  393. // If this is the last pending command block, then we
  394. // can nuke the adapter's last pending command pointer.
  395. //
  396. if (CbIndex == Adapter->LastPendingCommand) {
  397. Adapter->LastPendingCommand = ELNK_EMPTY;
  398. }
  399. NdisWriteRegisterUshort(&CommandBlock->NextCbOffset, ELNK_NULL);
  400. NdisWriteRegisterUshort(&CommandBlock->Status, CB_STATUS_FREE);
  401. Adapter->NumberOfAvailableCommandBlocks++;
  402. }