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.

401 lines
12 KiB

  1. /*
  2. *************************************************************************
  3. * File: DISPATCH.C
  4. *
  5. * Module: USBCCGP.SYS
  6. * USB Common Class Generic Parent driver.
  7. *
  8. * Copyright (c) 1998 Microsoft Corporation
  9. *
  10. *
  11. * Author: ervinp
  12. *
  13. *************************************************************************
  14. */
  15. #include <wdm.h>
  16. #include <windef.h>
  17. #include <unknown.h>
  18. #ifdef DRM_SUPPORT
  19. #include <ks.h>
  20. #include <ksmedia.h>
  21. #include <drmk.h>
  22. #include <ksdrmhlp.h>
  23. #endif
  24. #include <usbdi.h>
  25. #include <usbdlib.h>
  26. #include <usbioctl.h>
  27. #include "usbccgp.h"
  28. #include "debug.h"
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(PAGE, USBC_Create)
  31. #pragma alloc_text(PAGE, USBC_DeviceControl)
  32. #pragma alloc_text(PAGE, USBC_SystemControl)
  33. #pragma alloc_text(PAGE, USBC_Power)
  34. #ifdef DRM_SUPPORT
  35. #pragma alloc_text(PAGE, USBC_SetContentId)
  36. #endif
  37. #endif
  38. /*
  39. * USBC_Dispatch
  40. *
  41. * Note: this function cannot be pageable because reads can
  42. * come in at DISPATCH level.
  43. */
  44. NTSTATUS USBC_Dispatch(IN PDEVICE_OBJECT devObj, IN PIRP irp)
  45. {
  46. PIO_STACK_LOCATION irpSp;
  47. PDEVEXT devExt;
  48. PPARENT_FDO_EXT parentFdoExt;
  49. PFUNCTION_PDO_EXT functionPdoExt;
  50. ULONG majorFunction, minorFunction;
  51. BOOLEAN isParentFdo;
  52. NTSTATUS status;
  53. BOOLEAN abortIrp = FALSE;
  54. devExt = devObj->DeviceExtension;
  55. ASSERT(devExt);
  56. ASSERT(devExt->signature == USBCCGP_TAG);
  57. irpSp = IoGetCurrentIrpStackLocation(irp);
  58. /*
  59. * Keep these privately so we still have it after the IRP completes
  60. * or after the device extension is freed on a REMOVE_DEVICE
  61. */
  62. majorFunction = irpSp->MajorFunction;
  63. minorFunction = irpSp->MinorFunction;
  64. isParentFdo = devExt->isParentFdo;
  65. DBG_LOG_IRP_MAJOR(irp, majorFunction, isParentFdo, FALSE, 0);
  66. if (isParentFdo){
  67. parentFdoExt = &devExt->parentFdoExt;
  68. functionPdoExt = BAD_POINTER;
  69. }
  70. else {
  71. functionPdoExt = &devExt->functionPdoExt;
  72. parentFdoExt = functionPdoExt->parentFdoExt;
  73. }
  74. /*
  75. * For all IRPs except REMOVE, we increment the PendingActionCount
  76. * across the dispatch routine in order to prevent a race condition with
  77. * the REMOVE_DEVICE IRP (without this increment, if REMOVE_DEVICE
  78. * preempted another IRP, device object and extension might get
  79. * freed while the second thread was still using it).
  80. */
  81. if (!((majorFunction == IRP_MJ_PNP) && (minorFunction == IRP_MN_REMOVE_DEVICE))){
  82. IncrementPendingActionCount(parentFdoExt);
  83. }
  84. /*
  85. * Make sure we don't process any IRPs besides PNP and CLOSE
  86. * while a device object is getting removed.
  87. * Do this after we've incremented the pendingActionCount for this IRP.
  88. */
  89. if ((majorFunction != IRP_MJ_PNP) && (majorFunction != IRP_MJ_CLOSE)){
  90. enum deviceState state = (isParentFdo) ? parentFdoExt->state : functionPdoExt->state;
  91. if (!isParentFdo && majorFunction == IRP_MJ_POWER) {
  92. /*
  93. * Don't abort power IRP's on child function PDO's, even if
  94. * state is STATE_REMOVING or STATE_REMOVED as this will veto
  95. * a suspend request if the child function PDO is disabled.
  96. */
  97. ;
  98. } else if ((state == STATE_REMOVING) || (state == STATE_REMOVED)){
  99. abortIrp = TRUE;
  100. }
  101. }
  102. if (abortIrp){
  103. /*
  104. * Fail all irps after a remove irp.
  105. * This should never happen except:
  106. * we can get a power irp on a function pdo after a remove
  107. * because (per splante) the power state machine is not synchronized
  108. * with the pnp state machine. We now handle this case above.
  109. */
  110. DBGWARN(("Aborting IRP %ph (function %xh/%xh) because delete pending", irp, majorFunction, minorFunction));
  111. ASSERT((majorFunction == IRP_MJ_POWER) && !isParentFdo);
  112. status = irp->IoStatus.Status = STATUS_DELETE_PENDING;
  113. if (majorFunction == IRP_MJ_POWER){
  114. PoStartNextPowerIrp(irp);
  115. }
  116. IoCompleteRequest(irp, IO_NO_INCREMENT);
  117. }
  118. else {
  119. switch (majorFunction){
  120. case IRP_MJ_CREATE:
  121. status = USBC_Create(devExt, irp);
  122. break;
  123. case IRP_MJ_CLOSE:
  124. status = USBC_Close(devExt, irp);
  125. break;
  126. case IRP_MJ_DEVICE_CONTROL:
  127. status = USBC_DeviceControl(devExt, irp);
  128. break;
  129. case IRP_MJ_SYSTEM_CONTROL:
  130. status = USBC_SystemControl(devExt, irp);
  131. break;
  132. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  133. status = USBC_InternalDeviceControl(devExt, irp);
  134. break;
  135. case IRP_MJ_PNP:
  136. status = USBC_PnP(devExt, irp);
  137. break;
  138. case IRP_MJ_POWER:
  139. status = USBC_Power(devExt, irp);
  140. break;
  141. default:
  142. DBGERR(("USBC_Dispatch: unsupported irp majorFunction %xh.", majorFunction));
  143. if (isParentFdo){
  144. /*
  145. * Pass this IRP to the parent device.
  146. */
  147. IoSkipCurrentIrpStackLocation(irp);
  148. status = IoCallDriver(parentFdoExt->topDevObj, irp);
  149. }
  150. else {
  151. /*
  152. * This is not a pnp/power/syscntrl irp, so we fail unsupported irps
  153. * with an actual error code (not with the default status).
  154. */
  155. status = irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  156. IoCompleteRequest(irp, IO_NO_INCREMENT);
  157. }
  158. break;
  159. }
  160. }
  161. DBG_LOG_IRP_MAJOR(irp, majorFunction, isParentFdo, TRUE, status);
  162. /*
  163. * Balance the increment above
  164. */
  165. if (!((majorFunction == IRP_MJ_PNP) && (minorFunction == IRP_MN_REMOVE_DEVICE))){
  166. DecrementPendingActionCount(parentFdoExt);
  167. }
  168. return status;
  169. }
  170. NTSTATUS USBC_Create(PDEVEXT devExt, PIRP irp)
  171. {
  172. NTSTATUS status;
  173. PAGED_CODE();
  174. if (devExt->isParentFdo){
  175. PPARENT_FDO_EXT parentFdoExt = &devExt->parentFdoExt;
  176. IoSkipCurrentIrpStackLocation(irp);
  177. status = IoCallDriver(parentFdoExt->topDevObj, irp);
  178. }
  179. else {
  180. /*
  181. * This is not a pnp/power/syscntrl irp, so we fail unsupported irps
  182. * with an actual error code (not with the default status).
  183. */
  184. status = irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  185. IoCompleteRequest(irp, IO_NO_INCREMENT);
  186. }
  187. return status;
  188. }
  189. NTSTATUS USBC_Close(PDEVEXT devExt, PIRP irp)
  190. {
  191. NTSTATUS status;
  192. if (devExt->isParentFdo){
  193. PPARENT_FDO_EXT parentFdoExt = &devExt->parentFdoExt;
  194. IoSkipCurrentIrpStackLocation(irp);
  195. status = IoCallDriver(parentFdoExt->topDevObj, irp);
  196. }
  197. else {
  198. /*
  199. * This is not a pnp/power/syscntrl irp, so we fail unsupported irps
  200. * with an actual error code (not with the default status).
  201. */
  202. status = irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  203. IoCompleteRequest(irp, IO_NO_INCREMENT);
  204. }
  205. return status;
  206. }
  207. #ifdef DRM_SUPPORT
  208. /*****************************************************************************
  209. * USBC_SetContentId
  210. *****************************************************************************
  211. *
  212. */
  213. NTSTATUS
  214. USBC_SetContentId
  215. (
  216. IN PIRP irp,
  217. IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
  218. IN PKSDRMAUDIOSTREAM_CONTENTID pvData
  219. )
  220. {
  221. ULONG ContentId;
  222. PIO_STACK_LOCATION iostack;
  223. PDEVEXT devExt;
  224. USBD_PIPE_HANDLE hPipe;
  225. NTSTATUS status;
  226. PAGED_CODE();
  227. ASSERT(irp);
  228. ASSERT(pKsProperty);
  229. ASSERT(pvData);
  230. iostack = IoGetCurrentIrpStackLocation(irp);
  231. devExt = iostack->DeviceObject->DeviceExtension;
  232. hPipe = pKsProperty->Context;
  233. ContentId = pvData->ContentId;
  234. if (devExt->isParentFdo){
  235. // IOCTL sent to parent FDO. Forward to down the stack.
  236. PPARENT_FDO_EXT parentFdoExt = &devExt->parentFdoExt;
  237. status = pKsProperty->DrmForwardContentToDeviceObject(ContentId, parentFdoExt->topDevObj, hPipe);
  238. }
  239. else {
  240. // IOCTL send to function PDO. Forward to parent FDO on other stack.
  241. PFUNCTION_PDO_EXT functionPdoExt = &devExt->functionPdoExt;
  242. PPARENT_FDO_EXT parentFdoExt = functionPdoExt->parentFdoExt;
  243. status = pKsProperty->DrmForwardContentToDeviceObject(ContentId, parentFdoExt->fdo, hPipe);
  244. }
  245. return status;
  246. }
  247. #endif
  248. NTSTATUS USBC_DeviceControl(PDEVEXT devExt, PIRP irp)
  249. {
  250. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  251. ULONG ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
  252. NTSTATUS status;
  253. PAGED_CODE();
  254. #ifdef DRM_SUPPORT
  255. if (IOCTL_KS_PROPERTY == ioControlCode) {
  256. status = KsPropertyHandleDrmSetContentId(irp, USBC_SetContentId);
  257. irp->IoStatus.Status = status;
  258. IoCompleteRequest(irp, IO_NO_INCREMENT);
  259. } else {
  260. #endif
  261. if (devExt->isParentFdo){
  262. PPARENT_FDO_EXT parentFdoExt = &devExt->parentFdoExt;
  263. status = ParentDeviceControl(parentFdoExt, irp);
  264. }
  265. else {
  266. /*
  267. * Pass the IOCTL IRP sent to our child PDO to our own parent FDO.
  268. */
  269. PFUNCTION_PDO_EXT functionPdoExt = &devExt->functionPdoExt;
  270. PPARENT_FDO_EXT parentFdoExt = functionPdoExt->parentFdoExt;
  271. IoCopyCurrentIrpStackLocationToNext(irp);
  272. status = IoCallDriver(parentFdoExt->fdo, irp);
  273. }
  274. #ifdef DRM_SUPPORT
  275. }
  276. #endif
  277. DBG_LOG_IOCTL(ioControlCode, status);
  278. return status;
  279. }
  280. NTSTATUS USBC_SystemControl(PDEVEXT devExt, PIRP irp)
  281. {
  282. NTSTATUS status;
  283. PAGED_CODE();
  284. if (devExt->isParentFdo){
  285. PPARENT_FDO_EXT parentFdoExt = &devExt->parentFdoExt;
  286. IoSkipCurrentIrpStackLocation(irp);
  287. status = IoCallDriver(parentFdoExt->topDevObj, irp);
  288. }
  289. else {
  290. /*
  291. * Pass the IOCTL IRP sent to our child PDO to our own parent FDO.
  292. */
  293. PFUNCTION_PDO_EXT functionPdoExt = &devExt->functionPdoExt;
  294. PPARENT_FDO_EXT parentFdoExt = functionPdoExt->parentFdoExt;
  295. IoCopyCurrentIrpStackLocationToNext(irp);
  296. status = IoCallDriver(parentFdoExt->fdo, irp);
  297. }
  298. return status;
  299. }
  300. /*
  301. * USBC_InternalDeviceControl
  302. *
  303. *
  304. * Note: this function cannot be pageable because internal
  305. * ioctls may be sent at IRQL==DISPATCH_LEVEL.
  306. */
  307. NTSTATUS USBC_InternalDeviceControl(PDEVEXT devExt, PIRP irp)
  308. {
  309. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  310. ULONG ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
  311. NTSTATUS status;
  312. if (devExt->isParentFdo){
  313. PPARENT_FDO_EXT parentFdoExt = &devExt->parentFdoExt;
  314. status = ParentInternalDeviceControl(parentFdoExt, irp);
  315. }
  316. else {
  317. PFUNCTION_PDO_EXT functionPdoExt = &devExt->functionPdoExt;
  318. status = FunctionInternalDeviceControl(functionPdoExt, irp);
  319. }
  320. DBG_LOG_IOCTL(ioControlCode, status);
  321. return status;
  322. }
  323. NTSTATUS USBC_Power(PDEVEXT devExt, PIRP irp)
  324. {
  325. NTSTATUS status;
  326. PAGED_CODE();
  327. if (devExt->isParentFdo){
  328. PPARENT_FDO_EXT parentFdoExt = &devExt->parentFdoExt;
  329. status = HandleParentFdoPower(parentFdoExt, irp);
  330. }
  331. else {
  332. PFUNCTION_PDO_EXT functionPdoExt = &devExt->functionPdoExt;
  333. status = HandleFunctionPdoPower(functionPdoExt, irp);
  334. }
  335. return status;
  336. }