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.

1741 lines
53 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. config.c
  5. Abstract:
  6. handles configuration and interface URBs
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. 6-20-99 : created
  12. --*/
  13. #include "common.h"
  14. // paged functions
  15. #ifdef ALLOC_PRAGMA
  16. //#pragma alloc_text(PAGE, USBPORT_SelectInterface)
  17. #pragma alloc_text(PAGE, USBPORT_SelectConfiguration)
  18. #pragma alloc_text(PAGE, USBPORT_InitializeConfigurationHandle)
  19. #pragma alloc_text(PAGE, USBPORT_InternalOpenInterface)
  20. #pragma alloc_text(PAGE, USBPORT_InternalCloseConfiguration)
  21. #pragma alloc_text(PAGE, USBPORT_InternalParseConfigurationDescriptor)
  22. #pragma alloc_text(PAGE, USBPORT_InternalGetInterfaceLength)
  23. #endif
  24. // non paged functions
  25. USBD_PIPE_TYPE PipeTypes[4] = {UsbdPipeTypeControl, UsbdPipeTypeIsochronous,
  26. UsbdPipeTypeBulk, UsbdPipeTypeInterrupt};
  27. NTSTATUS
  28. USBPORT_SelectInterface(
  29. PDEVICE_OBJECT FdoDeviceObject,
  30. PIRP Irp,
  31. PURB Urb
  32. )
  33. /*++
  34. Routine Description:
  35. Select an alternate interface for a USB device. The orginal
  36. USBD code only supported selecting a single alternate interface
  37. so we will as well.
  38. Client will(should) pass in a URB buffer that looks like this:
  39. +------------------------------+
  40. |Hdr |
  41. |(_URB_HEADER) |
  42. | - <caller inputs> |
  43. | Function |
  44. | Length |
  45. | UsbdDeviceHandle |
  46. | |
  47. | - <port outputs> |
  48. | Status |
  49. +------------------------------+
  50. | - <caller inputs> |
  51. | ConfigurationHandle |
  52. +------------------------------+
  53. |Interface |
  54. |(USBD_INTERFACE_INFORMATION) |
  55. | - <caller inputs> |
  56. | Length |
  57. | InterfaceNumber |
  58. | AlternateSetting |
  59. | |
  60. | - <port outputs> |
  61. | InterfaceHandle |
  62. | NumberOfPipes |
  63. | SubClass |
  64. | Class |
  65. | Protocol |
  66. +------------------------------+
  67. |Pipes[0] | one of these for each pipe in the
  68. |(USBD_PIPE_INFORMATION) | interface
  69. | - <caller inputs> |
  70. | PipeFlags |
  71. | MaximumPacketSize (opt) |
  72. | |
  73. | - <port outputs> |
  74. +------------------------------+
  75. |Pipes[1] |
  76. +------------------------------+
  77. |.... |
  78. +------------------------------+
  79. |Pipes[n] |
  80. +------------------------------+
  81. Arguments:
  82. Return Value:
  83. --*/
  84. {
  85. NTSTATUS ntStatus;
  86. PUSBD_CONFIG_HANDLE configHandle = NULL;
  87. ULONG i;
  88. PDEVICE_EXTENSION devExt;
  89. PUSBD_DEVICE_HANDLE deviceHandle;
  90. PUSBD_INTERFACE_INFORMATION interfaceI;
  91. PUSBD_INTERFACE_HANDLE_I iHandle, iHandleNew;
  92. USHORT tmp;
  93. USBD_STATUS usbdStatus;
  94. PAGED_CODE();
  95. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  96. ASSERT_FDOEXT(devExt);
  97. GET_DEVICE_HANDLE(deviceHandle, Urb);
  98. LOCK_DEVICE(deviceHandle, FdoDeviceObject);
  99. // validate the configuration handle input
  100. configHandle = Urb->UrbSelectInterface.ConfigurationHandle;
  101. ASSERT_CONFIG_HANDLE(configHandle);
  102. //
  103. // will are interested in the alt setting of a specific
  104. // interface based on the interface number.
  105. //
  106. iHandle = NULL;
  107. interfaceI = &Urb->UrbSelectInterface.Interface;
  108. // validate the Length field in the Urb header, we can
  109. // figure out the correct value based on the interface
  110. // information passed in
  111. tmp = interfaceI->Length + sizeof(struct _URB_HEADER)
  112. + sizeof(configHandle);
  113. if (tmp != Urb->UrbHeader.Length) {
  114. // client passed in bogus total length, warn if in
  115. // 'verifier' mode.
  116. USBPORT_DebugClient(
  117. ("client driver passed invalid Urb.Header.Length\n"));
  118. // generally cleints mess up the header length so
  119. // we will override with the length we calculated
  120. // from the interface-information.
  121. Urb->UrbHeader.Length = tmp;
  122. }
  123. // validate the interfaceI structure passed to us by the client
  124. usbdStatus = USBPORT_InitializeInterfaceInformation(FdoDeviceObject,
  125. interfaceI,
  126. configHandle);
  127. if (usbdStatus == USBD_STATUS_SUCCESS) {
  128. // find the interface handle for the interface we are
  129. // interested in, if it is currently open we will need
  130. // to close it.
  131. iHandle = USBPORT_GetInterfaceHandle(FdoDeviceObject,
  132. configHandle,
  133. interfaceI->InterfaceNumber);
  134. if (iHandle != NULL) {
  135. // unlink this handle
  136. RemoveEntryList(&iHandle->InterfaceLink);
  137. // we have a handle
  138. ASSERT_INTERFACE(iHandle);
  139. // close the pipes in this interface, note that we
  140. // force the pipes closed unlike past versions of
  141. // USBD and force the client driver to deal with the
  142. // consequences if it has transfers outstanding.
  143. // attempt to close all endpoints in this interface
  144. for (i=0; i < iHandle->InterfaceDescriptor.bNumEndpoints; i++) {
  145. USBPORT_ClosePipe(deviceHandle,
  146. FdoDeviceObject,
  147. &iHandle->PipeHandle[i]);
  148. }
  149. }
  150. //
  151. // Now open the new interface with the new alternate setting
  152. //
  153. iHandleNew = NULL;
  154. usbdStatus = USBPORT_InternalOpenInterface(Urb,
  155. deviceHandle,
  156. FdoDeviceObject,
  157. configHandle,
  158. interfaceI,
  159. &iHandleNew,
  160. TRUE);
  161. }
  162. if (usbdStatus == USBD_STATUS_SUCCESS) {
  163. //
  164. // successfully opened the new interface,
  165. // we can free the old handle now if we
  166. // had one.
  167. //
  168. if (iHandle != NULL ) {
  169. #if DBG
  170. // all pipes should be closed
  171. for (i=0; i < iHandle->InterfaceDescriptor.bNumEndpoints; i++) {
  172. USBPORT_ASSERT(iHandle->PipeHandle[i].ListEntry.Flink == NULL &&
  173. iHandle->PipeHandle[i].ListEntry.Blink == NULL);
  174. }
  175. #endif
  176. FREE_POOL(FdoDeviceObject, iHandle);
  177. iHandle = NULL;
  178. }
  179. // return the 'new' handle
  180. interfaceI->InterfaceHandle = iHandleNew;
  181. // associate it with this configuration
  182. InsertTailList(&configHandle->InterfaceHandleList,
  183. &iHandleNew->InterfaceLink);
  184. } else {
  185. //
  186. // selecting the aternate interface failed.
  187. // Possible reasons:
  188. //
  189. // 1. we didn't have enough BW
  190. // 2. the device stalled the set_interface request
  191. // 3. The set_interface request failed because the
  192. // device is gone
  193. // 4. USBPORT_InitializeInterfaceInformation() failed due
  194. // bad parameters.
  195. // attempt to re-open the original alt-interface so that
  196. // the client still has the bandwidth
  197. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'slI!',
  198. usbdStatus,
  199. 0,
  200. 0);
  201. if (usbdStatus == USBD_STATUS_NO_BANDWIDTH) {
  202. // HISTORICAL NOTE:
  203. // The 2k USBD driver attempted to re-open the original
  204. // alt-setting on a failure to allocate bw. This would
  205. // leave the client with the bw it had when calling in
  206. // to select the new interface.
  207. //
  208. // I don't beleive that any drivers use this feature
  209. // and many drivers attempt to allocate BW in a loop
  210. // until they succeed.
  211. //
  212. // So as a performance optimization we will return
  213. // with no bandwidth allocated to the caller -- the
  214. // pipe handles will be invalid.
  215. // This should speed things up since the realloc of
  216. // the old bandwidth takes time.
  217. interfaceI->InterfaceHandle = USBPORT_BAD_HANDLE;
  218. } else {
  219. // case 2,3 we just fail the request and set the interface
  220. // handle to 'bad handle'
  221. interfaceI->InterfaceHandle = USBPORT_BAD_HANDLE;
  222. }
  223. // client has no reference to it and we closed it
  224. // free the structure here
  225. if (iHandle != NULL ) {
  226. #if DBG
  227. // all pipes should be closed
  228. for (i=0; i < iHandle->InterfaceDescriptor.bNumEndpoints; i++) {
  229. USBPORT_ASSERT(iHandle->PipeHandle[i].ListEntry.Flink == NULL &&
  230. iHandle->PipeHandle[i].ListEntry.Blink == NULL);
  231. }
  232. #endif
  233. FREE_POOL(FdoDeviceObject, iHandle);
  234. iHandle = NULL;
  235. }
  236. }
  237. UNLOCK_DEVICE(deviceHandle, FdoDeviceObject);
  238. ntStatus = SET_USBD_ERROR(Urb, usbdStatus);
  239. return ntStatus;
  240. }
  241. NTSTATUS
  242. USBPORT_SelectConfiguration(
  243. PDEVICE_OBJECT FdoDeviceObject,
  244. PIRP Irp,
  245. PURB Urb
  246. )
  247. /*++
  248. Routine Description:
  249. Open a configuration for a USB device.
  250. Client will(should) pass in a URB buffer that looks like this:
  251. +------------------------------+
  252. |Hdr |
  253. |(_URB_HEADER) |
  254. | - <caller inputs> |
  255. | Function |
  256. | Length |
  257. | UsbdDeviceHandle |
  258. | |
  259. | - <port outputs> |
  260. | Status |
  261. +------------------------------+
  262. | - <caller inputs> |
  263. | ConfigurationDescriptor |
  264. | - <port outputs> |
  265. | ConfigurationHandle |
  266. +------------------------------+
  267. |Interface(0) |
  268. |(USBD_INTERFACE_INFORMATION) |
  269. | - <caller inputs> |
  270. | Length |
  271. | InterfaceNumber |
  272. | AlternateSetting |
  273. | |
  274. | - <port outputs> |
  275. | InterfaceHandle |
  276. | NumberOfPipes |
  277. | SubClass |
  278. | Class |
  279. | Protocol |
  280. +------------------------------+
  281. |Pipes[0] | one of these for each pipe in the
  282. |(USBD_PIPE_INFORMATION) | interface
  283. | - <caller inputs> |
  284. | |
  285. | - <port outputs> |
  286. +------------------------------+
  287. |Pipes[1] |
  288. +------------------------------+
  289. |.... |
  290. +------------------------------+
  291. |Pipes[n] |
  292. +------------------------------+
  293. | Interface(1) | one of these for each interface in
  294. | | the configuration
  295. +------------------------------+
  296. |Pipes[1] |
  297. +------------------------------+
  298. |.... |
  299. +------------------------------+
  300. |Pipes[n] |
  301. +------------------------------+
  302. On input:
  303. The ConfigurationDescriptor must specify the number of interfaces
  304. in the configuration.
  305. The InterfaceInformation will specify a specific alt setting to be
  306. selected for each interface.
  307. 1. First we look at the configuration descriptor for the
  308. requested configuration and validate the client
  309. input buffer agianst it.
  310. 2. We open the interfaces for the requested configuration
  311. and open the pipes within those interfaces, setting
  312. alt settings were appropriate.
  313. 3. We set the configuration for the device with the
  314. appropriate control request.
  315. Arguments:
  316. DeviceObject -
  317. Irp - IO request block
  318. Urb - ptr to USB request block
  319. IrpIsPending -
  320. Return Value:
  321. --*/
  322. {
  323. NTSTATUS ntStatus = STATUS_SUCCESS;
  324. PUSBD_CONFIG_HANDLE configHandle = NULL;
  325. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
  326. PUSBD_INTERFACE_INFORMATION interfaceInformation;
  327. PUCHAR pch;
  328. ULONG i;
  329. PDEVICE_EXTENSION devExt;
  330. ULONG numInterfaces;
  331. PUCHAR end;
  332. PUSBD_DEVICE_HANDLE deviceHandle;
  333. USBD_STATUS usbdStatus;
  334. USB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
  335. PAGED_CODE();
  336. USBPORT_KdPrint((2, "' enter USBPORT_SelectConfiguration\n"));
  337. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  338. ASSERT_FDOEXT(devExt);
  339. GET_DEVICE_HANDLE(deviceHandle, Urb);
  340. LOCK_DEVICE(deviceHandle, FdoDeviceObject);
  341. ntStatus = STATUS_BOGUS;
  342. // BUGBUG
  343. // flush all current transfers or fail?
  344. //
  345. // dump old configuration data if we have any
  346. //
  347. if (deviceHandle->ConfigurationHandle) {
  348. // This is where we close the old configuration
  349. // handle, all pipes and all interfaces.
  350. USBPORT_InternalCloseConfiguration(deviceHandle,
  351. FdoDeviceObject,
  352. 0);
  353. }
  354. // now set up the new configuration
  355. configurationDescriptor =
  356. Urb->UrbSelectConfiguration.ConfigurationDescriptor;
  357. //
  358. // if null pased in set configuration to 0
  359. // 'unconfigured'
  360. //
  361. if (configurationDescriptor == NULL) {
  362. // device needs to be in the unconfigured state
  363. //
  364. // NOTE:
  365. // this may fail if the configuration is being
  366. // closed as the result of the device being unplugged
  367. // so we ignore the error
  368. //
  369. USBPORT_INIT_SETUP_PACKET(setupPacket,
  370. USB_REQUEST_SET_CONFIGURATION, // bRequest
  371. BMREQUEST_HOST_TO_DEVICE, // Dir
  372. BMREQUEST_TO_DEVICE, // Recipient
  373. BMREQUEST_STANDARD, // Type
  374. 0, // wValue
  375. 0, // wIndex
  376. 0); // wLength
  377. USBPORT_SendCommand(deviceHandle,
  378. FdoDeviceObject,
  379. &setupPacket,
  380. NULL,
  381. 0,
  382. NULL,
  383. NULL);
  384. ntStatus = SET_USBD_ERROR(Urb, USBD_STATUS_SUCCESS);
  385. goto USBD_SelectConfiguration_Done;
  386. } else {
  387. // validate the config descriptor by accessing it
  388. //
  389. // Note: that we we will still crash here if the config
  390. // descriptor is invalid. However is will be easiser to
  391. // debug this way.
  392. //
  393. //
  394. //
  395. PUCHAR tmp;
  396. UCHAR ch;
  397. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'vCNF',
  398. configurationDescriptor,
  399. 0,
  400. 0);
  401. // first a quick sanity check, it must be non-zero
  402. if (configurationDescriptor->wTotalLength == 0) {
  403. // this is bogus
  404. ntStatus = SET_USBD_ERROR(Urb,
  405. USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR);
  406. goto USBD_SelectConfiguration_Done;
  407. } else {
  408. // touch first and last byte, this wil fault if invalid.
  409. tmp = (PUCHAR) configurationDescriptor;
  410. ch = *tmp;
  411. tmp += configurationDescriptor->wTotalLength-1;
  412. ch = *tmp;
  413. }
  414. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'CFok',
  415. configurationDescriptor,
  416. 0,
  417. 0);
  418. }
  419. //
  420. // count the number of interfaces to process in this
  421. // request
  422. //
  423. pch = (PUCHAR) &Urb->UrbSelectConfiguration.Interface;
  424. numInterfaces = 0;
  425. end = ((PUCHAR) Urb) + Urb->UrbSelectConfiguration.Hdr.Length;
  426. do {
  427. numInterfaces++;
  428. interfaceInformation = (PUSBD_INTERFACE_INFORMATION) pch;
  429. pch+=interfaceInformation->Length;
  430. } while (pch < end);
  431. USBPORT_KdPrint((2, "'USBD_SelectConfiguration -- %d interfaces\n",
  432. numInterfaces));
  433. // sanity check the config descriptor with the URB request
  434. if (numInterfaces != configurationDescriptor->bNumInterfaces ||
  435. numInterfaces == 0) {
  436. //
  437. // driver is broken, config request does not match
  438. // config descriptor passed in!!!
  439. //
  440. USBPORT_DebugClient((
  441. "config request does not match config descriptor\n"));
  442. ntStatus = SET_USBD_ERROR(Urb,
  443. USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR);
  444. TC_TRAP();
  445. goto USBD_SelectConfiguration_Done;
  446. }
  447. //
  448. // Allocate a configuration handle and
  449. // verify there is enough room to store
  450. // all the information in the client buffer.
  451. //
  452. configHandle = USBPORT_InitializeConfigurationHandle(deviceHandle,
  453. FdoDeviceObject,
  454. configurationDescriptor);
  455. if (configHandle == NULL) {
  456. USBPORT_DebugClient((
  457. "failed to allocate config handle\n"));
  458. ntStatus = SET_USBD_ERROR(Urb,
  459. USBD_STATUS_INSUFFICIENT_RESOURCES);
  460. goto USBD_SelectConfiguration_Done;
  461. }
  462. //
  463. // Send the 'set configuration' command
  464. //
  465. USBPORT_INIT_SETUP_PACKET(setupPacket,
  466. USB_REQUEST_SET_CONFIGURATION, // bRequest
  467. BMREQUEST_HOST_TO_DEVICE, // Dir
  468. BMREQUEST_TO_DEVICE, // Recipient
  469. BMREQUEST_STANDARD, // Type
  470. configurationDescriptor->bConfigurationValue, // wValue
  471. 0, // wIndex
  472. 0); // wLength
  473. USBPORT_SendCommand(deviceHandle,
  474. FdoDeviceObject,
  475. &setupPacket,
  476. NULL,
  477. 0,
  478. NULL,
  479. &usbdStatus);
  480. USBPORT_KdPrint((2,"' SendCommand, SetConfiguration returned 0x%x\n", usbdStatus));
  481. if (USBD_ERROR(usbdStatus)) {
  482. USBPORT_DebugClient((
  483. "failed to 'set' the configuration\n"));
  484. ntStatus = SET_USBD_ERROR(Urb,
  485. USBD_STATUS_SET_CONFIG_FAILED);
  486. TC_TRAP();
  487. goto USBD_SelectConfiguration_Done;
  488. }
  489. USBPORT_ASSERT(ntStatus == STATUS_BOGUS);
  490. // we have "configured" the device in the USB sense.
  491. //
  492. // User buffer checks out and we have 'configured'
  493. // the device.
  494. // Now parse thru the configuration descriptor
  495. // and open the interfaces.
  496. //
  497. // The URB contains a set of INTERFACE_INFORMATION
  498. // structures these give us the information we need
  499. // to open the pipes
  500. /*
  501. _USBD_INTERFACE_INFORMATION
  502. client should have filled in:
  503. USHORT Length;
  504. UCHAR InterfaceNumber;
  505. UCHAR AlternateSetting;
  506. we fill in :
  507. UCHAR Class;
  508. UCHAR SubClass;
  509. UCHAR Protocol;
  510. UCHAR Reserved;
  511. USBD_INTERFACE_HANDLE InterfaceHandle;
  512. ULONG NumberOfPipes;
  513. */
  514. pch = (PUCHAR) &Urb->UrbSelectConfiguration.Interface;
  515. for (i=0; i<numInterfaces; i++) {
  516. PUSBD_INTERFACE_HANDLE_I interfaceHandle;
  517. // open the interface
  518. interfaceInformation = (PUSBD_INTERFACE_INFORMATION) pch;
  519. usbdStatus = USBPORT_InitializeInterfaceInformation(
  520. FdoDeviceObject,
  521. interfaceInformation,
  522. configHandle);
  523. interfaceHandle = NULL;
  524. if (usbdStatus == USBD_STATUS_SUCCESS) {
  525. // this function allocates the actual 'handle'
  526. usbdStatus = USBPORT_InternalOpenInterface(Urb,
  527. deviceHandle,
  528. FdoDeviceObject,
  529. configHandle,
  530. interfaceInformation,
  531. &interfaceHandle,
  532. TRUE);
  533. USBPORT_KdPrint((2, "' InternalOpenInterface returned(USBD) 0x%x\n",
  534. usbdStatus));
  535. }
  536. pch+=interfaceInformation->Length;
  537. // if we got back a handle add it to the list
  538. if (interfaceHandle != NULL) {
  539. InsertTailList(&configHandle->InterfaceHandleList,
  540. &interfaceHandle->InterfaceLink);
  541. }
  542. if (!USBD_SUCCESS(usbdStatus)) {
  543. ntStatus = SET_USBD_ERROR(Urb, usbdStatus);
  544. // we have an error opening the interface
  545. DEBUG_BREAK();
  546. TC_TRAP();
  547. goto USBD_SelectConfiguration_Done;
  548. }
  549. }
  550. //
  551. // interfaces were successfully set up then return success.
  552. //
  553. ntStatus = SET_USBD_ERROR(Urb, USBD_STATUS_SUCCESS);
  554. USBD_SelectConfiguration_Done:
  555. if (NT_SUCCESS(ntStatus)) {
  556. USBPORT_ASSERT(Urb->UrbSelectConfiguration.Hdr.Status ==
  557. USBD_STATUS_SUCCESS);
  558. Urb->UrbSelectConfiguration.ConfigurationHandle =
  559. configHandle;
  560. // remember the current configuration
  561. deviceHandle->ConfigurationHandle = configHandle;
  562. } else {
  563. //
  564. // something failed, clean up before we return an error.
  565. //
  566. if (configHandle) {
  567. TC_TRAP();
  568. ASSERT_DEVICE_HANDLE(deviceHandle);
  569. //
  570. // if we have a configHandle then we need to free it
  571. deviceHandle->ConfigurationHandle =
  572. configHandle;
  573. //
  574. // attempt to close it
  575. //
  576. USBPORT_InternalCloseConfiguration(deviceHandle,
  577. FdoDeviceObject,
  578. 0);
  579. deviceHandle->ConfigurationHandle = NULL;
  580. }
  581. // make sure we return an error in the URB.
  582. USBPORT_ASSERT(Urb->UrbSelectConfiguration.Hdr.Status !=
  583. USBD_STATUS_SUCCESS);
  584. USBPORT_KdPrint((2, "'Failing SelectConfig\n"));
  585. }
  586. UNLOCK_DEVICE(deviceHandle, FdoDeviceObject);
  587. USBPORT_KdPrint((2, "'exit SelectConfiguration 0x%x\n", ntStatus));
  588. return ntStatus;
  589. }
  590. PUSBD_CONFIG_HANDLE
  591. USBPORT_InitializeConfigurationHandle(
  592. PUSBD_DEVICE_HANDLE DeviceHandle,
  593. PDEVICE_OBJECT FdoDeviceObject,
  594. PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
  595. )
  596. /*++
  597. Routine Description:
  598. Initialize the configuration handle structure.
  599. Given a (hopefully) valid configuration descriptor
  600. and a count of the interfaces create the configuration
  601. handle for the device
  602. Arguments:
  603. Return Value:
  604. --*/
  605. {
  606. PUSBD_CONFIG_HANDLE configHandle = NULL;
  607. ULONG i;
  608. PUCHAR pch;
  609. PAGED_CODE();
  610. USBPORT_ASSERT(ConfigurationDescriptor->bNumInterfaces > 0);
  611. USBPORT_KdPrint((2, "' enter InitializeConfigurationHandle\n"));
  612. // get enough space for each interface
  613. ALLOC_POOL_Z(configHandle,
  614. NonPagedPool,
  615. sizeof(USBD_CONFIG_HANDLE) +
  616. ConfigurationDescriptor->wTotalLength);
  617. pch = (PUCHAR)configHandle;
  618. if (configHandle) {
  619. //
  620. // Initilaize the interface handle list
  621. //
  622. InitializeListHead(&configHandle->InterfaceHandleList);
  623. configHandle->ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)
  624. (pch + sizeof(USBD_CONFIG_HANDLE));
  625. // copy the config descriptor to our handle
  626. RtlCopyMemory(configHandle->ConfigurationDescriptor,
  627. ConfigurationDescriptor,
  628. ConfigurationDescriptor->wTotalLength);
  629. configHandle->Sig = SIG_CONFIG_HANDLE;
  630. }
  631. USBPORT_KdPrint((2, "' exit InitializeConfigurationHandle 0x%x\n",
  632. configHandle));
  633. return configHandle;
  634. }
  635. USBD_STATUS
  636. USBPORT_InternalOpenInterface(
  637. PURB Urb,
  638. PUSBD_DEVICE_HANDLE DeviceHandle,
  639. PDEVICE_OBJECT FdoDeviceObject,
  640. PUSBD_CONFIG_HANDLE ConfigHandle,
  641. PUSBD_INTERFACE_INFORMATION InterfaceInformation,
  642. PUSBD_INTERFACE_HANDLE_I *InterfaceHandle,
  643. BOOLEAN SendSetInterfaceCommand
  644. )
  645. /*++
  646. Routine Description:
  647. Arguments:
  648. DeviceObject -
  649. DeviceHandle - USBD device handle for this device.
  650. ConfigHandle - USBD configuration handle.
  651. InterfaceInformation - pointer to USBD interface information structure
  652. passed in by the client.
  653. We use the InterfaceNumber and AlternateSetting specified
  654. in this structure to select the interface.
  655. On success the .Length field is filled in with the actual length
  656. of the interface_information structure and the Pipe[] fields are filled
  657. in with the handles for the opened pipes.
  658. InterfaceHandle - pointer to an interface handle pointer, filled in
  659. with the allocated interface handle structure if NULL, otherwise the
  660. structure passed in is used.
  661. SendSetInterfaceCommand - indicates if the set_interface command should be
  662. sent.
  663. Return Value:
  664. --*/
  665. {
  666. USBD_STATUS usbdStatus = USBD_STATUS_SUCCESS;
  667. BOOLEAN hasAlternateSettings;
  668. PUSBD_INTERFACE_HANDLE_I interfaceHandle = NULL;
  669. PUSB_ENDPOINT_DESCRIPTOR endpointDescriptor;
  670. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
  671. PUCHAR pch;
  672. ULONG i;
  673. BOOLEAN allocated = FALSE;
  674. PUSB_COMMON_DESCRIPTOR descriptor;
  675. USHORT need;
  676. ULONG numEndpoints;
  677. USB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
  678. PAGED_CODE();
  679. ASSERT_CONFIG_HANDLE(ConfigHandle);
  680. if (*InterfaceHandle != NULL) {
  681. // using a previously allocated interface handle
  682. ASSERT_INTERFACE_HANDLE(*InterfaceHandle);
  683. TEST_TRAP();
  684. }
  685. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'opIF',
  686. InterfaceInformation->InterfaceNumber,
  687. InterfaceInformation->AlternateSetting,
  688. *InterfaceHandle);
  689. USBPORT_KdPrint((2, "' enter InternalOpenInterface\n"));
  690. USBPORT_KdPrint((2, "' Interface %d Altsetting %d\n",
  691. InterfaceInformation->InterfaceNumber,
  692. InterfaceInformation->AlternateSetting));
  693. //
  694. // Find the interface descriptor we are interested in inside
  695. // the configuration descriptor.
  696. //
  697. interfaceDescriptor =
  698. USBPORT_InternalParseConfigurationDescriptor(ConfigHandle->ConfigurationDescriptor,
  699. InterfaceInformation->InterfaceNumber,
  700. InterfaceInformation->AlternateSetting,
  701. &hasAlternateSettings);
  702. // we already validated this, if it is NULL
  703. // the function has a bug.
  704. USBPORT_ASSERT(interfaceDescriptor != NULL);
  705. if (interfaceDescriptor == NULL) {
  706. BUGCHECK(USBBUGCODE_INTERNAL_ERROR, (ULONG_PTR) DeviceHandle, 0, 0);
  707. // keep prefix scanner happy
  708. return USBD_STATUS_SUCCESS;
  709. }
  710. //
  711. // We got the interface descriptor, now try
  712. // to open all the pipes.
  713. //
  714. // found the requested interface in the configuration descriptor.
  715. numEndpoints = interfaceDescriptor->bNumEndpoints;
  716. need = (USHORT) (((numEndpoints-1) * sizeof(USBD_PIPE_INFORMATION) +
  717. sizeof(USBD_INTERFACE_INFORMATION)));
  718. // we should have already validated this
  719. USBPORT_ASSERT(InterfaceInformation->Length == need);
  720. if (hasAlternateSettings &&
  721. SendSetInterfaceCommand) {
  722. NTSTATUS ntStatus;
  723. //
  724. // If we have alternate settings we need
  725. // to send the set interface command.
  726. //
  727. USBPORT_INIT_SETUP_PACKET(setupPacket,
  728. USB_REQUEST_SET_INTERFACE, // bRequest
  729. BMREQUEST_HOST_TO_DEVICE, // Dir
  730. BMREQUEST_TO_INTERFACE, // Recipient
  731. BMREQUEST_STANDARD, // Type
  732. InterfaceInformation->AlternateSetting, // wValue
  733. InterfaceInformation->InterfaceNumber, // wIndex
  734. 0); // wLength
  735. ntStatus = USBPORT_SendCommand(DeviceHandle,
  736. FdoDeviceObject,
  737. &setupPacket,
  738. NULL,
  739. 0,
  740. NULL,
  741. &usbdStatus);
  742. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'seIF',
  743. ntStatus,
  744. InterfaceInformation->AlternateSetting,
  745. InterfaceInformation->InterfaceNumber);
  746. if (USBD_ERROR(usbdStatus)) {
  747. DEBUG_BREAK();
  748. goto USBPORT_InternalOpenInterface_Done;
  749. }
  750. USBPORT_ASSERT(ntStatus == STATUS_SUCCESS);
  751. }
  752. //
  753. // we successfully selected the alternate interface
  754. // initialize the interface handle and open the pipes
  755. //
  756. if (*InterfaceHandle == NULL) {
  757. ULONG privateLength = sizeof(USBD_INTERFACE_HANDLE_I) +
  758. sizeof(USBD_PIPE_HANDLE_I) * numEndpoints;
  759. // allow space for a copy of the USBD_INTERFACE_INFORMATION
  760. // that is returned to the client
  761. ALLOC_POOL_Z(interfaceHandle,
  762. NonPagedPool,
  763. privateLength);
  764. if (interfaceHandle != NULL) {
  765. // initialize the pipe handles to a known state
  766. for (i=0; i<numEndpoints; i++) {
  767. interfaceHandle->PipeHandle[i].Endpoint = NULL;
  768. interfaceHandle->PipeHandle[i].Sig = SIG_PIPE_HANDLE;
  769. interfaceHandle->PipeHandle[i].PipeStateFlags =
  770. USBPORT_PIPE_STATE_CLOSED;
  771. //interfaceHandle->PipeHandle[i].ListEntry.Flink = NULL;
  772. //interfaceHandle->PipeHandle[i].ListEntry.Blink = NULL;
  773. }
  774. allocated = TRUE;
  775. } else {
  776. usbdStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
  777. goto USBPORT_InternalOpenInterface_Done;
  778. }
  779. } else {
  780. // using old handle
  781. interfaceHandle = *InterfaceHandle;
  782. }
  783. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'ihIF',
  784. interfaceHandle,
  785. 0,
  786. 0);
  787. USBPORT_ASSERT(interfaceHandle != NULL);
  788. interfaceHandle->Sig = SIG_INTERFACE_HANDLE;
  789. interfaceHandle->HasAlternateSettings = hasAlternateSettings;
  790. InterfaceInformation->NumberOfPipes =
  791. interfaceDescriptor->bNumEndpoints;
  792. InterfaceInformation->Class =
  793. interfaceDescriptor->bInterfaceClass;
  794. InterfaceInformation->SubClass =
  795. interfaceDescriptor->bInterfaceSubClass;
  796. InterfaceInformation->Protocol =
  797. interfaceDescriptor->bInterfaceProtocol;
  798. InterfaceInformation->Reserved = 0;
  799. // start with first endpoint
  800. // skip over any non-endpoint descriptors
  801. pch = (PUCHAR) (interfaceDescriptor) +
  802. interfaceDescriptor->bLength;
  803. // initialize the pipe fields for this interfacae
  804. // assume success
  805. usbdStatus = USBD_STATUS_SUCCESS;
  806. interfaceHandle->InterfaceDescriptor = *interfaceDescriptor;
  807. for (i=0; i<numEndpoints; i++) {
  808. USB_HIGH_SPEED_MAXPACKET muxPacket;
  809. descriptor = (PUSB_COMMON_DESCRIPTOR) pch;
  810. while (descriptor->bDescriptorType !=
  811. USB_ENDPOINT_DESCRIPTOR_TYPE) {
  812. if (descriptor->bLength == 0) {
  813. break; // Don't loop forever
  814. }
  815. pch += descriptor->bLength;
  816. descriptor = (PUSB_COMMON_DESCRIPTOR) pch;
  817. }
  818. endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) pch;
  819. USBPORT_ASSERT(endpointDescriptor->bDescriptorType ==
  820. USB_ENDPOINT_DESCRIPTOR_TYPE);
  821. // initial state is CLOSED
  822. interfaceHandle->PipeHandle[i].PipeStateFlags =
  823. USBPORT_PIPE_STATE_CLOSED;
  824. interfaceHandle->PipeHandle[i].Endpoint = NULL;
  825. // init pipe flags
  826. interfaceHandle->PipeHandle[i].UsbdPipeFlags =
  827. InterfaceInformation->Pipes[i].PipeFlags;
  828. if (InterfaceInformation->Pipes[i].PipeFlags &
  829. USBD_PF_CHANGE_MAX_PACKET) {
  830. // client wants to override original max_packet
  831. // size in endpoint descriptor
  832. endpointDescriptor->wMaxPacketSize =
  833. InterfaceInformation->Pipes[i].MaximumPacketSize;
  834. USBPORT_KdPrint((2,
  835. "'new bMaxPacket 0x%x\n", endpointDescriptor->wMaxPacketSize));
  836. }
  837. //
  838. // copy the endpoint descriptor into the
  839. // pipe handle structure.
  840. //
  841. RtlCopyMemory(&interfaceHandle->PipeHandle[i].EndpointDescriptor,
  842. pch,
  843. sizeof(interfaceHandle->PipeHandle[i].EndpointDescriptor) );
  844. // advance to next endpoint
  845. // first field in endpoint descriptor is length
  846. pch += endpointDescriptor->bLength;
  847. //
  848. // return information about the pipe
  849. //
  850. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'ipIF',
  851. interfaceHandle,
  852. i,
  853. &interfaceHandle->PipeHandle[i]);
  854. InterfaceInformation->Pipes[i].EndpointAddress =
  855. endpointDescriptor->bEndpointAddress;
  856. InterfaceInformation->Pipes[i].PipeType =
  857. PipeTypes[endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK];
  858. muxPacket.us = endpointDescriptor->wMaxPacketSize;
  859. InterfaceInformation->Pipes[i].MaximumPacketSize =
  860. muxPacket.MaxPacket * (muxPacket.HSmux+1);
  861. InterfaceInformation->Pipes[i].Interval =
  862. endpointDescriptor->bInterval;
  863. InterfaceInformation->Pipes[i].PipeHandle =
  864. USBPORT_BAD_HANDLE;
  865. } /* end for numEndpoints */
  866. if (usbdStatus != USBD_STATUS_SUCCESS) {
  867. // if we got an error bail now
  868. // we will return with the structure
  869. // initailized but no open pipes
  870. goto USBPORT_InternalOpenInterface_Done;
  871. }
  872. // all pipe handle fields initialized and
  873. // urb structure has been filled in
  874. // now loop thru and open the pipes
  875. for (i=0; i<interfaceDescriptor->bNumEndpoints; i++) {
  876. NTSTATUS ntStatus;
  877. ntStatus = USBPORT_OpenEndpoint(DeviceHandle,
  878. FdoDeviceObject,
  879. &interfaceHandle->PipeHandle[i],
  880. &usbdStatus,
  881. FALSE);
  882. if (NT_SUCCESS(ntStatus)) {
  883. // if success set the pipe handle for client
  884. InterfaceInformation->Pipes[i].PipeHandle =
  885. &interfaceHandle->PipeHandle[i];
  886. USBPORT_KdPrint((2, "'pipe handle = 0x%x\n",
  887. InterfaceInformation->Pipes[i].PipeHandle ));
  888. } else {
  889. USBPORT_KdPrint((1,
  890. "'error opening one of the pipes in interface (%x)\n", usbdStatus));
  891. ntStatus = SET_USBD_ERROR(Urb, usbdStatus);
  892. break;
  893. }
  894. }
  895. USBPORT_InternalOpenInterface_Done:
  896. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'oIFd',
  897. InterfaceInformation->InterfaceNumber,
  898. InterfaceInformation->AlternateSetting,
  899. usbdStatus);
  900. if (USBD_SUCCESS(usbdStatus)) {
  901. //
  902. // successfully opened the interface, return the handle
  903. // to it
  904. //
  905. *InterfaceHandle =
  906. InterfaceInformation->InterfaceHandle = interfaceHandle;
  907. //
  908. // set the length properly, the value we already
  909. // calculated
  910. //
  911. InterfaceInformation->Length = (USHORT) need;
  912. } else {
  913. //
  914. // had a problem, go back thru and close anything we opened.
  915. //
  916. if (interfaceHandle) {
  917. for (i=0; i<numEndpoints; i++) {
  918. USBPORT_KdPrint((2, "'open interface cleanup -- closing endpoint %x\n",
  919. &interfaceHandle->PipeHandle[i]));
  920. // fortunately this cannot fail
  921. USBPORT_ClosePipe(DeviceHandle,
  922. FdoDeviceObject,
  923. &interfaceHandle->PipeHandle[i]);
  924. }
  925. if (allocated) {
  926. FREE_POOL(FdoDeviceObject, interfaceHandle);
  927. interfaceHandle = NULL;
  928. }
  929. }
  930. }
  931. USBPORT_KdPrint((3, "' exit InternalOpenInterface 0x%x\n", usbdStatus));
  932. return usbdStatus;
  933. }
  934. VOID
  935. USBPORT_InternalCloseConfiguration(
  936. PUSBD_DEVICE_HANDLE DeviceHandle,
  937. PDEVICE_OBJECT FdoDeviceObject,
  938. ULONG Flags
  939. )
  940. /*++
  941. Routine Description:
  942. Closes the current configuration for a device.
  943. Arguments:
  944. Return Value:
  945. this function cannot fail
  946. --*/
  947. {
  948. ULONG i, j;
  949. PUSBD_CONFIG_HANDLE configHandle = NULL;
  950. BOOLEAN retry = TRUE;
  951. ULONG interfaceCount;
  952. PAGED_CODE();
  953. // device handle MUST be valid
  954. ASSERT_DEVICE_HANDLE(DeviceHandle);
  955. configHandle = DeviceHandle->ConfigurationHandle;
  956. if (configHandle == NULL) {
  957. // device is not configured
  958. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'nCFG', 0, 0, DeviceHandle);
  959. goto USBPORT_InternalCloseConfiguration_Done;
  960. }
  961. ASSERT_CONFIG_HANDLE(configHandle);
  962. interfaceCount = configHandle->ConfigurationDescriptor->bNumInterfaces;
  963. LOGENTRY(NULL, FdoDeviceObject,
  964. LOG_PNP, 'cCFG', interfaceCount, 0, configHandle);
  965. // we ensure that all transfers are aborted for the device handle
  966. // before calling this function so the close configuration will
  967. // not fail
  968. // do the cleanup
  969. while (!IsListEmpty(&configHandle->InterfaceHandleList)) {
  970. //
  971. // found an open interface, close it
  972. //
  973. PUSBD_INTERFACE_HANDLE_I iHandle;
  974. ULONG endpointCount;
  975. PLIST_ENTRY listEntry;
  976. listEntry = RemoveHeadList(&configHandle->InterfaceHandleList);
  977. iHandle = (PUSBD_INTERFACE_HANDLE_I) CONTAINING_RECORD(
  978. listEntry,
  979. struct _USBD_INTERFACE_HANDLE_I,
  980. InterfaceLink);
  981. ASSERT_INTERFACE(iHandle);
  982. endpointCount = iHandle->InterfaceDescriptor.bNumEndpoints;
  983. LOGENTRY(NULL, FdoDeviceObject,
  984. LOG_PNP, 'cIFX', iHandle, 0, configHandle);
  985. USBPORT_KdPrint((2, "'%d endpoints to close\n", endpointCount));
  986. for (j=0; j<endpointCount; j++) {
  987. PUSBD_PIPE_HANDLE_I pipeHandle;
  988. // if the pipe is open, close it
  989. pipeHandle = &iHandle->PipeHandle[j];
  990. USBPORT_KdPrint((2, "'close config -- closing pipe %x\n",
  991. &iHandle->PipeHandle[j]));
  992. USBPORT_ClosePipe(DeviceHandle,
  993. FdoDeviceObject,
  994. pipeHandle);
  995. USBPORT_ASSERT(pipeHandle->ListEntry.Flink == NULL &&
  996. pipeHandle->ListEntry.Blink == NULL);
  997. }
  998. // all pipes are now closed
  999. FREE_POOL(FdoDeviceObject, iHandle);
  1000. }
  1001. // NOTE: this also frees
  1002. // configHandle->ConfigurationDescriptor since it
  1003. // is in the same block allocated for the confighandle
  1004. FREE_POOL(FdoDeviceObject, configHandle);
  1005. // device is not 'unconfigured'
  1006. DeviceHandle->ConfigurationHandle = NULL;
  1007. USBPORT_InternalCloseConfiguration_Done:
  1008. USBPORT_KdPrint((2, "'current configuration closed\n"));
  1009. }
  1010. PUSB_INTERFACE_DESCRIPTOR
  1011. USBPORT_InternalParseConfigurationDescriptor(
  1012. PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
  1013. UCHAR InterfaceNumber,
  1014. UCHAR AlternateSetting,
  1015. PBOOLEAN HasAlternateSettings
  1016. )
  1017. /*++
  1018. Routine Description:
  1019. Get the configuration descriptor for a given device.
  1020. Arguments:
  1021. DeviceObject -
  1022. DeviceData -
  1023. Urb -
  1024. ConfigurationDescriptor -
  1025. Return Value:
  1026. --*/
  1027. {
  1028. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
  1029. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptorSetting = NULL;
  1030. PUCHAR pch = (PUCHAR) ConfigurationDescriptor, end;
  1031. ULONG i;
  1032. PUSB_COMMON_DESCRIPTOR commonDescriptor;
  1033. PAGED_CODE();
  1034. if (HasAlternateSettings) {
  1035. *HasAlternateSettings = FALSE;
  1036. }
  1037. commonDescriptor =
  1038. (PUSB_COMMON_DESCRIPTOR) (pch + ConfigurationDescriptor->bLength);
  1039. while (commonDescriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE) {
  1040. if (commonDescriptor->bLength == 0) {
  1041. break; // Don't loop forever
  1042. }
  1043. ((PUCHAR)(commonDescriptor))+= commonDescriptor->bLength;
  1044. }
  1045. interfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) commonDescriptor;
  1046. USBPORT_ASSERT(interfaceDescriptor->bDescriptorType ==
  1047. USB_INTERFACE_DESCRIPTOR_TYPE);
  1048. end = pch + ConfigurationDescriptor->wTotalLength;
  1049. //
  1050. // First find the matching InterfaceNumber
  1051. //
  1052. while (pch < end && interfaceDescriptor->bInterfaceNumber != InterfaceNumber) {
  1053. pch = (PUCHAR) interfaceDescriptor;
  1054. pch += USBPORT_InternalGetInterfaceLength(interfaceDescriptor, end);
  1055. // point to the next interface
  1056. interfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) pch;
  1057. #if DBG
  1058. if (pch < end) {
  1059. USBPORT_ASSERT(interfaceDescriptor->bDescriptorType ==
  1060. USB_INTERFACE_DESCRIPTOR_TYPE);
  1061. }
  1062. #endif //MAX_DEBUG
  1063. }
  1064. //#ifdef MAX_DEBUG
  1065. // if (pch >= end) {
  1066. // USBD_KdPrint(3, ("'Interface %x alt %x not found!\n", InterfaceNumber,
  1067. // AlternateSetting));
  1068. // TEST_TRAP();
  1069. // }
  1070. //#endif //MAX_DEBUG
  1071. i = 0;
  1072. // Now find the proper alternate setting
  1073. while (pch < end && interfaceDescriptor->bInterfaceNumber == InterfaceNumber) {
  1074. if (interfaceDescriptor->bAlternateSetting == AlternateSetting) {
  1075. interfaceDescriptorSetting = interfaceDescriptor;
  1076. }
  1077. pch = (PUCHAR) interfaceDescriptor;
  1078. pch += USBPORT_InternalGetInterfaceLength(interfaceDescriptor, end);
  1079. // point to next interface
  1080. interfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) pch;
  1081. #if DBG
  1082. if (pch < end) {
  1083. USBPORT_ASSERT(interfaceDescriptor->bDescriptorType ==
  1084. USB_INTERFACE_DESCRIPTOR_TYPE);
  1085. }
  1086. #endif
  1087. i++;
  1088. }
  1089. if (i>1 && HasAlternateSettings) {
  1090. *HasAlternateSettings = TRUE;
  1091. USBPORT_KdPrint((2, "'device has alternate settings!\n"));
  1092. }
  1093. return interfaceDescriptorSetting;
  1094. }
  1095. ULONG
  1096. USBPORT_InternalGetInterfaceLength(
  1097. PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
  1098. PUCHAR End
  1099. )
  1100. /*++
  1101. Routine Description:
  1102. Initialize the configuration handle structure.
  1103. Arguments:
  1104. InterfaceDescriptor - pointer to usb interface descriptor
  1105. followed by endpoint descriptors
  1106. Return Value:
  1107. Length of the interface plus endpoint descriptors and class specific
  1108. descriptors in bytes.
  1109. --*/
  1110. {
  1111. PUCHAR pch = (PUCHAR) InterfaceDescriptor;
  1112. ULONG i, numEndpoints;
  1113. PUSB_ENDPOINT_DESCRIPTOR endpointDescriptor;
  1114. PUSB_COMMON_DESCRIPTOR usbDescriptor;
  1115. PAGED_CODE();
  1116. USBPORT_ASSERT(InterfaceDescriptor->bDescriptorType ==
  1117. USB_INTERFACE_DESCRIPTOR_TYPE);
  1118. i = InterfaceDescriptor->bLength;
  1119. numEndpoints = InterfaceDescriptor->bNumEndpoints;
  1120. // advance to the first endpoint
  1121. pch += i;
  1122. while (numEndpoints) {
  1123. usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
  1124. while (usbDescriptor->bDescriptorType !=
  1125. USB_ENDPOINT_DESCRIPTOR_TYPE) {
  1126. if (usbDescriptor->bLength == 0) {
  1127. break; // Don't loop forever
  1128. }
  1129. i += usbDescriptor->bLength;
  1130. pch += usbDescriptor->bLength;
  1131. usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
  1132. }
  1133. endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) pch;
  1134. USBPORT_ASSERT(endpointDescriptor->bDescriptorType ==
  1135. USB_ENDPOINT_DESCRIPTOR_TYPE);
  1136. i += endpointDescriptor->bLength;
  1137. pch += endpointDescriptor->bLength;
  1138. numEndpoints--;
  1139. }
  1140. while (pch < End) {
  1141. // see if we are pointing at an interface
  1142. // if not skip over the other junk
  1143. usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
  1144. if (usbDescriptor->bDescriptorType ==
  1145. USB_INTERFACE_DESCRIPTOR_TYPE) {
  1146. break;
  1147. }
  1148. USBPORT_ASSERT(usbDescriptor->bLength != 0);
  1149. if (usbDescriptor->bLength == 0) {
  1150. break; // Don't loop forever
  1151. }
  1152. i += usbDescriptor->bLength;
  1153. pch += usbDescriptor->bLength;
  1154. }
  1155. return i;
  1156. }
  1157. BOOLEAN
  1158. USBPORT_ValidateConfigurtionDescriptor(
  1159. PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
  1160. USBD_STATUS *UsbdStatus
  1161. )
  1162. /*++
  1163. Routine Description:
  1164. Validate a configuration descriptor
  1165. Arguments:
  1166. ConfigurationDescriptor -
  1167. Urb -
  1168. Return Value:
  1169. TRUE if it looks valid
  1170. --*/
  1171. {
  1172. BOOLEAN valid = TRUE;
  1173. if (ConfigurationDescriptor->bDescriptorType !=
  1174. USB_CONFIGURATION_DESCRIPTOR_TYPE) {
  1175. valid = FALSE;
  1176. *UsbdStatus = USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR;
  1177. }
  1178. if (ConfigurationDescriptor->bLength !=
  1179. sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
  1180. valid = FALSE;
  1181. *UsbdStatus = USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR;
  1182. }
  1183. return valid;
  1184. }
  1185. PUSBD_INTERFACE_HANDLE_I
  1186. USBPORT_GetInterfaceHandle(
  1187. PDEVICE_OBJECT FdoDeviceObject,
  1188. PUSBD_CONFIG_HANDLE ConfigurationHandle,
  1189. UCHAR InterfaceNumber
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. Walks the list of interfaces attached to the configuration
  1194. handle and returns the one with the matching InterfaceNumber
  1195. Arguments:
  1196. Return Value:
  1197. interface handle
  1198. --*/
  1199. {
  1200. PLIST_ENTRY listEntry;
  1201. PUSBD_INTERFACE_HANDLE_I iHandle;
  1202. // walk the list
  1203. GET_HEAD_LIST(ConfigurationHandle->InterfaceHandleList, listEntry);
  1204. while (listEntry &&
  1205. listEntry != &ConfigurationHandle->InterfaceHandleList) {
  1206. // extract the handle from this entry
  1207. iHandle = (PUSBD_INTERFACE_HANDLE_I) CONTAINING_RECORD(
  1208. listEntry,
  1209. struct _USBD_INTERFACE_HANDLE_I,
  1210. InterfaceLink);
  1211. ASSERT_INTERFACE(iHandle);
  1212. // is this the one we want?
  1213. if (iHandle->InterfaceDescriptor.bInterfaceNumber ==
  1214. InterfaceNumber) {
  1215. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'gfh1', iHandle, 0, 0);
  1216. return iHandle;
  1217. }
  1218. listEntry = iHandle->InterfaceLink.Flink;
  1219. } /* while */
  1220. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'gfh2', 0, 0, 0);
  1221. return NULL;
  1222. }
  1223. USBD_STATUS
  1224. USBPORT_InitializeInterfaceInformation(
  1225. PDEVICE_OBJECT FdoDeviceObject,
  1226. PUSBD_INTERFACE_INFORMATION InterfaceInformation,
  1227. PUSBD_CONFIG_HANDLE ConfigHandle
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. validates and initializes the interface information structure
  1232. passed by the client
  1233. Arguments:
  1234. Return Value:
  1235. --*/
  1236. {
  1237. ULONG need, i;
  1238. ULONG numEndpoints;
  1239. USBD_STATUS usbdStatus = USBD_STATUS_SUCCESS;
  1240. BOOLEAN hasAlternateSettings;
  1241. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
  1242. interfaceDescriptor =
  1243. USBPORT_InternalParseConfigurationDescriptor(
  1244. ConfigHandle->ConfigurationDescriptor,
  1245. InterfaceInformation->InterfaceNumber,
  1246. InterfaceInformation->AlternateSetting,
  1247. &hasAlternateSettings);
  1248. // we know we need at least this much
  1249. need = sizeof(USBD_PIPE_INFORMATION) + sizeof(USBD_INTERFACE_INFORMATION);
  1250. if (interfaceDescriptor == NULL) {
  1251. usbdStatus = USBD_STATUS_INTERFACE_NOT_FOUND;
  1252. TEST_TRAP();
  1253. goto USBPORT_InitializeInterfaceInformation_Done;
  1254. }
  1255. // Here is where we verify there is enough room in the client
  1256. // buffer since we know how many pipes we'll need based on the
  1257. // interface descriptor.
  1258. //
  1259. // we need space for pipe_info for each endpoint plus the
  1260. // interface_info
  1261. numEndpoints = interfaceDescriptor->bNumEndpoints;
  1262. need = (USHORT) (((numEndpoints-1) * sizeof(USBD_PIPE_INFORMATION) +
  1263. sizeof(USBD_INTERFACE_INFORMATION)));
  1264. USBPORT_KdPrint((2, "'Interface.Length = %d need = %d\n",
  1265. InterfaceInformation->Length, need));
  1266. if (InterfaceInformation->Length < need) {
  1267. // the client has indicated that the buffer
  1268. // is smaller than what we need
  1269. usbdStatus = USBD_STATUS_BUFFER_TOO_SMALL;
  1270. TC_TRAP();
  1271. }
  1272. if (usbdStatus == USBD_STATUS_SUCCESS) {
  1273. // initialize all fields not set by caller to zero
  1274. InterfaceInformation->Class = 0;
  1275. InterfaceInformation->SubClass = 0;
  1276. InterfaceInformation->Protocol = 0;
  1277. InterfaceInformation->Reserved = 0;
  1278. InterfaceInformation->InterfaceHandle = NULL;
  1279. InterfaceInformation->NumberOfPipes =
  1280. numEndpoints;
  1281. for (i=0; i< numEndpoints; i++) {
  1282. InterfaceInformation->Pipes[i].EndpointAddress = 0;
  1283. InterfaceInformation->Pipes[i].Interval = 0;
  1284. InterfaceInformation->Pipes[i].PipeType = 0;
  1285. InterfaceInformation->Pipes[i].PipeHandle = NULL;
  1286. // attempt to detect bad flags
  1287. // if any unused bits are set we assume that the pipeflags
  1288. // field is uninitialized.
  1289. if (InterfaceInformation->Pipes[i].PipeFlags & ~USBD_PF_VALID_MASK) {
  1290. // client driver is passing bad flags
  1291. USBPORT_DebugClient(("client driver is passing bad pipe flags\n"));
  1292. usbdStatus = USBD_STATUS_INAVLID_PIPE_FLAGS;
  1293. TC_TRAP();
  1294. }
  1295. // note: if USBD_PF_CHANGE_MAX_PACKET is set then
  1296. // maxpacket size is passed in as a parameter so
  1297. // we don't initialize it
  1298. if (!TEST_FLAG(InterfaceInformation->Pipes[i].PipeFlags,
  1299. USBD_PF_CHANGE_MAX_PACKET)) {
  1300. InterfaceInformation->Pipes[i].MaximumPacketSize = 0;
  1301. }
  1302. }
  1303. }
  1304. USBPORT_InitializeInterfaceInformation_Done:
  1305. // set length to the correct value regardless
  1306. // of error
  1307. InterfaceInformation->Length = need;
  1308. return usbdStatus;
  1309. }