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.

610 lines
14 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. core.c
  5. Abstract:
  6. We maintain two lists for Transfer Irps
  7. (1)
  8. PendingTransferIrps - transfers on the endpoint pending List
  9. protected by PendingIrpLock
  10. (2)
  11. ActiveTransferIrps - transfers on the enpoint ACTIVE, CANCEL list
  12. or on the MapTransfer List
  13. protected by ActiveIrpLock
  14. each list has its own cancel and completion routine
  15. Environment:
  16. kernel mode only
  17. Notes:
  18. Revision History:
  19. 6-20-99 : created
  20. --*/
  21. #include "common.h"
  22. #ifdef ALLOC_PRAGMA
  23. #endif
  24. // non paged functions
  25. // USBPORT_QueuePendingTransferIrp
  26. // USBPORT_CancelPendingTransferIrp
  27. // USBPORT_InsertIrpInTable
  28. // USBPORT_RemoveIrpFromTable
  29. // USBPORT_FindIrpInTable
  30. VOID
  31. USBPORT_InsertIrpInTable(
  32. PDEVICE_OBJECT FdoDeviceObject,
  33. PUSBPORT_IRP_TABLE IrpTable,
  34. PIRP Irp
  35. )
  36. /*++
  37. Routine Description:
  38. Arguments:
  39. Return Value:
  40. --*/
  41. {
  42. ULONG i;
  43. PUSBPORT_IRP_TABLE t = IrpTable;
  44. USBPORT_ASSERT(IrpTable != NULL);
  45. t = (PUSBPORT_IRP_TABLE) &IrpTable;
  46. do {
  47. t = t->NextTable;
  48. for (i = 0; i<IRP_TABLE_LENGTH; i++) {
  49. if (t->Irps[i] == NULL) {
  50. t->Irps[i] = Irp;
  51. return;
  52. }
  53. }
  54. } while (t->NextTable);
  55. // no room, grow the table and recurse
  56. ALLOC_POOL_Z(t->NextTable, NonPagedPool,
  57. sizeof(USBPORT_IRP_TABLE));
  58. if (t->NextTable != NULL) {
  59. USBPORT_InsertIrpInTable(FdoDeviceObject, t->NextTable, Irp);
  60. } else {
  61. // we should handle this more gracefully
  62. // you can hit this in a low resource scenario
  63. BUGCHECK(USBBUGCODE_INTERNAL_ERROR, 0, 0, 0);
  64. }
  65. return;
  66. }
  67. PIRP
  68. USBPORT_RemoveIrpFromTable(
  69. PDEVICE_OBJECT FdoDeviceObject,
  70. PUSBPORT_IRP_TABLE IrpTable,
  71. PIRP Irp
  72. )
  73. /*++
  74. Routine Description:
  75. Arguments:
  76. Return Value:
  77. --*/
  78. {
  79. ULONG i;
  80. PUSBPORT_IRP_TABLE t = IrpTable;
  81. USBPORT_ASSERT(IrpTable != NULL);
  82. t = (PUSBPORT_IRP_TABLE) &IrpTable;
  83. do {
  84. t = t->NextTable;
  85. for (i = 0; i<IRP_TABLE_LENGTH; i++) {
  86. if (t->Irps[i] == Irp) {
  87. t->Irps[i] = NULL;
  88. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'rmIP', i, Irp, IrpTable);
  89. return Irp;
  90. }
  91. }
  92. } while (t->NextTable);
  93. return NULL;
  94. }
  95. PIRP
  96. USBPORT_FindUrbInIrpTable(
  97. PDEVICE_OBJECT FdoDeviceObject,
  98. PUSBPORT_IRP_TABLE IrpTable,
  99. PTRANSFER_URB Urb,
  100. PIRP InputIrp
  101. )
  102. /*++
  103. Routine Description:
  104. Given and table urb we scan for it in the the irp table
  105. if we find it it means the client has submitted the same
  106. urb twice.
  107. This function is used to validate client drivers, there is
  108. a small perf hit taken here but probably worth it.
  109. Arguments:
  110. Return Value:
  111. --*/
  112. {
  113. ULONG i;
  114. PUSBPORT_IRP_TABLE t = IrpTable;
  115. PIRP tIrp = NULL;
  116. PTRANSFER_URB urb;
  117. PIO_STACK_LOCATION irpStack;
  118. USBPORT_ASSERT(IrpTable != NULL);
  119. t = (PUSBPORT_IRP_TABLE) &IrpTable;
  120. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'fndU', t, Urb, 0);
  121. do {
  122. t = t->NextTable;
  123. for (i=0; i<IRP_TABLE_LENGTH; i++) {
  124. tIrp = t->Irps[i];
  125. if (tIrp != NULL) {
  126. irpStack = IoGetCurrentIrpStackLocation(tIrp);
  127. urb = irpStack->Parameters.Others.Argument1;
  128. if (urb == Urb) {
  129. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'fkkX', tIrp, urb, InputIrp);
  130. if (tIrp == InputIrp) {
  131. // this is a double submit by the client driver, that
  132. // is the irp is still pending
  133. BUGCHECK(USBBUGCODE_DOUBLE_SUBMIT, (ULONG_PTR) tIrp,
  134. (ULONG_PTR) urb, 0);
  135. } else {
  136. // this is the case where the URB is attached to
  137. // another irp
  138. BUGCHECK(USBBUGCODE_BAD_URB, (ULONG_PTR) tIrp, (ULONG_PTR) InputIrp,
  139. (ULONG_PTR) urb);
  140. }
  141. }
  142. }
  143. }
  144. } while (t->NextTable);
  145. return tIrp;
  146. }
  147. PIRP
  148. USBPORT_FindIrpInTable(
  149. PDEVICE_OBJECT FdoDeviceObject,
  150. PUSBPORT_IRP_TABLE IrpTable,
  151. PIRP Irp
  152. )
  153. /*++
  154. Routine Description:
  155. Arguments:
  156. Return Value:
  157. --*/
  158. {
  159. ULONG i;
  160. PUSBPORT_IRP_TABLE t = IrpTable;
  161. USBPORT_ASSERT(IrpTable != NULL);
  162. t = (PUSBPORT_IRP_TABLE) &IrpTable;
  163. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'fIPT', t, Irp, 0);
  164. do {
  165. t = t->NextTable;
  166. for (i = 0; i<IRP_TABLE_LENGTH; i++) {
  167. if (t->Irps[i] == Irp) {
  168. return Irp;
  169. }
  170. }
  171. } while (t->NextTable);
  172. return NULL;
  173. }
  174. VOID
  175. USBPORT_QueuePendingTransferIrp(
  176. PIRP Irp
  177. )
  178. /*++
  179. Routine Description:
  180. Arguments:
  181. Return Value:
  182. None.
  183. --*/
  184. {
  185. PHCD_TRANSFER_CONTEXT transfer;
  186. PHCD_ENDPOINT endpoint;
  187. KIRQL cancelIrql, irql;
  188. PDEVICE_OBJECT fdoDeviceObject;
  189. PIO_STACK_LOCATION irpStack;
  190. PDEVICE_EXTENSION devExt;
  191. PTRANSFER_URB urb;
  192. // on entry the urb is not cancelable ie
  193. // no cancel routine
  194. // extract the urb;
  195. irpStack = IoGetCurrentIrpStackLocation(Irp);
  196. urb = irpStack->Parameters.Others.Argument1;
  197. ASSERT_TRANSFER_URB(urb);
  198. transfer = urb->pd.HcdTransferContext;
  199. endpoint = transfer->Endpoint;
  200. fdoDeviceObject = endpoint->FdoDeviceObject;
  201. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  202. ASSERT_FDOEXT(devExt);
  203. LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'tIRP', transfer, endpoint, 0);
  204. USBPORT_ASSERT(Irp == transfer->Irp);
  205. USBPORT_ASSERT(Irp != NULL);
  206. Irp->IoStatus.Status = STATUS_PENDING;
  207. IoMarkIrpPending(Irp);
  208. ACQUIRE_PENDING_IRP_LOCK(devExt, irql);
  209. IoSetCancelRoutine(Irp, USBPORT_CancelPendingTransferIrp);
  210. if (Irp->Cancel &&
  211. IoSetCancelRoutine(Irp, NULL)) {
  212. // irp was canceled and our cancel routine
  213. // did not run
  214. RELEASE_PENDING_IRP_LOCK(devExt, irql);
  215. USBPORT_CompleteTransfer(urb,
  216. USBD_STATUS_CANCELED);
  217. } else {
  218. // cancel routine is set
  219. USBPORT_InsertPendingTransferIrp(fdoDeviceObject, Irp);
  220. USBPORT_QueuePendingUrbToEndpoint(endpoint, urb);
  221. RELEASE_PENDING_IRP_LOCK(devExt, irql);
  222. }
  223. }
  224. VOID
  225. USBPORT_CancelPendingTransferIrp(
  226. PDEVICE_OBJECT PdoDeviceObject,
  227. PIRP CancelIrp
  228. )
  229. /*++
  230. Routine Description:
  231. Arguments:
  232. Return Value:
  233. --*/
  234. {
  235. PIRP irp;
  236. PDEVICE_EXTENSION devExt, rhDevExt;
  237. PHCD_TRANSFER_CONTEXT transfer;
  238. PHCD_ENDPOINT endpoint;
  239. PIO_STACK_LOCATION irpStack;
  240. PDEVICE_OBJECT fdoDeviceObject;
  241. KIRQL irql;
  242. // release cancel spinlock
  243. IoReleaseCancelSpinLock(CancelIrp->CancelIrql);
  244. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  245. ASSERT_PDOEXT(rhDevExt);
  246. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  247. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  248. ASSERT_FDOEXT(devExt);
  249. LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'canP', fdoDeviceObject, CancelIrp, 0);
  250. ACQUIRE_PENDING_IRP_LOCK(devExt, irql);
  251. irp = USBPORT_RemovePendingTransferIrp(fdoDeviceObject, CancelIrp);
  252. if (irp) {
  253. PTRANSFER_URB urb;
  254. // found it
  255. irpStack = IoGetCurrentIrpStackLocation(CancelIrp);
  256. urb = irpStack->Parameters.Others.Argument1;
  257. ASSERT_TRANSFER_URB(urb);
  258. transfer = urb->pd.HcdTransferContext;
  259. endpoint = transfer->Endpoint;
  260. USBPORT_ASSERT(fdoDeviceObject == endpoint->FdoDeviceObject);
  261. ACQUIRE_ENDPOINT_LOCK(endpoint, fdoDeviceObject, 'Le10');
  262. // remove request from the endpoint,
  263. // it will be on the pending list
  264. #if DBG
  265. USBPORT_ASSERT(
  266. USBPORT_FindUrbInList(urb, &endpoint->PendingList));
  267. #endif
  268. RemoveEntryList(&transfer->TransferLink);
  269. transfer->TransferLink.Flink = NULL;
  270. transfer->TransferLink.Blink = NULL;
  271. RELEASE_ENDPOINT_LOCK(endpoint, fdoDeviceObject, 'Ue10');
  272. }
  273. RELEASE_PENDING_IRP_LOCK(devExt, irql);
  274. // noone nows about this irp anymore
  275. // complete it with status canceled
  276. if (irp) {
  277. USBPORT_CompleteTransfer(transfer->Urb,
  278. USBD_STATUS_CANCELED);
  279. }
  280. }
  281. VOID
  282. USBPORT_CancelActiveTransferIrp(
  283. PDEVICE_OBJECT PdoDeviceObject,
  284. PIRP CancelIrp
  285. )
  286. /*++
  287. Routine Description:
  288. Cancels come in on the root hub Pdo
  289. Arguments:
  290. Return Value:
  291. --*/
  292. {
  293. PIRP irp;
  294. PDEVICE_EXTENSION devExt, rhDevExt;
  295. PHCD_TRANSFER_CONTEXT transfer;
  296. PHCD_ENDPOINT endpoint;
  297. PIO_STACK_LOCATION irpStack;
  298. PDEVICE_OBJECT fdoDeviceObject;
  299. KIRQL irql;
  300. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  301. ASSERT_PDOEXT(rhDevExt);
  302. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  303. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  304. ASSERT_FDOEXT(devExt);
  305. LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'canA', fdoDeviceObject, CancelIrp, 0);
  306. // when we have the fdo we can release the global cancel lock
  307. IoReleaseCancelSpinLock(CancelIrp->CancelIrql);
  308. ACQUIRE_ACTIVE_IRP_LOCK(fdoDeviceObject, devExt, irql);
  309. irp = USBPORT_FindActiveTransferIrp(fdoDeviceObject, CancelIrp);
  310. // if irp is not on our list then we have already completed it.
  311. if (irp) {
  312. PTRANSFER_URB urb;
  313. USBPORT_ASSERT(irp == CancelIrp);
  314. LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'CANA', fdoDeviceObject, irp, 0);
  315. // found it
  316. // mark the transfer so it will be canceled the next
  317. // time we process the endpoint.
  318. irpStack = IoGetCurrentIrpStackLocation(irp);
  319. urb = irpStack->Parameters.Others.Argument1;
  320. ASSERT_TRANSFER_URB(urb);
  321. transfer = urb->pd.HcdTransferContext;
  322. endpoint = transfer->Endpoint;
  323. USBPORT_ASSERT(fdoDeviceObject == endpoint->FdoDeviceObject);
  324. ACQUIRE_ENDPOINT_LOCK(endpoint, fdoDeviceObject, 'LeI0');
  325. if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_SPLIT)) {
  326. KIRQL tIrql;
  327. PLIST_ENTRY listEntry;
  328. PHCD_TRANSFER_CONTEXT childTransfer;
  329. SET_FLAG(transfer->Flags, USBPORT_TXFLAG_CANCELED);
  330. ACQUIRE_TRANSFER_LOCK(fdoDeviceObject, transfer, tIrql);
  331. // mark all children as cancelled
  332. GET_HEAD_LIST(transfer->SplitTransferList, listEntry);
  333. while (listEntry &&
  334. listEntry != &transfer->SplitTransferList) {
  335. childTransfer = (PHCD_TRANSFER_CONTEXT) CONTAINING_RECORD(
  336. listEntry,
  337. struct _HCD_TRANSFER_CONTEXT,
  338. SplitLink);
  339. ASSERT_TRANSFER(childTransfer);
  340. SET_FLAG(childTransfer->Flags, USBPORT_TXFLAG_CANCELED);
  341. listEntry = childTransfer->SplitLink.Flink;
  342. }
  343. RELEASE_TRANSFER_LOCK(fdoDeviceObject, transfer, tIrql);
  344. } else {
  345. SET_FLAG(transfer->Flags, USBPORT_TXFLAG_CANCELED);
  346. }
  347. RELEASE_ENDPOINT_LOCK(endpoint, fdoDeviceObject, 'UeI0');
  348. RELEASE_ACTIVE_IRP_LOCK(fdoDeviceObject, devExt, irql);
  349. // if we canceled a transfer then
  350. // this endpoint needs attention
  351. USBPORT_InvalidateEndpoint(fdoDeviceObject,
  352. endpoint,
  353. IEP_SIGNAL_WORKER);
  354. } else {
  355. RELEASE_ACTIVE_IRP_LOCK(fdoDeviceObject, devExt, irql);
  356. }
  357. }
  358. PIRP
  359. USBPORT_FindActiveTransferIrp(
  360. PDEVICE_OBJECT FdoDeviceObject,
  361. PIRP Irp
  362. )
  363. /*++
  364. Routine Description:
  365. Arguments:
  366. Return Value:
  367. --*/
  368. {
  369. PDEVICE_EXTENSION devExt;
  370. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  371. ASSERT_FDOEXT(devExt);
  372. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'fnAC', 0, Irp, 0);
  373. return USBPORT_FindIrpInTable(FdoDeviceObject,
  374. devExt->ActiveTransferIrpTable,
  375. Irp);
  376. }
  377. PIRP
  378. USBPORT_RemoveActiveTransferIrp(
  379. PDEVICE_OBJECT FdoDeviceObject,
  380. PIRP Irp
  381. )
  382. /*++
  383. Routine Description:
  384. Arguments:
  385. Return Value:
  386. --*/
  387. {
  388. PDEVICE_EXTENSION devExt;
  389. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  390. ASSERT_FDOEXT(devExt);
  391. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'rmAC', 0, Irp, 0);
  392. return USBPORT_RemoveIrpFromTable(FdoDeviceObject,
  393. devExt->ActiveTransferIrpTable,
  394. Irp);
  395. }
  396. PIRP
  397. USBPORT_RemovePendingTransferIrp(
  398. PDEVICE_OBJECT FdoDeviceObject,
  399. PIRP Irp
  400. )
  401. /*++
  402. Routine Description:
  403. Arguments:
  404. Return Value:
  405. --*/
  406. {
  407. PDEVICE_EXTENSION devExt;
  408. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  409. ASSERT_FDOEXT(devExt);
  410. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'rmPN', 0, Irp, 0);
  411. return USBPORT_RemoveIrpFromTable(FdoDeviceObject,
  412. devExt->PendingTransferIrpTable,
  413. Irp);
  414. }
  415. VOID
  416. USBPORT_FreeIrpTable(
  417. PDEVICE_OBJECT FdoDeviceObject,
  418. PUSBPORT_IRP_TABLE BaseIrpTable
  419. )
  420. /*++
  421. Routine Description:
  422. Arguments:
  423. Return Value:
  424. --*/
  425. {
  426. PUSBPORT_IRP_TABLE tmp;
  427. while (BaseIrpTable != NULL) {
  428. tmp = BaseIrpTable->NextTable;
  429. FREE_POOL(FdoDeviceObject, BaseIrpTable);
  430. BaseIrpTable = tmp;
  431. };
  432. }