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.

579 lines
17 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. dma.c
  5. Abstract:
  6. functions for processing ennpoints that use DMA to
  7. process transfers
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. 6-20-99 : created
  13. --*/
  14. #include "common.h"
  15. #ifdef ALLOC_PRAGMA
  16. #endif
  17. // non paged functions
  18. // USBPORT_DmaEndpointWorker
  19. // USBPORT_DmaEndpointPaused
  20. // USBPORT_DmaEndpointActive
  21. MP_ENDPOINT_STATE
  22. USBPORT_DmaEndpointActive(
  23. PDEVICE_OBJECT FdoDeviceObject,
  24. PHCD_ENDPOINT Endpoint
  25. )
  26. /*++
  27. Routine Description:
  28. process the active state
  29. returns the next needed state if we
  30. discover the need for a transition
  31. Arguments:
  32. Return Value:
  33. None.
  34. --*/
  35. {
  36. MP_ENDPOINT_STATE currentState;
  37. PLIST_ENTRY listEntry;
  38. MP_ENDPOINT_STATE nextState;
  39. PHCD_TRANSFER_CONTEXT transfer;
  40. PDEVICE_EXTENSION devExt;
  41. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  42. ASSERT_FDOEXT(devExt);
  43. ASSERT_ENDPOINT(Endpoint);
  44. currentState = USBPORT_GetEndpointState(Endpoint);
  45. LOGENTRY(Endpoint,
  46. FdoDeviceObject, LOG_XFERS, 'dmaA', 0, Endpoint, currentState);
  47. USBPORT_ASSERT(currentState == ENDPOINT_ACTIVE);
  48. ASSERT_ENDPOINT_LOCKED(Endpoint);
  49. // BUGBUG
  50. //nextState = ENDPOINT_IDLE;
  51. nextState = ENDPOINT_ACTIVE;
  52. // now walk thru and process active requests
  53. GET_HEAD_LIST(Endpoint->ActiveList, listEntry);
  54. while (listEntry &&
  55. listEntry != &Endpoint->ActiveList) {
  56. transfer = (PHCD_TRANSFER_CONTEXT) CONTAINING_RECORD(
  57. listEntry,
  58. struct _HCD_TRANSFER_CONTEXT,
  59. TransferLink);
  60. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'pACT', transfer, 0, 0);
  61. ASSERT_TRANSFER(transfer);
  62. USBPORT_ASSERT(transfer->Tp.TransferBufferLength <=
  63. EP_MAX_TRANSFER(Endpoint));
  64. // process the transfer
  65. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_KILL_SPLIT)) {
  66. USBPORT_QueueDoneTransfer(transfer,
  67. STATUS_SUCCESS);
  68. break;
  69. } else if (!TEST_FLAG(transfer->Flags,USBPORT_TXFLAG_IN_MINIPORT) &&
  70. !TEST_FLAG(Endpoint->Flags, EPFLAG_NUKED)) {
  71. USB_MINIPORT_STATUS mpStatus;
  72. // transfer has not been called down yet
  73. // call it down now
  74. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_ISO)) {
  75. LOGENTRY(Endpoint, FdoDeviceObject, LOG_ISO, 'subI', mpStatus, Endpoint, transfer);
  76. MP_SubmitIsoTransfer(devExt, Endpoint, transfer, mpStatus);
  77. } else {
  78. MP_SubmitTransfer(devExt, Endpoint, transfer, mpStatus);
  79. }
  80. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'subm', mpStatus, Endpoint, transfer);
  81. if (mpStatus == USBMP_STATUS_SUCCESS) {
  82. LARGE_INTEGER timeout;
  83. SET_FLAG(transfer->Flags, USBPORT_TXFLAG_IN_MINIPORT);
  84. // miniport took it -- set the timeout
  85. KeQuerySystemTime(&transfer->TimeoutTime);
  86. timeout.QuadPart = transfer->MillisecTimeout;
  87. // convert to 100ns units
  88. timeout.QuadPart = timeout.QuadPart * 10000;
  89. transfer->TimeoutTime.QuadPart += timeout.QuadPart;
  90. } else if (mpStatus == USBMP_STATUS_BUSY) {
  91. // miniport busy try later
  92. break;
  93. } else {
  94. // an error, we will need to complete
  95. // this transfer for the miniport
  96. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'tERR',
  97. transfer,
  98. mpStatus,
  99. 0);
  100. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_ISO)) {
  101. LOGENTRY(Endpoint, FdoDeviceObject, LOG_ISO, 'iERR',
  102. transfer,
  103. mpStatus,
  104. 0);
  105. USBPORT_ErrorCompleteIsoTransfer(FdoDeviceObject,
  106. Endpoint,
  107. transfer);
  108. } else {
  109. TEST_TRAP();
  110. }
  111. break;
  112. }
  113. // go active
  114. nextState = ENDPOINT_ACTIVE;
  115. }
  116. // if we find a canceled 'active' transfer we need to pause
  117. // the enpoint so we can flush it out
  118. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_CANCELED) ||
  119. TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_ABORTED) ) {
  120. // we need to pause the endpoint
  121. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'inAC', transfer, Endpoint,
  122. transfer->Flags);
  123. nextState = ENDPOINT_PAUSE;
  124. break;
  125. }
  126. listEntry = transfer->TransferLink.Flink;
  127. }
  128. USBPORT_DmaEndpointActive_Done:
  129. return nextState;
  130. }
  131. MP_ENDPOINT_STATE
  132. USBPORT_DmaEndpointPaused(
  133. PDEVICE_OBJECT FdoDeviceObject,
  134. PHCD_ENDPOINT Endpoint
  135. )
  136. /*++
  137. Routine Description:
  138. process the paused state
  139. endpoint is paused, cancel any transfers that need
  140. canceling
  141. Arguments:
  142. Return Value:
  143. None.
  144. --*/
  145. {
  146. MP_ENDPOINT_STATE currentState;
  147. MP_ENDPOINT_STATE nextState;
  148. PLIST_ENTRY listEntry;
  149. PHCD_TRANSFER_CONTEXT transfer;
  150. PDEVICE_EXTENSION devExt;
  151. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  152. ASSERT_FDOEXT(devExt);
  153. ASSERT_ENDPOINT(Endpoint);
  154. currentState = USBPORT_GetEndpointState(Endpoint);
  155. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'dmaP', 0, Endpoint, currentState);
  156. USBPORT_ASSERT(currentState == ENDPOINT_PAUSE);
  157. nextState = currentState;
  158. // now walk thru and process active requests
  159. GET_HEAD_LIST(Endpoint->ActiveList, listEntry);
  160. while (listEntry &&
  161. listEntry != &Endpoint->ActiveList) {
  162. // extract the urb that is currently on the active
  163. // list, there should only be one
  164. transfer = (PHCD_TRANSFER_CONTEXT) CONTAINING_RECORD(
  165. listEntry,
  166. struct _HCD_TRANSFER_CONTEXT,
  167. TransferLink);
  168. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'pPAU', transfer, Endpoint, 0);
  169. ASSERT_TRANSFER(transfer);
  170. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_CANCELED) ||
  171. TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_ABORTED)) {
  172. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_ISO) &&
  173. TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_IN_MINIPORT) &&
  174. !TEST_FLAG(Endpoint->Flags, EPFLAG_NUKED)) {
  175. ULONG cf, lastFrame;
  176. PTRANSFER_URB urb;
  177. LOGENTRY(Endpoint,
  178. FdoDeviceObject, LOG_XFERS, 'drn+', transfer, 0, 0);
  179. urb = transfer->Urb;
  180. ASSERT_TRANSFER_URB(urb);
  181. // iso transfer in the miniport, we need to let the
  182. // iso TDs drain out, before doing an abort.
  183. lastFrame =
  184. urb->u.Isoch.StartFrame + urb->u.Isoch.NumberOfPackets;
  185. // get the current frame
  186. MP_Get32BitFrameNumber(devExt, cf);
  187. if (cf < lastFrame + 1) {
  188. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'drne', transfer, 0, 0);
  189. goto stay_paused;
  190. }
  191. }
  192. if ( TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_IN_MINIPORT) &&
  193. !TEST_FLAG(Endpoint->Flags, EPFLAG_NUKED)) {
  194. ULONG bytesTransferred = 0;
  195. // abort the transfer
  196. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'inMP', transfer, 0, 0);
  197. MP_AbortTransfer(devExt, Endpoint, transfer, bytesTransferred);
  198. // make sure we indicate any data that has been transferred
  199. // prior to abort
  200. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_ISO)) {
  201. USBPORT_FlushIsoTransfer(FdoDeviceObject,
  202. &transfer->Tp,
  203. transfer->IsoTransfer);
  204. } else {
  205. transfer->MiniportBytesTransferred = bytesTransferred;
  206. }
  207. LOGENTRY(Endpoint, FdoDeviceObject, LOG_XFERS, 'abrL', 0,
  208. transfer, bytesTransferred);
  209. // pick up the next ptr
  210. listEntry = transfer->TransferLink.Flink;
  211. // no more references, put this transfer on the
  212. // cancel list
  213. RemoveEntryList(&transfer->TransferLink);
  214. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_SPLIT_CHILD)) {
  215. USBPORT_CancelSplitTransfer(FdoDeviceObject, transfer);
  216. } else {
  217. InsertTailList(&Endpoint->CancelList, &transfer->TransferLink);
  218. }
  219. } else {
  220. // transfer not in miniport, put it on the
  221. // cancel list since it can not be completed
  222. // by the miniport.
  223. LOGENTRY(Endpoint,
  224. FdoDeviceObject, LOG_XFERS, 'niMP', transfer, 0, 0);
  225. // pick up the next ptr
  226. listEntry = transfer->TransferLink.Flink;
  227. RemoveEntryList(&transfer->TransferLink);
  228. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_SPLIT_CHILD)) {
  229. USBPORT_CancelSplitTransfer(FdoDeviceObject, transfer);
  230. } else {
  231. InsertTailList(&Endpoint->CancelList, &transfer->TransferLink);
  232. }
  233. }
  234. } else {
  235. listEntry = transfer->TransferLink.Flink;
  236. }
  237. } /* while */
  238. // cancel routine will bump us back to
  239. // the active state
  240. nextState = ENDPOINT_ACTIVE;
  241. stay_paused:
  242. return nextState;
  243. }
  244. VOID
  245. USBPORT_DmaEndpointWorker(
  246. PHCD_ENDPOINT Endpoint
  247. )
  248. /*++
  249. Routine Description:
  250. endpoints that need transfers mapped come thru here
  251. Arguments:
  252. Return Value:
  253. None.
  254. --*/
  255. {
  256. PDEVICE_OBJECT fdoDeviceObject;
  257. MP_ENDPOINT_STATE currentState;
  258. MP_ENDPOINT_STATE nextState;
  259. BOOLEAN invalidate = FALSE;
  260. ASSERT_ENDPOINT(Endpoint);
  261. fdoDeviceObject = Endpoint->FdoDeviceObject;
  262. LOGENTRY(Endpoint, fdoDeviceObject, LOG_XFERS, 'dmaW', 0, Endpoint, 0);
  263. ACQUIRE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'Le90');
  264. // we should be in the last requested state
  265. currentState = USBPORT_GetEndpointState(Endpoint);
  266. switch(currentState) {
  267. case ENDPOINT_PAUSE:
  268. nextState =
  269. USBPORT_DmaEndpointPaused(
  270. fdoDeviceObject,
  271. Endpoint);
  272. break;
  273. case ENDPOINT_ACTIVE:
  274. nextState =
  275. USBPORT_DmaEndpointActive(
  276. fdoDeviceObject,
  277. Endpoint);
  278. break;
  279. default:
  280. // state not handled
  281. // this is a bug
  282. TEST_TRAP();
  283. }
  284. // release the endpoint lists
  285. RELEASE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'Ue90');
  286. // flush out canceled requests
  287. USBPORT_FlushCancelList(Endpoint);
  288. // endpoint has now been processed, if we were paused all canceled
  289. // transfers were removed.
  290. // We were either
  291. // 1. paused and need to stay paused (for iso drain)
  292. // 2. paused and need to go active
  293. // 3. active and need to pause
  294. // 4. active and need to stay active
  295. //
  296. ACQUIRE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'LeJ0');
  297. // set to new endpoint state if necessary
  298. if (nextState != currentState) {
  299. // case 2, 3
  300. USBPORT_SetEndpointState(Endpoint, nextState);
  301. } else if (nextState == currentState &&
  302. nextState == ENDPOINT_PAUSE) {
  303. invalidate = TRUE;
  304. }
  305. RELEASE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'UeJ0');
  306. if (invalidate) {
  307. // state change, defer this to the worker
  308. USBPORT_InvalidateEndpoint(fdoDeviceObject, Endpoint, IEP_SIGNAL_WORKER);
  309. }
  310. }
  311. typedef struct _USBPORT_DB_HANDLE {
  312. ULONG Sig;
  313. LIST_ENTRY DbLink;
  314. PVOID DbSystemAddress;
  315. ULONG DbLength;
  316. PUCHAR DbData;
  317. } USBPORT_DB_HANDLE, *PUSBPORT_DB_HANDLE;
  318. VOID
  319. USBPORTSVC_NotifyDoubleBuffer(
  320. PDEVICE_DATA DeviceData,
  321. PTRANSFER_PARAMETERS TransferParameters,
  322. PVOID DbSystemAddress,
  323. ULONG DbLength
  324. )
  325. /*++
  326. Routine Description:
  327. Notify the port driver that double buffering has occured,
  328. port driver will create a node for use during a subsequent
  329. adapter flush.
  330. Arguments:
  331. Return Value:
  332. none
  333. --*/
  334. {
  335. PDEVICE_EXTENSION devExt;
  336. PHCD_TRANSFER_CONTEXT transfer;
  337. PDEVICE_OBJECT fdoDeviceObject;
  338. PUSBPORT_DB_HANDLE dbHandle;
  339. ULONG length;
  340. BOOLEAN write;
  341. DEVEXT_FROM_DEVDATA(devExt, DeviceData);
  342. ASSERT_FDOEXT(devExt);
  343. fdoDeviceObject = devExt->HcFdoDeviceObject;
  344. LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'NOdb', 0,
  345. 0, TransferParameters);
  346. TRANSFER_FROM_TPARAMETERS(transfer, TransferParameters);
  347. ASSERT_TRANSFER(transfer);
  348. write = transfer->Direction == WriteData ? TRUE : FALSE;
  349. // allocate a node and add it to the list, we don't care if it is a
  350. // write
  351. if (!write && transfer->MapRegisterBase != NULL) {
  352. PUCHAR pch;
  353. length = sizeof(USBPORT_DB_HANDLE) + DbLength;
  354. ALLOC_POOL_Z(pch,
  355. NonPagedPool,
  356. length);
  357. LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'db++', DbSystemAddress,
  358. DbLength, transfer);
  359. dbHandle = (PUSBPORT_DB_HANDLE) pch;
  360. pch += sizeof(USBPORT_DB_HANDLE);
  361. dbHandle->Sig = SIG_DB;
  362. dbHandle->DbSystemAddress = DbSystemAddress;
  363. dbHandle->DbLength = DbLength;
  364. dbHandle->DbData = pch;
  365. RtlCopyMemory(pch,
  366. DbSystemAddress,
  367. DbLength);
  368. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_SPLIT_CHILD)) {
  369. ASSERT_TRANSFER(transfer->Transfer);
  370. InsertTailList(&transfer->Transfer->DoubleBufferList,
  371. &dbHandle->DbLink);
  372. } else {
  373. InsertTailList(&transfer->DoubleBufferList,
  374. &dbHandle->DbLink);
  375. }
  376. }
  377. }
  378. VOID
  379. USBPORT_FlushAdapterDBs(
  380. PDEVICE_OBJECT FdoDeviceObject,
  381. PHCD_TRANSFER_CONTEXT Transfer
  382. )
  383. /*++
  384. Routine Description:
  385. Arguments:
  386. Return Value:
  387. none
  388. --*/
  389. {
  390. PDEVICE_EXTENSION devExt;
  391. PLIST_ENTRY listEntry;
  392. PUSBPORT_DB_HANDLE dbHandle;
  393. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  394. ASSERT_FDOEXT(devExt);
  395. ASSERT_TRANSFER(Transfer);
  396. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'flDB', Transfer,
  397. 0, 0);
  398. // dump the 4 dwords of the transfer buffer
  399. //{
  400. // PULONG p;
  401. //
  402. // p = (PULONG) Transfer->SgList.MdlVirtualAddress;
  403. // LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'dmp1', *(p),
  404. // *(p+1), *(p+2));
  405. //}
  406. while (!IsListEmpty(&Transfer->DoubleBufferList)) {
  407. listEntry = RemoveHeadList(&Transfer->DoubleBufferList);
  408. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'flle', Transfer,
  409. listEntry, 0);
  410. dbHandle = (PUSBPORT_DB_HANDLE) CONTAINING_RECORD(
  411. listEntry,
  412. struct _USBPORT_DB_HANDLE,
  413. DbLink);
  414. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'DBHf', Transfer,
  415. dbHandle, 0);
  416. ASSERT_DB_HANDLE(dbHandle);
  417. // flush to the system address
  418. RtlCopyMemory(dbHandle->DbSystemAddress,
  419. dbHandle->DbData,
  420. dbHandle->DbLength);
  421. FREE_POOL(FdoDeviceObject, dbHandle);
  422. }
  423. }