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.

217 lines
7.9 KiB

  1. /*
  2. *************************************************************************
  3. * File: URBFUNC.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 <stdio.h>
  17. #include <usbdi.h>
  18. #include <usbdlib.h>
  19. #include <usbioctl.h>
  20. #include "usbccgp.h"
  21. #include "debug.h"
  22. /*
  23. * UrbFunctionSelectConfiguration
  24. *
  25. *
  26. */
  27. NTSTATUS UrbFunctionSelectConfiguration(PFUNCTION_PDO_EXT functionPdoExt, PURB urb)
  28. {
  29. NTSTATUS status = NO_STATUS;
  30. if (urb->UrbSelectConfiguration.ConfigurationDescriptor){
  31. PUSBD_INTERFACE_INFORMATION urbIface = &urb->UrbSelectConfiguration.Interface;
  32. PUSBD_INTERFACE_LIST_ENTRY iface, funcIface = NULL;
  33. ULONG i;
  34. ASSERT(ISPTR(functionPdoExt->functionInterfaceList));
  35. iface = functionPdoExt->functionInterfaceList;
  36. for (i = 0; i < functionPdoExt->numInterfaces; i++){
  37. if (iface->Interface->InterfaceNumber == urbIface->InterfaceNumber){
  38. funcIface = iface;
  39. break;
  40. }
  41. iface++;
  42. }
  43. if (funcIface && funcIface->Interface){
  44. BOOLEAN sendSelectIface = FALSE;
  45. BOOLEAN selectAltIface = FALSE;
  46. /*
  47. * To service the client's SELECT_CONFIGURATION call, we only need to
  48. * call the parent if the client is:
  49. * 1. Selecting a different alternate interface
  50. * or
  51. * 2. Changing the MaximumTransferSize for one of the pipes.
  52. *
  53. * In either of those cases, we send down a SELECT_INTERFACE request.
  54. */
  55. if (funcIface->Interface->AlternateSetting != urbIface->AlternateSetting){
  56. DBGWARN(("Coverage: Changing alt iface in UrbFunctionSelectConfiguration (iface #%xh from %xh to %xh).", urbIface->InterfaceNumber, funcIface->Interface->AlternateSetting, urbIface->AlternateSetting));
  57. sendSelectIface = TRUE;
  58. selectAltIface = TRUE;
  59. }
  60. else {
  61. ULONG numPipes;
  62. //
  63. // We shouldn't be looking at NumberOfPipes in the URB because this is an
  64. // OUTPUT field.
  65. // ASSERT(urbIface->NumberOfPipes == funcIface->Interface->NumberOfPipes);
  66. // numPipes = MIN(urbIface->NumberOfPipes, funcIface->Interface->NumberOfPipes);
  67. numPipes = funcIface->Interface->NumberOfPipes;
  68. for (i = 0; i < numPipes; i++){
  69. if (urbIface->Pipes[i].MaximumTransferSize != funcIface->Interface->Pipes[i].MaximumTransferSize){
  70. DBGWARN(("Coverage: Changing MaximumTransferSize in UrbFunctionSelectConfiguration (from %xh to %xh).", funcIface->Interface->Pipes[i].MaximumTransferSize, urbIface->Pipes[i].MaximumTransferSize));
  71. sendSelectIface = TRUE;
  72. }
  73. }
  74. }
  75. if (sendSelectIface){
  76. PURB selectIfaceUrb;
  77. USHORT size;
  78. //
  79. // BUT, when choosing an alternate interface, we must use the NumberOfPipes in
  80. // the URB.
  81. //
  82. if (selectAltIface){
  83. size = (USHORT)(GET_SELECT_INTERFACE_REQUEST_SIZE(urbIface->NumberOfPipes));
  84. }
  85. else {
  86. size = (USHORT)(GET_SELECT_INTERFACE_REQUEST_SIZE(funcIface->Interface->NumberOfPipes));
  87. }
  88. selectIfaceUrb = ALLOCPOOL(NonPagedPool, size);
  89. if (selectIfaceUrb){
  90. PUSBD_INTERFACE_INFORMATION selectIface = &selectIfaceUrb->UrbSelectInterface.Interface;
  91. selectIfaceUrb->UrbSelectInterface.Hdr.Function = URB_FUNCTION_SELECT_INTERFACE;
  92. selectIfaceUrb->UrbSelectInterface.Hdr.Length = size;
  93. ASSERT(functionPdoExt->parentFdoExt->selectedConfigHandle);
  94. selectIfaceUrb->UrbSelectInterface.ConfigurationHandle = functionPdoExt->parentFdoExt->selectedConfigHandle;
  95. RtlCopyMemory(selectIface, urbIface, urbIface->Length);
  96. status = SubmitUrb(functionPdoExt->parentFdoExt, selectIfaceUrb, TRUE, NULL, NULL);
  97. if (NT_SUCCESS(status)){
  98. /*
  99. * Replace the old PUSBD_INTERFACE_INFORMATION
  100. * (which we got when we did select-configuration for the parent)
  101. * with the new one.
  102. */
  103. ASSERT(funcIface->Interface);
  104. FREEPOOL(funcIface->Interface);
  105. funcIface->Interface = MemDup(selectIface, selectIface->Length);
  106. if (!funcIface->Interface){
  107. status = STATUS_INSUFFICIENT_RESOURCES;
  108. }
  109. }
  110. else {
  111. ASSERT(NT_SUCCESS(status));
  112. }
  113. FREEPOOL(selectIfaceUrb);
  114. }
  115. else {
  116. ASSERT(selectIfaceUrb);
  117. status = STATUS_INSUFFICIENT_RESOURCES;
  118. }
  119. }
  120. else {
  121. status = STATUS_SUCCESS;
  122. }
  123. if (NT_SUCCESS(status)){
  124. /*
  125. * Copy the interface information
  126. */
  127. ASSERT(urbIface->Length == funcIface->Interface->Length);
  128. RtlCopyMemory(urbIface, funcIface->Interface, funcIface->Interface->Length);
  129. ASSERT(functionPdoExt->parentFdoExt->selectedConfigHandle);
  130. urb->UrbSelectConfiguration.ConfigurationHandle = functionPdoExt->parentFdoExt->selectedConfigHandle;
  131. }
  132. }
  133. else {
  134. DBGERR(("invalid interface number"));
  135. status = STATUS_INVALID_PARAMETER;
  136. }
  137. }
  138. else {
  139. DBGVERBOSE(("FunctionInternalDeviceControl - closing configuration"));
  140. status = STATUS_SUCCESS;
  141. }
  142. return status;
  143. }
  144. /*
  145. * UrbFunctionGetDescriptorFromDevice
  146. *
  147. *
  148. * Note: this function cannot be pageable because internal
  149. * ioctls may be sent at IRQL==DISPATCH_LEVEL.
  150. */
  151. NTSTATUS UrbFunctionGetDescriptorFromDevice(PFUNCTION_PDO_EXT functionPdoExt, PURB urb)
  152. {
  153. NTSTATUS status;
  154. switch (urb->UrbControlDescriptorRequest.DescriptorType){
  155. case USB_DEVICE_DESCRIPTOR_TYPE:
  156. DBGVERBOSE((" USB_DEVICE_DESCRIPTOR_TYPE"));
  157. if (urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR)){
  158. RtlCopyMemory( urb->UrbControlDescriptorRequest.TransferBuffer,
  159. &functionPdoExt->functionDeviceDesc,
  160. sizeof(USB_DEVICE_DESCRIPTOR));
  161. status = STATUS_SUCCESS;
  162. }
  163. else {
  164. status = STATUS_INVALID_BUFFER_SIZE;
  165. }
  166. urb->UrbControlDescriptorRequest.TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
  167. break;
  168. case USB_CONFIGURATION_DESCRIPTOR_TYPE:
  169. DBGVERBOSE((" USB_CONFIGURATION_DESCRIPTOR_TYPE"));
  170. status = BuildFunctionConfigurationDescriptor(
  171. functionPdoExt,
  172. urb->UrbControlDescriptorRequest.TransferBuffer,
  173. urb->UrbControlDescriptorRequest.TransferBufferLength,
  174. &urb->UrbControlDescriptorRequest.TransferBufferLength);
  175. break;
  176. default:
  177. /*
  178. * Return NO_STATUS so that URB gets passed down to USBHUB.
  179. */
  180. DBGVERBOSE(("UrbFunctionGetDescriptorFromDevice: Unhandled desc type: %xh.", (ULONG)urb->UrbControlDescriptorRequest.DescriptorType));
  181. status = NO_STATUS;
  182. break;
  183. }
  184. return status;
  185. }