xref: /reactos/drivers/usb/usbport/device.c (revision bf74391d)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:     ReactOS USB Port Driver
3c2c66affSColin Finck  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4c2c66affSColin Finck  * PURPOSE:     USBPort device functions
5c2c66affSColin Finck  * COPYRIGHT:   Copyright 2017 Vadim Galyant <vgal@rambler.ru>
6c2c66affSColin Finck  */
7c2c66affSColin Finck 
8c2c66affSColin Finck #include "usbport.h"
9c2c66affSColin Finck 
10c2c66affSColin Finck #define NDEBUG
11c2c66affSColin Finck #include <debug.h>
12c2c66affSColin Finck 
13c2c66affSColin Finck NTSTATUS
14c2c66affSColin Finck NTAPI
15c2c66affSColin Finck USBPORT_SendSetupPacket(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
16c2c66affSColin Finck                         IN PDEVICE_OBJECT FdoDevice,
17c2c66affSColin Finck                         IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
18c2c66affSColin Finck                         IN PVOID Buffer,
19c2c66affSColin Finck                         IN ULONG Length,
20c2c66affSColin Finck                         IN OUT PULONG TransferedLen,
21c2c66affSColin Finck                         IN OUT PUSBD_STATUS pUSBDStatus)
22c2c66affSColin Finck {
23c2c66affSColin Finck     PURB Urb;
24c2c66affSColin Finck     PMDL Mdl;
25c2c66affSColin Finck     USBD_STATUS USBDStatus;
26c2c66affSColin Finck     KEVENT Event;
27c2c66affSColin Finck     NTSTATUS Status;
28c2c66affSColin Finck 
29c2c66affSColin Finck     DPRINT("USBPORT_SendSetupPacket: DeviceHandle - %p, FdoDevice - %p, SetupPacket - %p, Buffer - %p, Length - %x, TransferedLen - %x, pUSBDStatus - %x\n",
30c2c66affSColin Finck            DeviceHandle,
31c2c66affSColin Finck            FdoDevice,
32c2c66affSColin Finck            SetupPacket,
33c2c66affSColin Finck            Buffer,
34c2c66affSColin Finck            Length,
35c2c66affSColin Finck            TransferedLen,
36c2c66affSColin Finck            pUSBDStatus);
37c2c66affSColin Finck 
38c2c66affSColin Finck     KeInitializeEvent(&Event, NotificationEvent, FALSE);
39c2c66affSColin Finck 
40c2c66affSColin Finck     Urb = ExAllocatePoolWithTag(NonPagedPool,
41c2c66affSColin Finck                                 sizeof(struct _URB_CONTROL_TRANSFER),
42c2c66affSColin Finck                                 USB_PORT_TAG);
43c2c66affSColin Finck 
44c2c66affSColin Finck     if (Urb)
45c2c66affSColin Finck     {
46c2c66affSColin Finck         InterlockedIncrement(&DeviceHandle->DeviceHandleLock);
47c2c66affSColin Finck 
48c2c66affSColin Finck         RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_TRANSFER));
49c2c66affSColin Finck 
50c2c66affSColin Finck         RtlCopyMemory(Urb->UrbControlTransfer.SetupPacket,
51c2c66affSColin Finck                       SetupPacket,
52c2c66affSColin Finck                       sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
53c2c66affSColin Finck 
54c2c66affSColin Finck         Urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER);
55c2c66affSColin Finck         Urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
56c2c66affSColin Finck         Urb->UrbHeader.UsbdDeviceHandle = DeviceHandle;
57c2c66affSColin Finck         Urb->UrbHeader.UsbdFlags = 0;
58c2c66affSColin Finck 
59c2c66affSColin Finck         Urb->UrbControlTransfer.PipeHandle = &DeviceHandle->PipeHandle;
60c2c66affSColin Finck         Urb->UrbControlTransfer.TransferBufferLength = Length;
61c2c66affSColin Finck         Urb->UrbControlTransfer.TransferBuffer = Buffer;
62c2c66affSColin Finck         Urb->UrbControlTransfer.TransferBufferMDL = NULL;
63c2c66affSColin Finck 
64c2c66affSColin Finck         Urb->UrbControlTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK |
65c2c66affSColin Finck                                                 USBD_TRANSFER_DIRECTION;
66c2c66affSColin Finck 
67c2c66affSColin Finck         if (SetupPacket->bmRequestType.Dir != BMREQUEST_DEVICE_TO_HOST)
68c2c66affSColin Finck         {
69c2c66affSColin Finck             Urb->UrbControlTransfer.TransferFlags &= ~USBD_TRANSFER_DIRECTION_IN;
70c2c66affSColin Finck         }
71c2c66affSColin Finck 
72c2c66affSColin Finck         Status = STATUS_SUCCESS;
73c2c66affSColin Finck 
74c2c66affSColin Finck         if (Length)
75c2c66affSColin Finck         {
76c2c66affSColin Finck             Mdl = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL);
77c2c66affSColin Finck 
78c2c66affSColin Finck             Urb->UrbControlTransfer.TransferBufferMDL = Mdl;
79c2c66affSColin Finck 
80c2c66affSColin Finck             if (Mdl)
81c2c66affSColin Finck             {
82c2c66affSColin Finck                 Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_MDL;
83c2c66affSColin Finck                 MmBuildMdlForNonPagedPool(Mdl);
84c2c66affSColin Finck             }
85c2c66affSColin Finck             else
86c2c66affSColin Finck             {
87c2c66affSColin Finck                 Status = USBPORT_USBDStatusToNtStatus(NULL,
88c2c66affSColin Finck                                                       USBD_STATUS_INSUFFICIENT_RESOURCES);
89c2c66affSColin Finck             }
90c2c66affSColin Finck         }
91c2c66affSColin Finck 
92c2c66affSColin Finck         if (NT_SUCCESS(Status))
93c2c66affSColin Finck         {
94c2c66affSColin Finck             USBDStatus = USBPORT_AllocateTransfer(FdoDevice,
95c2c66affSColin Finck                                                   Urb,
96c2c66affSColin Finck                                                   NULL,
97c2c66affSColin Finck                                                   NULL,
98c2c66affSColin Finck                                                   &Event);
99c2c66affSColin Finck 
100c2c66affSColin Finck             if (USBD_SUCCESS(USBDStatus))
101c2c66affSColin Finck             {
102c2c66affSColin Finck                 InterlockedIncrement(&DeviceHandle->DeviceHandleLock);
103c2c66affSColin Finck 
104c2c66affSColin Finck                 USBPORT_QueueTransferUrb(Urb);
105c2c66affSColin Finck 
106c2c66affSColin Finck                 KeWaitForSingleObject(&Event,
107c2c66affSColin Finck                                       Suspended,
108c2c66affSColin Finck                                       KernelMode,
109c2c66affSColin Finck                                       FALSE,
110c2c66affSColin Finck                                       NULL);
111c2c66affSColin Finck 
112c2c66affSColin Finck                 USBDStatus = Urb->UrbHeader.Status;
113c2c66affSColin Finck             }
114c2c66affSColin Finck 
115c2c66affSColin Finck             Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
116c2c66affSColin Finck 
117c2c66affSColin Finck             if (TransferedLen)
118c2c66affSColin Finck                 *TransferedLen = Urb->UrbControlTransfer.TransferBufferLength;
119c2c66affSColin Finck 
120c2c66affSColin Finck             if (pUSBDStatus)
121c2c66affSColin Finck                 *pUSBDStatus = USBDStatus;
122c2c66affSColin Finck         }
123c2c66affSColin Finck 
124c2c66affSColin Finck         InterlockedDecrement(&DeviceHandle->DeviceHandleLock);
125c2c66affSColin Finck         ExFreePoolWithTag(Urb, USB_PORT_TAG);
126c2c66affSColin Finck     }
127c2c66affSColin Finck     else
128c2c66affSColin Finck     {
129c2c66affSColin Finck         if (pUSBDStatus)
130c2c66affSColin Finck             *pUSBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
131c2c66affSColin Finck 
132c2c66affSColin Finck         Status = USBPORT_USBDStatusToNtStatus(NULL,
133c2c66affSColin Finck                                               USBD_STATUS_INSUFFICIENT_RESOURCES);
134c2c66affSColin Finck     }
135c2c66affSColin Finck 
136c2c66affSColin Finck     DPRINT("USBPORT_SendSetupPacket: Status - %x\n", Status);
137c2c66affSColin Finck     return Status;
138c2c66affSColin Finck }
139c2c66affSColin Finck 
140c2c66affSColin Finck ULONG
141c2c66affSColin Finck NTAPI
142c2c66affSColin Finck USBPORT_GetInterfaceLength(IN PUSB_INTERFACE_DESCRIPTOR iDescriptor,
143c2c66affSColin Finck                            IN ULONG_PTR EndDescriptors)
144c2c66affSColin Finck {
145c2c66affSColin Finck     SIZE_T Length;
146c2c66affSColin Finck     PUSB_ENDPOINT_DESCRIPTOR Descriptor;
147c2c66affSColin Finck     ULONG ix;
148c2c66affSColin Finck 
149c2c66affSColin Finck     DPRINT("USBPORT_GetInterfaceLength ... \n");
150c2c66affSColin Finck 
151c2c66affSColin Finck     Length = iDescriptor->bLength;
152c2c66affSColin Finck     Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)iDescriptor + Length);
153c2c66affSColin Finck 
154c2c66affSColin Finck     if (iDescriptor->bNumEndpoints)
155c2c66affSColin Finck     {
156c2c66affSColin Finck         for (ix = 0; ix < iDescriptor->bNumEndpoints; ix++)
157c2c66affSColin Finck         {
158c2c66affSColin Finck             while ((Descriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE) &&
159c2c66affSColin Finck                    (Descriptor->bLength > 0))
160c2c66affSColin Finck             {
161c2c66affSColin Finck                 Length += Descriptor->bLength;
162c2c66affSColin Finck                 Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
163c2c66affSColin Finck                                                         Descriptor->bLength);
164c2c66affSColin Finck             }
165c2c66affSColin Finck 
166c2c66affSColin Finck             Length += Descriptor->bLength;
167c2c66affSColin Finck             Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
168c2c66affSColin Finck                                                     Descriptor->bLength);
169c2c66affSColin Finck         }
170c2c66affSColin Finck     }
171c2c66affSColin Finck 
172c2c66affSColin Finck     while (((ULONG_PTR)Descriptor < EndDescriptors) &&
173c2c66affSColin Finck            (Descriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE) &&
174c2c66affSColin Finck            (Descriptor->bLength > 0))
175c2c66affSColin Finck     {
176c2c66affSColin Finck         Length += Descriptor->bLength;
177c2c66affSColin Finck         Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
178c2c66affSColin Finck                                                 Descriptor->bLength);
179c2c66affSColin Finck     }
180c2c66affSColin Finck 
181c2c66affSColin Finck     return Length;
182c2c66affSColin Finck }
183c2c66affSColin Finck 
184c2c66affSColin Finck PUSB_INTERFACE_DESCRIPTOR
185c2c66affSColin Finck NTAPI
186c2c66affSColin Finck USBPORT_ParseConfigurationDescriptor(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
187c2c66affSColin Finck                                      IN UCHAR InterfaceNumber,
188c2c66affSColin Finck                                      IN UCHAR Alternate,
189c2c66affSColin Finck                                      OUT PUCHAR OutAlternate)
190c2c66affSColin Finck {
191c2c66affSColin Finck     PUSB_CONFIGURATION_DESCRIPTOR TmpDescriptor;
192c2c66affSColin Finck     PUSB_INTERFACE_DESCRIPTOR iDescriptor;
193c2c66affSColin Finck     PUSB_INTERFACE_DESCRIPTOR OutDescriptor = NULL;
194c2c66affSColin Finck     ULONG_PTR Descriptor = (ULONG_PTR)ConfigDescriptor;
195c2c66affSColin Finck     ULONG_PTR EndDescriptors;
196c2c66affSColin Finck     ULONG ix;
197c2c66affSColin Finck 
198c2c66affSColin Finck     DPRINT("USBPORT_ParseConfigurationDescriptor ... \n");
199c2c66affSColin Finck 
200c2c66affSColin Finck     if (OutAlternate)
201c2c66affSColin Finck         *OutAlternate = 0;
202c2c66affSColin Finck 
203c2c66affSColin Finck     for (TmpDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)ConfigDescriptor + ConfigDescriptor->bLength);
204c2c66affSColin Finck          TmpDescriptor->bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE && TmpDescriptor->bDescriptorType > 0;
205c2c66affSColin Finck          TmpDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)TmpDescriptor + TmpDescriptor->bLength))
206c2c66affSColin Finck     ;
207c2c66affSColin Finck 
208c2c66affSColin Finck     iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)TmpDescriptor;
209c2c66affSColin Finck 
210c2c66affSColin Finck     EndDescriptors = (ULONG_PTR)ConfigDescriptor +
211c2c66affSColin Finck                                 ConfigDescriptor->wTotalLength;
212c2c66affSColin Finck 
213c2c66affSColin Finck     while ((Descriptor < EndDescriptors) &&
214c2c66affSColin Finck            (iDescriptor->bInterfaceNumber != InterfaceNumber))
215c2c66affSColin Finck     {
216c2c66affSColin Finck         Descriptor = (ULONG_PTR)iDescriptor +
217c2c66affSColin Finck                      USBPORT_GetInterfaceLength(iDescriptor, EndDescriptors);
218c2c66affSColin Finck 
219c2c66affSColin Finck         iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor;
220c2c66affSColin Finck     }
221c2c66affSColin Finck 
222c2c66affSColin Finck     ix = 0;
223c2c66affSColin Finck 
224c2c66affSColin Finck     while (Descriptor < EndDescriptors &&
225c2c66affSColin Finck            iDescriptor->bInterfaceNumber == InterfaceNumber)
226c2c66affSColin Finck     {
227c2c66affSColin Finck         if (iDescriptor->bAlternateSetting == Alternate)
228c2c66affSColin Finck             OutDescriptor = iDescriptor;
229c2c66affSColin Finck 
230c2c66affSColin Finck         Descriptor = (ULONG_PTR)iDescriptor +
231c2c66affSColin Finck                      USBPORT_GetInterfaceLength(iDescriptor, EndDescriptors);
232c2c66affSColin Finck 
233c2c66affSColin Finck         iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor;
234c2c66affSColin Finck 
235c2c66affSColin Finck         ++ix;
236c2c66affSColin Finck     }
237c2c66affSColin Finck 
238c2c66affSColin Finck     if ((ix > 1) && OutAlternate)
239c2c66affSColin Finck         *OutAlternate = 1;
240c2c66affSColin Finck 
241c2c66affSColin Finck     return OutDescriptor;
242c2c66affSColin Finck }
243c2c66affSColin Finck 
244c2c66affSColin Finck USBD_STATUS
245c2c66affSColin Finck NTAPI
246c2c66affSColin Finck USBPORT_OpenInterface(IN PURB Urb,
247c2c66affSColin Finck                       IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
248c2c66affSColin Finck                       IN PDEVICE_OBJECT FdoDevice,
249c2c66affSColin Finck                       IN PUSBPORT_CONFIGURATION_HANDLE ConfigHandle,
250c2c66affSColin Finck                       IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
251c2c66affSColin Finck                       IN OUT PUSBPORT_INTERFACE_HANDLE *iHandle,
252c2c66affSColin Finck                       IN BOOLEAN IsSetInterface)
253c2c66affSColin Finck {
254c2c66affSColin Finck     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
255c2c66affSColin Finck     PUSBPORT_INTERFACE_HANDLE InterfaceHandle = NULL;
256c2c66affSColin Finck     PUSBPORT_PIPE_HANDLE PipeHandle;
257c2c66affSColin Finck     PUSB_ENDPOINT_DESCRIPTOR Descriptor;
258c2c66affSColin Finck     PUSBD_PIPE_INFORMATION PipeInfo;
259c2c66affSColin Finck     ULONG NumEndpoints;
260c2c66affSColin Finck     SIZE_T Length;
261c2c66affSColin Finck     SIZE_T HandleLength;
262c2c66affSColin Finck     BOOLEAN IsAllocated = FALSE;
263c2c66affSColin Finck     USHORT MaxPacketSize;
264c2c66affSColin Finck     USHORT wMaxPacketSize;
265c2c66affSColin Finck     ULONG ix;
266c2c66affSColin Finck     USBD_STATUS USBDStatus = USBD_STATUS_SUCCESS;
267c2c66affSColin Finck     NTSTATUS Status;
268c2c66affSColin Finck 
269c2c66affSColin Finck     DPRINT("USBPORT_OpenInterface: ...\n");
270c2c66affSColin Finck 
271c2c66affSColin Finck     InterfaceDescriptor = USBPORT_ParseConfigurationDescriptor(ConfigHandle->ConfigurationDescriptor,
272c2c66affSColin Finck                                                                InterfaceInfo->InterfaceNumber,
273c2c66affSColin Finck                                                                InterfaceInfo->AlternateSetting,
274c2c66affSColin Finck                                                                &InterfaceInfo->AlternateSetting);
275c2c66affSColin Finck 
276c2c66affSColin Finck     NumEndpoints = InterfaceDescriptor->bNumEndpoints;
277c2c66affSColin Finck 
278*bf74391dSThomas Faber     Length = FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) +
279*bf74391dSThomas Faber              NumEndpoints * sizeof(USBD_PIPE_INFORMATION);
280c2c66affSColin Finck 
281c2c66affSColin Finck     if (InterfaceInfo->AlternateSetting && IsSetInterface)
282c2c66affSColin Finck     {
283c2c66affSColin Finck         DPRINT1("USBPORT_OpenInterface: InterfaceInfo->AlternateSetting && IsSetInterface !\n");
284c2c66affSColin Finck     }
285c2c66affSColin Finck 
286c2c66affSColin Finck     if (*iHandle)
287c2c66affSColin Finck     {
288c2c66affSColin Finck         InterfaceHandle = *iHandle;
289c2c66affSColin Finck     }
290c2c66affSColin Finck     else
291c2c66affSColin Finck     {
292*bf74391dSThomas Faber         HandleLength = FIELD_OFFSET(USBPORT_INTERFACE_HANDLE, PipeHandle) +
293*bf74391dSThomas Faber                        NumEndpoints * sizeof(USBPORT_PIPE_HANDLE);
294c2c66affSColin Finck 
295c2c66affSColin Finck         InterfaceHandle = ExAllocatePoolWithTag(NonPagedPool,
296c2c66affSColin Finck                                                 HandleLength,
297c2c66affSColin Finck                                                 USB_PORT_TAG);
298c2c66affSColin Finck 
299c2c66affSColin Finck         if (!InterfaceHandle)
300c2c66affSColin Finck         {
301c2c66affSColin Finck             USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
302c2c66affSColin Finck             goto Exit;
303c2c66affSColin Finck         }
304c2c66affSColin Finck 
305c2c66affSColin Finck         RtlZeroMemory(InterfaceHandle, HandleLength);
306c2c66affSColin Finck 
307c2c66affSColin Finck         for (ix = 0; ix < NumEndpoints; ++ix)
308c2c66affSColin Finck         {
309c2c66affSColin Finck             PipeHandle = &InterfaceHandle->PipeHandle[ix];
310c2c66affSColin Finck 
311c2c66affSColin Finck             PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED;
312c2c66affSColin Finck             PipeHandle->Endpoint = NULL;
313c2c66affSColin Finck         }
314c2c66affSColin Finck 
315c2c66affSColin Finck         IsAllocated = TRUE;
316c2c66affSColin Finck     }
317c2c66affSColin Finck 
318c2c66affSColin Finck     InterfaceHandle->AlternateSetting = InterfaceInfo->AlternateSetting;
319c2c66affSColin Finck 
320c2c66affSColin Finck     RtlCopyMemory(&InterfaceHandle->InterfaceDescriptor,
321c2c66affSColin Finck                   InterfaceDescriptor,
322c2c66affSColin Finck                   sizeof(USB_INTERFACE_DESCRIPTOR));
323c2c66affSColin Finck 
324c2c66affSColin Finck     InterfaceInfo->Class = InterfaceDescriptor->bInterfaceClass;
325c2c66affSColin Finck     InterfaceInfo->SubClass = InterfaceDescriptor->bInterfaceSubClass;
326c2c66affSColin Finck     InterfaceInfo->Protocol = InterfaceDescriptor->bInterfaceProtocol;
327c2c66affSColin Finck     InterfaceInfo->Reserved = 0;
328c2c66affSColin Finck     InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
329c2c66affSColin Finck 
330c2c66affSColin Finck     Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor +
331c2c66affSColin Finck                                             InterfaceDescriptor->bLength);
332c2c66affSColin Finck 
333c2c66affSColin Finck     for (ix = 0; ix < NumEndpoints; ++ix)
334c2c66affSColin Finck     {
335c2c66affSColin Finck         PipeHandle = &InterfaceHandle->PipeHandle[ix];
336c2c66affSColin Finck 
337c2c66affSColin Finck         while (Descriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE)
338c2c66affSColin Finck         {
339c2c66affSColin Finck             if (Descriptor->bLength == 0)
340c2c66affSColin Finck             {
341c2c66affSColin Finck                 break;
342c2c66affSColin Finck             }
343c2c66affSColin Finck             else
344c2c66affSColin Finck             {
345c2c66affSColin Finck                 Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
346c2c66affSColin Finck                                                         Descriptor->bLength);
347c2c66affSColin Finck             }
348c2c66affSColin Finck         }
349c2c66affSColin Finck 
350c2c66affSColin Finck         if (InterfaceInfo->Pipes[ix].PipeFlags & USBD_PF_CHANGE_MAX_PACKET)
351c2c66affSColin Finck         {
352c2c66affSColin Finck             Descriptor->wMaxPacketSize = InterfaceInfo->Pipes[ix].MaximumPacketSize;
353c2c66affSColin Finck         }
354c2c66affSColin Finck 
355c2c66affSColin Finck         RtlCopyMemory(&PipeHandle->EndpointDescriptor,
356c2c66affSColin Finck                       Descriptor,
357c2c66affSColin Finck                       sizeof(USB_ENDPOINT_DESCRIPTOR));
358c2c66affSColin Finck 
359c2c66affSColin Finck         PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED;
360c2c66affSColin Finck         PipeHandle->PipeFlags = InterfaceInfo->Pipes[ix].PipeFlags;
361c2c66affSColin Finck         PipeHandle->Endpoint = NULL;
362c2c66affSColin Finck 
363c2c66affSColin Finck         wMaxPacketSize = Descriptor->wMaxPacketSize;
364c2c66affSColin Finck 
365c2c66affSColin Finck         /* USB 2.0 Specification, 5.9 High-Speed, High Bandwidth Endpoints */
366c2c66affSColin Finck         MaxPacketSize = (wMaxPacketSize & 0x7FF) * (((wMaxPacketSize >> 11) & 3) + 1);
367c2c66affSColin Finck 
368c2c66affSColin Finck         InterfaceInfo->Pipes[ix].EndpointAddress = Descriptor->bEndpointAddress;
369c2c66affSColin Finck         InterfaceInfo->Pipes[ix].PipeType = Descriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK;
370c2c66affSColin Finck         InterfaceInfo->Pipes[ix].MaximumPacketSize = MaxPacketSize;
371c2c66affSColin Finck         InterfaceInfo->Pipes[ix].PipeHandle = (USBD_PIPE_HANDLE)-1;
372c2c66affSColin Finck         InterfaceInfo->Pipes[ix].Interval = Descriptor->bInterval;
373c2c66affSColin Finck 
374c2c66affSColin Finck         Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
375c2c66affSColin Finck                                                 Descriptor->bLength);
376c2c66affSColin Finck     }
377c2c66affSColin Finck 
378c2c66affSColin Finck     if (USBD_SUCCESS(USBDStatus))
379c2c66affSColin Finck     {
380c2c66affSColin Finck         for (ix = 0; ix < NumEndpoints; ++ix)
381c2c66affSColin Finck         {
382c2c66affSColin Finck             PipeInfo = &InterfaceInfo->Pipes[ix];
383c2c66affSColin Finck             PipeHandle = &InterfaceHandle->PipeHandle[ix];
384c2c66affSColin Finck 
385c2c66affSColin Finck             Status = USBPORT_OpenPipe(FdoDevice,
386c2c66affSColin Finck                                       DeviceHandle,
387c2c66affSColin Finck                                       PipeHandle,
388c2c66affSColin Finck                                       &USBDStatus);
389c2c66affSColin Finck 
390c2c66affSColin Finck             if (!NT_SUCCESS(Status))
391c2c66affSColin Finck                 break;
392c2c66affSColin Finck 
393c2c66affSColin Finck             PipeInfo->PipeHandle = PipeHandle;
394c2c66affSColin Finck         }
395c2c66affSColin Finck 
396c2c66affSColin Finck         if (NumEndpoints)
397c2c66affSColin Finck         {
398c2c66affSColin Finck             USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
399c2c66affSColin Finck         }
400c2c66affSColin Finck     }
401c2c66affSColin Finck 
402c2c66affSColin Finck Exit:
403c2c66affSColin Finck 
404c2c66affSColin Finck     if (USBD_SUCCESS(USBDStatus))
405c2c66affSColin Finck     {
406c2c66affSColin Finck         InterfaceInfo->InterfaceHandle = InterfaceHandle;
407c2c66affSColin Finck         *iHandle = InterfaceHandle;
408c2c66affSColin Finck         InterfaceInfo->Length = Length;
409c2c66affSColin Finck     }
410c2c66affSColin Finck     else
411c2c66affSColin Finck     {
412c2c66affSColin Finck         if (InterfaceHandle)
413c2c66affSColin Finck         {
414c2c66affSColin Finck             if (NumEndpoints)
415c2c66affSColin Finck             {
416c2c66affSColin Finck                 DPRINT1("USBPORT_OpenInterface: USBDStatus - %lx\n", USBDStatus);
417c2c66affSColin Finck             }
418c2c66affSColin Finck 
419c2c66affSColin Finck             if (IsAllocated)
420c2c66affSColin Finck                 ExFreePoolWithTag(InterfaceHandle, USB_PORT_TAG);
421c2c66affSColin Finck         }
422c2c66affSColin Finck     }
423c2c66affSColin Finck 
424c2c66affSColin Finck     return USBDStatus;
425c2c66affSColin Finck }
426c2c66affSColin Finck 
427c2c66affSColin Finck VOID
428c2c66affSColin Finck NTAPI
429c2c66affSColin Finck USBPORT_CloseConfiguration(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
430c2c66affSColin Finck                            IN PDEVICE_OBJECT FdoDevice)
431c2c66affSColin Finck {
432c2c66affSColin Finck     PUSBPORT_CONFIGURATION_HANDLE ConfigHandle;
433c2c66affSColin Finck     PLIST_ENTRY iHandleList;
434c2c66affSColin Finck     PUSBPORT_INTERFACE_HANDLE iHandle;
435c2c66affSColin Finck     ULONG NumEndpoints;
436c2c66affSColin Finck     PUSBPORT_PIPE_HANDLE PipeHandle;
437c2c66affSColin Finck 
438c2c66affSColin Finck     DPRINT("USBPORT_CloseConfiguration: ... \n");
439c2c66affSColin Finck 
440c2c66affSColin Finck     ConfigHandle = DeviceHandle->ConfigHandle;
441c2c66affSColin Finck 
442c2c66affSColin Finck     if (ConfigHandle)
443c2c66affSColin Finck     {
444c2c66affSColin Finck         iHandleList = &ConfigHandle->InterfaceHandleList;
445c2c66affSColin Finck 
446c2c66affSColin Finck         while (!IsListEmpty(iHandleList))
447c2c66affSColin Finck         {
448c2c66affSColin Finck             iHandle = CONTAINING_RECORD(iHandleList->Flink,
449c2c66affSColin Finck                                         USBPORT_INTERFACE_HANDLE,
450c2c66affSColin Finck                                         InterfaceLink);
451c2c66affSColin Finck 
452c2c66affSColin Finck             DPRINT("USBPORT_CloseConfiguration: iHandle - %p\n", iHandle);
453c2c66affSColin Finck 
454c2c66affSColin Finck             RemoveHeadList(iHandleList);
455c2c66affSColin Finck 
456c2c66affSColin Finck             NumEndpoints = iHandle->InterfaceDescriptor.bNumEndpoints;
457c2c66affSColin Finck 
458c2c66affSColin Finck             PipeHandle = &iHandle->PipeHandle[0];
459c2c66affSColin Finck 
460c2c66affSColin Finck             while (NumEndpoints > 0)
461c2c66affSColin Finck             {
462c2c66affSColin Finck                 USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle);
463c2c66affSColin Finck                 PipeHandle += 1;
464c2c66affSColin Finck                 --NumEndpoints;
465c2c66affSColin Finck             }
466c2c66affSColin Finck 
467c2c66affSColin Finck             ExFreePoolWithTag(iHandle, USB_PORT_TAG);
468c2c66affSColin Finck         }
469c2c66affSColin Finck 
470c2c66affSColin Finck         ExFreePoolWithTag(ConfigHandle, USB_PORT_TAG);
471c2c66affSColin Finck         DeviceHandle->ConfigHandle = NULL;
472c2c66affSColin Finck     }
473c2c66affSColin Finck }
474c2c66affSColin Finck 
475c2c66affSColin Finck NTSTATUS
476c2c66affSColin Finck NTAPI
477c2c66affSColin Finck USBPORT_InitInterfaceInfo(IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
478c2c66affSColin Finck                           IN PUSBPORT_CONFIGURATION_HANDLE ConfigHandle)
479c2c66affSColin Finck {
480c2c66affSColin Finck     PUSB_INTERFACE_DESCRIPTOR Descriptor;
481c2c66affSColin Finck     PUSBD_PIPE_INFORMATION Pipe;
482c2c66affSColin Finck     USHORT Length;
483c2c66affSColin Finck     ULONG PipeFlags;
484c2c66affSColin Finck     ULONG NumberOfPipes;
485c2c66affSColin Finck     USBD_STATUS USBDStatus = USBD_STATUS_SUCCESS;
486c2c66affSColin Finck 
487c2c66affSColin Finck     DPRINT("USBPORT_InitInterfaceInfo: InterfaceInfo - %p, ConfigHandle - %p\n",
488c2c66affSColin Finck            InterfaceInfo,
489c2c66affSColin Finck            ConfigHandle);
490c2c66affSColin Finck 
491c2c66affSColin Finck     Descriptor = USBPORT_ParseConfigurationDescriptor(ConfigHandle->ConfigurationDescriptor,
492c2c66affSColin Finck                                                       InterfaceInfo->InterfaceNumber,
493c2c66affSColin Finck                                                       InterfaceInfo->AlternateSetting,
494c2c66affSColin Finck                                                       &InterfaceInfo->AlternateSetting);
495c2c66affSColin Finck 
496c2c66affSColin Finck     Length = sizeof(USBD_INTERFACE_INFORMATION) +
497c2c66affSColin Finck              sizeof(USBD_PIPE_INFORMATION);
498c2c66affSColin Finck 
499c2c66affSColin Finck     if (Descriptor)
500c2c66affSColin Finck     {
501c2c66affSColin Finck         NumberOfPipes = Descriptor->bNumEndpoints;
502c2c66affSColin Finck 
503*bf74391dSThomas Faber         Length = FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) +
504*bf74391dSThomas Faber                  NumberOfPipes * sizeof(USBD_PIPE_INFORMATION);
505c2c66affSColin Finck 
506c2c66affSColin Finck         if (InterfaceInfo->Length >= Length)
507c2c66affSColin Finck         {
508c2c66affSColin Finck             InterfaceInfo->Class = 0;
509c2c66affSColin Finck             InterfaceInfo->SubClass = 0;
510c2c66affSColin Finck             InterfaceInfo->Protocol = 0;
511c2c66affSColin Finck             InterfaceInfo->Reserved = 0;
512c2c66affSColin Finck             InterfaceInfo->InterfaceHandle = 0;
513c2c66affSColin Finck             InterfaceInfo->NumberOfPipes = NumberOfPipes;
514c2c66affSColin Finck 
515c2c66affSColin Finck             Pipe = InterfaceInfo->Pipes;
516c2c66affSColin Finck 
517c2c66affSColin Finck             while (NumberOfPipes > 0)
518c2c66affSColin Finck             {
519c2c66affSColin Finck                 Pipe->EndpointAddress = 0;
520c2c66affSColin Finck                 Pipe->Interval = 0;
521c2c66affSColin Finck                 Pipe->PipeType = 0;
522c2c66affSColin Finck                 Pipe->PipeHandle = 0;
523c2c66affSColin Finck 
524c2c66affSColin Finck                 PipeFlags = Pipe->PipeFlags;
525c2c66affSColin Finck 
526c2c66affSColin Finck                 if (PipeFlags & ~USBD_PF_VALID_MASK)
527c2c66affSColin Finck                     USBDStatus = USBD_STATUS_INVALID_PIPE_FLAGS;
528c2c66affSColin Finck 
529c2c66affSColin Finck                 if (!(PipeFlags & USBD_PF_CHANGE_MAX_PACKET))
530c2c66affSColin Finck                     Pipe->MaximumPacketSize = 0;
531c2c66affSColin Finck 
532c2c66affSColin Finck                 Pipe += 1;
533c2c66affSColin Finck                 --NumberOfPipes;
534c2c66affSColin Finck             }
535c2c66affSColin Finck         }
536c2c66affSColin Finck         else
537c2c66affSColin Finck         {
538c2c66affSColin Finck             USBDStatus = USBD_STATUS_BUFFER_TOO_SMALL;
539c2c66affSColin Finck         }
540c2c66affSColin Finck     }
541c2c66affSColin Finck     else
542c2c66affSColin Finck     {
543c2c66affSColin Finck         USBDStatus = USBD_STATUS_INTERFACE_NOT_FOUND;
544c2c66affSColin Finck     }
545c2c66affSColin Finck 
546c2c66affSColin Finck     InterfaceInfo->Length = Length;
547c2c66affSColin Finck     return USBDStatus;
548c2c66affSColin Finck }
549c2c66affSColin Finck 
550c2c66affSColin Finck NTSTATUS
551c2c66affSColin Finck NTAPI
552c2c66affSColin Finck USBPORT_HandleSelectConfiguration(IN PDEVICE_OBJECT FdoDevice,
553c2c66affSColin Finck                                   IN PIRP Irp,
554c2c66affSColin Finck                                   IN PURB Urb)
555c2c66affSColin Finck {
556c2c66affSColin Finck     PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
557c2c66affSColin Finck     PUSBPORT_DEVICE_HANDLE DeviceHandle;
558c2c66affSColin Finck     PUSBPORT_CONFIGURATION_HANDLE ConfigHandle = NULL;
559c2c66affSColin Finck     PUSBD_INTERFACE_INFORMATION InterfaceInfo;
560c2c66affSColin Finck     PUSBPORT_INTERFACE_HANDLE InterfaceHandle;
561c2c66affSColin Finck     ULONG iNumber;
562c2c66affSColin Finck     ULONG ix;
563c2c66affSColin Finck     USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
564c2c66affSColin Finck     NTSTATUS Status;
565c2c66affSColin Finck     USBD_STATUS USBDStatus;
566c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
567c2c66affSColin Finck 
568c2c66affSColin Finck     DPRINT("USBPORT_HandleSelectConfiguration: ConfigDescriptor %p\n",
569c2c66affSColin Finck            Urb->UrbSelectConfiguration.ConfigurationDescriptor);
570c2c66affSColin Finck 
571c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
572c2c66affSColin Finck 
573c2c66affSColin Finck     KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
574c2c66affSColin Finck                           Executive,
575c2c66affSColin Finck                           KernelMode,
576c2c66affSColin Finck                           FALSE,
577c2c66affSColin Finck                           NULL);
578c2c66affSColin Finck 
579c2c66affSColin Finck     DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle;
580c2c66affSColin Finck     ConfigDescriptor = Urb->UrbSelectConfiguration.ConfigurationDescriptor;
581c2c66affSColin Finck 
582c2c66affSColin Finck     if (!ConfigDescriptor)
583c2c66affSColin Finck     {
584c2c66affSColin Finck         DPRINT("USBPORT_HandleSelectConfiguration: ConfigDescriptor == NULL\n");
585c2c66affSColin Finck 
586c2c66affSColin Finck         RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
587c2c66affSColin Finck 
588c2c66affSColin Finck         SetupPacket.bmRequestType.B = 0;
589c2c66affSColin Finck         SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION;
590c2c66affSColin Finck         SetupPacket.wValue.W = 0;
591c2c66affSColin Finck         SetupPacket.wIndex.W = 0;
592c2c66affSColin Finck         SetupPacket.wLength = 0;
593c2c66affSColin Finck 
594c2c66affSColin Finck         USBPORT_SendSetupPacket(DeviceHandle,
595c2c66affSColin Finck                                 FdoDevice,
596c2c66affSColin Finck                                 &SetupPacket,
597c2c66affSColin Finck                                 NULL,
598c2c66affSColin Finck                                 0,
599c2c66affSColin Finck                                 NULL,
600c2c66affSColin Finck                                 NULL);
601c2c66affSColin Finck 
602c2c66affSColin Finck         Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS);
603c2c66affSColin Finck         goto Exit;
604c2c66affSColin Finck     }
605c2c66affSColin Finck 
606c2c66affSColin Finck     USBPORT_DumpingConfiguration(ConfigDescriptor);
607c2c66affSColin Finck 
608c2c66affSColin Finck     InterfaceInfo = &Urb->UrbSelectConfiguration.Interface;
609c2c66affSColin Finck 
610c2c66affSColin Finck     iNumber = 0;
611c2c66affSColin Finck 
612c2c66affSColin Finck     do
613c2c66affSColin Finck     {
614c2c66affSColin Finck         ++iNumber;
615c2c66affSColin Finck         InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)
616c2c66affSColin Finck                         ((ULONG_PTR)InterfaceInfo +
617c2c66affSColin Finck                          InterfaceInfo->Length);
618c2c66affSColin Finck     }
619c2c66affSColin Finck     while ((ULONG_PTR)InterfaceInfo < (ULONG_PTR)Urb + Urb->UrbHeader.Length);
620c2c66affSColin Finck 
621c2c66affSColin Finck     if ((iNumber <= 0) || (iNumber != ConfigDescriptor->bNumInterfaces))
622c2c66affSColin Finck     {
623c2c66affSColin Finck         Status = USBPORT_USBDStatusToNtStatus(Urb,
624c2c66affSColin Finck                                               USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR);
625c2c66affSColin Finck         goto Exit;
626c2c66affSColin Finck     }
627c2c66affSColin Finck 
628c2c66affSColin Finck     ConfigHandle = ExAllocatePoolWithTag(NonPagedPool,
629c2c66affSColin Finck                                          ConfigDescriptor->wTotalLength + sizeof(USBPORT_CONFIGURATION_HANDLE),
630c2c66affSColin Finck                                          USB_PORT_TAG);
631c2c66affSColin Finck 
632c2c66affSColin Finck     if (!ConfigHandle)
633c2c66affSColin Finck     {
634c2c66affSColin Finck         Status = USBPORT_USBDStatusToNtStatus(Urb,
635c2c66affSColin Finck                                               USBD_STATUS_INSUFFICIENT_RESOURCES);
636c2c66affSColin Finck         goto Exit;
637c2c66affSColin Finck     }
638c2c66affSColin Finck 
639c2c66affSColin Finck     RtlZeroMemory(ConfigHandle,
640c2c66affSColin Finck                   ConfigDescriptor->wTotalLength + sizeof(USBPORT_CONFIGURATION_HANDLE));
641c2c66affSColin Finck 
642c2c66affSColin Finck     InitializeListHead(&ConfigHandle->InterfaceHandleList);
643c2c66affSColin Finck 
644c2c66affSColin Finck     ConfigHandle->ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)(ConfigHandle + 1);
645c2c66affSColin Finck 
646c2c66affSColin Finck     RtlCopyMemory(ConfigHandle->ConfigurationDescriptor,
647c2c66affSColin Finck                   ConfigDescriptor,
648c2c66affSColin Finck                   ConfigDescriptor->wTotalLength);
649c2c66affSColin Finck 
650c2c66affSColin Finck     RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
651c2c66affSColin Finck 
652c2c66affSColin Finck     SetupPacket.bmRequestType.B = 0;
653c2c66affSColin Finck     SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION;
654c2c66affSColin Finck     SetupPacket.wValue.W = ConfigDescriptor->bConfigurationValue;
655c2c66affSColin Finck     SetupPacket.wIndex.W = 0;
656c2c66affSColin Finck     SetupPacket.wLength = 0;
657c2c66affSColin Finck 
658c2c66affSColin Finck     USBPORT_SendSetupPacket(DeviceHandle,
659c2c66affSColin Finck                             FdoDevice,
660c2c66affSColin Finck                             &SetupPacket,
661c2c66affSColin Finck                             NULL,
662c2c66affSColin Finck                             0,
663c2c66affSColin Finck                             NULL,
664c2c66affSColin Finck                             &USBDStatus);
665c2c66affSColin Finck 
666c2c66affSColin Finck     if (USBD_ERROR(USBDStatus))
667c2c66affSColin Finck     {
668c2c66affSColin Finck         Status = USBPORT_USBDStatusToNtStatus(Urb,
669c2c66affSColin Finck                                               USBD_STATUS_SET_CONFIG_FAILED);
670c2c66affSColin Finck         goto Exit;
671c2c66affSColin Finck     }
672c2c66affSColin Finck 
673c2c66affSColin Finck     if (iNumber <= 0)
674c2c66affSColin Finck     {
675c2c66affSColin Finck         Status = USBPORT_USBDStatusToNtStatus(Urb,
676c2c66affSColin Finck                                               USBD_STATUS_SUCCESS);
677c2c66affSColin Finck 
678c2c66affSColin Finck         goto Exit;
679c2c66affSColin Finck     }
680c2c66affSColin Finck 
681c2c66affSColin Finck     InterfaceInfo = &Urb->UrbSelectConfiguration.Interface;
682c2c66affSColin Finck 
683c2c66affSColin Finck     for (ix = 0; ix < iNumber; ++ix)
684c2c66affSColin Finck     {
685c2c66affSColin Finck         USBDStatus = USBPORT_InitInterfaceInfo(InterfaceInfo,
686c2c66affSColin Finck                                                ConfigHandle);
687c2c66affSColin Finck 
688c2c66affSColin Finck         InterfaceHandle = NULL;
689c2c66affSColin Finck 
690c2c66affSColin Finck         if (USBD_SUCCESS(USBDStatus))
691c2c66affSColin Finck         {
692c2c66affSColin Finck             USBDStatus = USBPORT_OpenInterface(Urb,
693c2c66affSColin Finck                                                DeviceHandle,
694c2c66affSColin Finck                                                FdoDevice,
695c2c66affSColin Finck                                                ConfigHandle,
696c2c66affSColin Finck                                                InterfaceInfo,
697c2c66affSColin Finck                                                &InterfaceHandle,
698c2c66affSColin Finck                                                TRUE);
699c2c66affSColin Finck         }
700c2c66affSColin Finck 
701c2c66affSColin Finck         if (InterfaceHandle)
702c2c66affSColin Finck         {
703c2c66affSColin Finck             InsertTailList(&ConfigHandle->InterfaceHandleList,
704c2c66affSColin Finck                            &InterfaceHandle->InterfaceLink);
705c2c66affSColin Finck         }
706c2c66affSColin Finck 
707c2c66affSColin Finck         if (USBD_ERROR(USBDStatus))
708c2c66affSColin Finck             break;
709c2c66affSColin Finck 
710c2c66affSColin Finck         InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)
711c2c66affSColin Finck                          ((ULONG_PTR)InterfaceInfo +
712c2c66affSColin Finck                           InterfaceInfo->Length);
713c2c66affSColin Finck     }
714c2c66affSColin Finck 
715c2c66affSColin Finck     if (ix >= iNumber)
716c2c66affSColin Finck     {
717c2c66affSColin Finck         Status = USBPORT_USBDStatusToNtStatus(Urb,
718c2c66affSColin Finck                                               USBD_STATUS_SUCCESS);
719c2c66affSColin Finck     }
720c2c66affSColin Finck     else
721c2c66affSColin Finck     {
722c2c66affSColin Finck         Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
723c2c66affSColin Finck     }
724c2c66affSColin Finck 
725c2c66affSColin Finck Exit:
726c2c66affSColin Finck 
727c2c66affSColin Finck     if (NT_SUCCESS(Status))
728c2c66affSColin Finck     {
729c2c66affSColin Finck         Urb->UrbSelectConfiguration.ConfigurationHandle = ConfigHandle;
730c2c66affSColin Finck         DeviceHandle->ConfigHandle = ConfigHandle;
731c2c66affSColin Finck     }
732c2c66affSColin Finck     else
733c2c66affSColin Finck     {
734c2c66affSColin Finck         DPRINT1("USBPORT_HandleSelectConfiguration: Status %x\n", Status);
735c2c66affSColin Finck     }
736c2c66affSColin Finck 
737c2c66affSColin Finck     KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
738c2c66affSColin Finck                        LOW_REALTIME_PRIORITY,
739c2c66affSColin Finck                        1,
740c2c66affSColin Finck                        FALSE);
741c2c66affSColin Finck 
742c2c66affSColin Finck     return Status;
743c2c66affSColin Finck }
744c2c66affSColin Finck 
745c2c66affSColin Finck VOID
746c2c66affSColin Finck NTAPI
747c2c66affSColin Finck USBPORT_AddDeviceHandle(IN PDEVICE_OBJECT FdoDevice,
748c2c66affSColin Finck                         IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
749c2c66affSColin Finck {
750c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
751c2c66affSColin Finck 
752c2c66affSColin Finck     DPRINT("USBPORT_AddDeviceHandle: ... \n");
753c2c66affSColin Finck 
754c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
755c2c66affSColin Finck 
756c2c66affSColin Finck     InsertTailList(&FdoExtension->DeviceHandleList,
757c2c66affSColin Finck                    &DeviceHandle->DeviceHandleLink);
758c2c66affSColin Finck }
759c2c66affSColin Finck 
760c2c66affSColin Finck VOID
761c2c66affSColin Finck NTAPI
762c2c66affSColin Finck USBPORT_RemoveDeviceHandle(IN PDEVICE_OBJECT FdoDevice,
763c2c66affSColin Finck                            IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
764c2c66affSColin Finck {
765c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
766c2c66affSColin Finck     KIRQL OldIrql;
767c2c66affSColin Finck 
768c2c66affSColin Finck     DPRINT("USBPORT_RemoveDeviceHandle \n");
769c2c66affSColin Finck 
770c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
771c2c66affSColin Finck 
772c2c66affSColin Finck     KeAcquireSpinLock(&FdoExtension->DeviceHandleSpinLock, &OldIrql);
773c2c66affSColin Finck     RemoveEntryList(&DeviceHandle->DeviceHandleLink);
774c2c66affSColin Finck     KeReleaseSpinLock(&FdoExtension->DeviceHandleSpinLock, OldIrql);
775c2c66affSColin Finck }
776c2c66affSColin Finck 
777c2c66affSColin Finck BOOLEAN
778c2c66affSColin Finck NTAPI
779c2c66affSColin Finck USBPORT_ValidateDeviceHandle(IN PDEVICE_OBJECT FdoDevice,
780c2c66affSColin Finck                              IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
781c2c66affSColin Finck {
782c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
783c2c66affSColin Finck     KIRQL OldIrql;
784c2c66affSColin Finck     PLIST_ENTRY HandleList;
785c2c66affSColin Finck     PUSBPORT_DEVICE_HANDLE CurrentHandle;
786c2c66affSColin Finck     BOOLEAN Result = FALSE;
787c2c66affSColin Finck 
788c2c66affSColin Finck     //DPRINT("USBPORT_ValidateDeviceHandle: DeviceHandle - %p\n", DeviceHandle \n");
789c2c66affSColin Finck 
790c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
791c2c66affSColin Finck 
792c2c66affSColin Finck     KeAcquireSpinLock(&FdoExtension->DeviceHandleSpinLock, &OldIrql);
793c2c66affSColin Finck     if (DeviceHandle)
794c2c66affSColin Finck     {
795c2c66affSColin Finck         HandleList = FdoExtension->DeviceHandleList.Flink;
796c2c66affSColin Finck 
797c2c66affSColin Finck         while (HandleList != &FdoExtension->DeviceHandleList)
798c2c66affSColin Finck         {
799c2c66affSColin Finck             CurrentHandle = CONTAINING_RECORD(HandleList,
800c2c66affSColin Finck                                               USBPORT_DEVICE_HANDLE,
801c2c66affSColin Finck                                               DeviceHandleLink);
802c2c66affSColin Finck 
803c2c66affSColin Finck             if (CurrentHandle == DeviceHandle)
804c2c66affSColin Finck             {
805c2c66affSColin Finck                 Result = TRUE;
806c2c66affSColin Finck                 break;
807c2c66affSColin Finck             }
808c2c66affSColin Finck 
809c2c66affSColin Finck             HandleList = HandleList->Flink;
810c2c66affSColin Finck         }
811c2c66affSColin Finck     }
812c2c66affSColin Finck     KeReleaseSpinLock(&FdoExtension->DeviceHandleSpinLock, OldIrql);
813c2c66affSColin Finck 
814c2c66affSColin Finck     return Result;
815c2c66affSColin Finck }
816c2c66affSColin Finck 
817c2c66affSColin Finck BOOLEAN
818c2c66affSColin Finck NTAPI
819c2c66affSColin Finck USBPORT_DeviceHasTransfers(IN PDEVICE_OBJECT FdoDevice,
820c2c66affSColin Finck                            IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
821c2c66affSColin Finck {
822c2c66affSColin Finck     PLIST_ENTRY PipeHandleList;
823c2c66affSColin Finck     PUSBPORT_PIPE_HANDLE PipeHandle;
824c2c66affSColin Finck 
825c2c66affSColin Finck     DPRINT("USBPORT_DeviceHasTransfers: ... \n");
826c2c66affSColin Finck 
827c2c66affSColin Finck     PipeHandleList = DeviceHandle->PipeHandleList.Flink;
828c2c66affSColin Finck 
829c2c66affSColin Finck     while (PipeHandleList != &DeviceHandle->PipeHandleList)
830c2c66affSColin Finck     {
831c2c66affSColin Finck         PipeHandle = CONTAINING_RECORD(PipeHandleList,
832c2c66affSColin Finck                                        USBPORT_PIPE_HANDLE,
833c2c66affSColin Finck                                        PipeLink);
834c2c66affSColin Finck 
835c2c66affSColin Finck         PipeHandleList = PipeHandleList->Flink;
836c2c66affSColin Finck 
837c2c66affSColin Finck         if (!(PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE) &&
838c2c66affSColin Finck             USBPORT_EndpointHasQueuedTransfers(FdoDevice, PipeHandle->Endpoint, NULL))
839c2c66affSColin Finck         {
840c2c66affSColin Finck             return TRUE;
841c2c66affSColin Finck         }
842c2c66affSColin Finck     }
843c2c66affSColin Finck 
844c2c66affSColin Finck     return FALSE;
845c2c66affSColin Finck }
846c2c66affSColin Finck 
847c2c66affSColin Finck VOID
848c2c66affSColin Finck NTAPI
849c2c66affSColin Finck USBPORT_AbortTransfers(IN PDEVICE_OBJECT FdoDevice,
850c2c66affSColin Finck                        IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
851c2c66affSColin Finck {
852c2c66affSColin Finck     PLIST_ENTRY HandleList;
853c2c66affSColin Finck     PUSBPORT_PIPE_HANDLE PipeHandle;
854c2c66affSColin Finck     BOOLEAN Result;
855c2c66affSColin Finck 
856c2c66affSColin Finck     DPRINT("USBPORT_AbortAllTransfers: ... \n");
857c2c66affSColin Finck 
858c2c66affSColin Finck     HandleList = DeviceHandle->PipeHandleList.Flink;
859c2c66affSColin Finck 
860c2c66affSColin Finck     while (HandleList != &DeviceHandle->PipeHandleList)
861c2c66affSColin Finck     {
862c2c66affSColin Finck         PipeHandle = CONTAINING_RECORD(HandleList,
863c2c66affSColin Finck                                        USBPORT_PIPE_HANDLE,
864c2c66affSColin Finck                                        PipeLink);
865c2c66affSColin Finck 
866c2c66affSColin Finck         HandleList = HandleList->Flink;
867c2c66affSColin Finck 
868c2c66affSColin Finck         if (!(PipeHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB))
869c2c66affSColin Finck         {
870c2c66affSColin Finck             PipeHandle->Endpoint->Flags |= ENDPOINT_FLAG_ABORTING;
871c2c66affSColin Finck 
872c2c66affSColin Finck             USBPORT_AbortEndpoint(FdoDevice, PipeHandle->Endpoint, NULL);
873c2c66affSColin Finck             USBPORT_FlushMapTransfers(FdoDevice);
874c2c66affSColin Finck         }
875c2c66affSColin Finck     }
876c2c66affSColin Finck 
877c2c66affSColin Finck     while (TRUE)
878c2c66affSColin Finck     {
879c2c66affSColin Finck         Result = USBPORT_DeviceHasTransfers(FdoDevice, DeviceHandle);
880c2c66affSColin Finck 
881c2c66affSColin Finck         if (!Result)
882c2c66affSColin Finck             break;
883c2c66affSColin Finck 
884c2c66affSColin Finck         USBPORT_Wait(FdoDevice, 100);
885c2c66affSColin Finck     }
886c2c66affSColin Finck }
887c2c66affSColin Finck 
888c2c66affSColin Finck NTSTATUS
889c2c66affSColin Finck NTAPI
890c2c66affSColin Finck USBPORT_CreateDevice(IN OUT PUSB_DEVICE_HANDLE *pUsbdDeviceHandle,
891c2c66affSColin Finck                      IN PDEVICE_OBJECT FdoDevice,
892c2c66affSColin Finck                      IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle,
893c2c66affSColin Finck                      IN USHORT PortStatus,
894c2c66affSColin Finck                      IN USHORT Port)
895c2c66affSColin Finck {
896c2c66affSColin Finck     PUSBPORT_DEVICE_HANDLE DeviceHandle;
897c2c66affSColin Finck     PUSBPORT_PIPE_HANDLE PipeHandle;
898c2c66affSColin Finck     BOOL IsOpenedPipe;
899c2c66affSColin Finck     PVOID DeviceDescriptor;
900c2c66affSColin Finck     USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
901c2c66affSColin Finck     SIZE_T TransferedLen;
902c2c66affSColin Finck     SIZE_T DescriptorMinSize;
903c2c66affSColin Finck     UCHAR MaxPacketSize;
904c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
905c2c66affSColin Finck 
906c2c66affSColin Finck     NTSTATUS Status;
907c2c66affSColin Finck 
908c2c66affSColin Finck     DPRINT("USBPORT_CreateDevice: PortStatus - %p, Port - %x\n",
909c2c66affSColin Finck            PortStatus,
910c2c66affSColin Finck            Port);
911c2c66affSColin Finck 
912c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
913c2c66affSColin Finck 
914c2c66affSColin Finck     KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
915c2c66affSColin Finck                           Executive,
916c2c66affSColin Finck                           KernelMode,
917c2c66affSColin Finck                           FALSE,
918c2c66affSColin Finck                           NULL);
919c2c66affSColin Finck 
920c2c66affSColin Finck     if (!USBPORT_ValidateDeviceHandle(FdoDevice, HubDeviceHandle))
921c2c66affSColin Finck     {
922c2c66affSColin Finck         KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
923c2c66affSColin Finck                            LOW_REALTIME_PRIORITY,
924c2c66affSColin Finck                            1,
925c2c66affSColin Finck                            FALSE);
926c2c66affSColin Finck 
927c2c66affSColin Finck         DPRINT1("USBPORT_CreateDevice: Not valid hub DeviceHandle\n");
928c2c66affSColin Finck         return STATUS_DEVICE_NOT_CONNECTED;
929c2c66affSColin Finck     }
930c2c66affSColin Finck 
931c2c66affSColin Finck     if (FdoExtension->MiniPortInterface->Packet.MiniPortFlags & USB_MINIPORT_FLAGS_USB2 &&
932c2c66affSColin Finck         !(PortStatus & USB_PORT_STATUS_HIGH_SPEED))
933c2c66affSColin Finck     {
934c2c66affSColin Finck         DPRINT1("USBPORT_CreateDevice: USB1 device connected to USB2 port. FIXME: Transaction Translator.\n");
935c2c66affSColin Finck         DbgBreakPoint();
936c2c66affSColin Finck     }
937c2c66affSColin Finck 
938c2c66affSColin Finck     KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
939c2c66affSColin Finck                        LOW_REALTIME_PRIORITY,
940c2c66affSColin Finck                        1,
941c2c66affSColin Finck                        FALSE);
942c2c66affSColin Finck 
943c2c66affSColin Finck     DeviceHandle = ExAllocatePoolWithTag(NonPagedPool,
944c2c66affSColin Finck                                          sizeof(USBPORT_DEVICE_HANDLE),
945c2c66affSColin Finck                                          USB_PORT_TAG);
946c2c66affSColin Finck 
947c2c66affSColin Finck     if (!DeviceHandle)
948c2c66affSColin Finck     {
949c2c66affSColin Finck         DPRINT1("USBPORT_CreateDevice: Not allocated DeviceHandle\n");
950c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
951c2c66affSColin Finck     }
952c2c66affSColin Finck 
953c2c66affSColin Finck     RtlZeroMemory(DeviceHandle, sizeof(USBPORT_DEVICE_HANDLE));
954c2c66affSColin Finck 
955c2c66affSColin Finck     *pUsbdDeviceHandle = NULL;
956c2c66affSColin Finck 
957c2c66affSColin Finck     DeviceHandle->PortNumber = Port;
958c2c66affSColin Finck     DeviceHandle->HubDeviceHandle = HubDeviceHandle;
959c2c66affSColin Finck 
960c2c66affSColin Finck     if (PortStatus & USB_PORT_STATUS_LOW_SPEED)
961c2c66affSColin Finck     {
962c2c66affSColin Finck         DeviceHandle->DeviceSpeed = UsbLowSpeed;
963c2c66affSColin Finck     }
964c2c66affSColin Finck     else if (PortStatus & USB_PORT_STATUS_HIGH_SPEED)
965c2c66affSColin Finck     {
966c2c66affSColin Finck         DeviceHandle->DeviceSpeed = UsbHighSpeed;
967c2c66affSColin Finck     }
968c2c66affSColin Finck     else
969c2c66affSColin Finck     {
970c2c66affSColin Finck         DeviceHandle->DeviceSpeed = UsbFullSpeed;
971c2c66affSColin Finck     }
972c2c66affSColin Finck 
973c2c66affSColin Finck     KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
974c2c66affSColin Finck                           Executive,
975c2c66affSColin Finck                           KernelMode,
976c2c66affSColin Finck                           FALSE,
977c2c66affSColin Finck                           NULL);
978c2c66affSColin Finck 
979c2c66affSColin Finck     PipeHandle = &DeviceHandle->PipeHandle;
980c2c66affSColin Finck 
981c2c66affSColin Finck     PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED;
982c2c66affSColin Finck 
983c2c66affSColin Finck     PipeHandle->EndpointDescriptor.bLength = sizeof(PipeHandle->EndpointDescriptor);
984c2c66affSColin Finck     PipeHandle->EndpointDescriptor.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE;
985c2c66affSColin Finck 
986c2c66affSColin Finck     if (DeviceHandle->DeviceSpeed == UsbLowSpeed)
987c2c66affSColin Finck     {
988c2c66affSColin Finck         PipeHandle->EndpointDescriptor.wMaxPacketSize = 8;
989c2c66affSColin Finck     }
990c2c66affSColin Finck     else
991c2c66affSColin Finck     {
992c2c66affSColin Finck         PipeHandle->EndpointDescriptor.wMaxPacketSize = USB_DEFAULT_MAX_PACKET;
993c2c66affSColin Finck     }
994c2c66affSColin Finck 
995c2c66affSColin Finck     InitializeListHead(&DeviceHandle->PipeHandleList);
996c2c66affSColin Finck 
997c2c66affSColin Finck     Status = USBPORT_OpenPipe(FdoDevice,
998c2c66affSColin Finck                               DeviceHandle,
999c2c66affSColin Finck                               PipeHandle,
1000c2c66affSColin Finck                               NULL);
1001c2c66affSColin Finck 
1002c2c66affSColin Finck     IsOpenedPipe = NT_SUCCESS(Status);
1003c2c66affSColin Finck 
1004c2c66affSColin Finck     if (NT_ERROR(Status))
1005c2c66affSColin Finck     {
1006c2c66affSColin Finck         DPRINT1("USBPORT_CreateDevice: USBPORT_OpenPipe return - %lx\n", Status);
1007c2c66affSColin Finck 
1008c2c66affSColin Finck         KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1009c2c66affSColin Finck                            LOW_REALTIME_PRIORITY,
1010c2c66affSColin Finck                            1,
1011c2c66affSColin Finck                            FALSE);
1012c2c66affSColin Finck 
1013c2c66affSColin Finck         ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG);
1014c2c66affSColin Finck 
1015c2c66affSColin Finck         return Status;
1016c2c66affSColin Finck     }
1017c2c66affSColin Finck 
1018c2c66affSColin Finck     DeviceDescriptor = ExAllocatePoolWithTag(NonPagedPool,
1019c2c66affSColin Finck                                              USB_DEFAULT_MAX_PACKET,
1020c2c66affSColin Finck                                              USB_PORT_TAG);
1021c2c66affSColin Finck 
1022c2c66affSColin Finck     if (!DeviceDescriptor)
1023c2c66affSColin Finck     {
1024c2c66affSColin Finck         DPRINT1("USBPORT_CreateDevice: Not allocated DeviceDescriptor\n");
1025c2c66affSColin Finck         goto ErrorExit;
1026c2c66affSColin Finck     }
1027c2c66affSColin Finck 
1028c2c66affSColin Finck     RtlZeroMemory(DeviceDescriptor, USB_DEFAULT_MAX_PACKET);
1029c2c66affSColin Finck     RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1030c2c66affSColin Finck 
1031c2c66affSColin Finck     SetupPacket.bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
1032c2c66affSColin Finck     SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
1033c2c66affSColin Finck     SetupPacket.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
1034c2c66affSColin Finck     SetupPacket.wLength = USB_DEFAULT_MAX_PACKET;
1035c2c66affSColin Finck 
1036c2c66affSColin Finck     TransferedLen = 0;
1037c2c66affSColin Finck 
1038c2c66affSColin Finck     Status = USBPORT_SendSetupPacket(DeviceHandle,
1039c2c66affSColin Finck                                      FdoDevice,
1040c2c66affSColin Finck                                      &SetupPacket,
1041c2c66affSColin Finck                                      DeviceDescriptor,
1042c2c66affSColin Finck                                      USB_DEFAULT_MAX_PACKET,
1043c2c66affSColin Finck                                      &TransferedLen,
1044c2c66affSColin Finck                                      NULL);
1045c2c66affSColin Finck 
1046c2c66affSColin Finck     RtlCopyMemory(&DeviceHandle->DeviceDescriptor,
1047c2c66affSColin Finck                   DeviceDescriptor,
1048c2c66affSColin Finck                   sizeof(USB_DEVICE_DESCRIPTOR));
1049c2c66affSColin Finck 
1050c2c66affSColin Finck     ExFreePoolWithTag(DeviceDescriptor, USB_PORT_TAG);
1051c2c66affSColin Finck 
1052c2c66affSColin Finck     DescriptorMinSize = RTL_SIZEOF_THROUGH_FIELD(USB_DEVICE_DESCRIPTOR,
1053c2c66affSColin Finck                                                  bMaxPacketSize0);
1054c2c66affSColin Finck 
1055c2c66affSColin Finck     if ((TransferedLen == DescriptorMinSize) && !NT_SUCCESS(Status))
1056c2c66affSColin Finck     {
1057c2c66affSColin Finck         Status = STATUS_SUCCESS;
1058c2c66affSColin Finck     }
1059c2c66affSColin Finck 
1060c2c66affSColin Finck     if (NT_SUCCESS(Status) && (TransferedLen >= DescriptorMinSize))
1061c2c66affSColin Finck     {
1062c2c66affSColin Finck         if ((DeviceHandle->DeviceDescriptor.bLength >= sizeof(USB_DEVICE_DESCRIPTOR)) &&
1063c2c66affSColin Finck             (DeviceHandle->DeviceDescriptor.bDescriptorType == USB_DEVICE_DESCRIPTOR_TYPE))
1064c2c66affSColin Finck         {
1065c2c66affSColin Finck             MaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0;
1066c2c66affSColin Finck 
1067c2c66affSColin Finck             if (MaxPacketSize == 8 ||
1068c2c66affSColin Finck                 MaxPacketSize == 16 ||
1069c2c66affSColin Finck                 MaxPacketSize == 32 ||
1070c2c66affSColin Finck                 MaxPacketSize == 64)
1071c2c66affSColin Finck             {
1072c2c66affSColin Finck                 USBPORT_AddDeviceHandle(FdoDevice, DeviceHandle);
1073c2c66affSColin Finck 
1074c2c66affSColin Finck                 *pUsbdDeviceHandle = DeviceHandle;
1075c2c66affSColin Finck 
1076c2c66affSColin Finck                 KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1077c2c66affSColin Finck                                    LOW_REALTIME_PRIORITY,
1078c2c66affSColin Finck                                    1,
1079c2c66affSColin Finck                                    FALSE);
1080c2c66affSColin Finck 
1081c2c66affSColin Finck                 return Status;
1082c2c66affSColin Finck             }
1083c2c66affSColin Finck         }
1084c2c66affSColin Finck     }
1085c2c66affSColin Finck 
1086c2c66affSColin Finck     DPRINT1("USBPORT_CreateDevice: ERROR!!! TransferedLen - %x, Status - %lx\n",
1087c2c66affSColin Finck             TransferedLen,
1088c2c66affSColin Finck             Status);
1089c2c66affSColin Finck 
1090c2c66affSColin Finck ErrorExit:
1091c2c66affSColin Finck 
1092c2c66affSColin Finck     // FIXME: if Transaction Translator
1093c2c66affSColin Finck 
1094c2c66affSColin Finck     Status = STATUS_DEVICE_DATA_ERROR;
1095c2c66affSColin Finck 
1096c2c66affSColin Finck     if (IsOpenedPipe)
1097c2c66affSColin Finck     {
1098c2c66affSColin Finck         USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle);
1099c2c66affSColin Finck     }
1100c2c66affSColin Finck 
1101c2c66affSColin Finck     KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1102c2c66affSColin Finck                        LOW_REALTIME_PRIORITY,
1103c2c66affSColin Finck                        1,
1104c2c66affSColin Finck                        FALSE);
1105c2c66affSColin Finck 
1106c2c66affSColin Finck     ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG);
1107c2c66affSColin Finck 
1108c2c66affSColin Finck     return Status;
1109c2c66affSColin Finck }
1110c2c66affSColin Finck 
1111c2c66affSColin Finck ULONG
1112c2c66affSColin Finck NTAPI
1113c2c66affSColin Finck USBPORT_AllocateUsbAddress(IN PDEVICE_OBJECT FdoDevice)
1114c2c66affSColin Finck {
1115c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1116c2c66affSColin Finck     ULONG BitMapIdx;
1117c2c66affSColin Finck     ULONG BitNumber;
1118c2c66affSColin Finck     ULONG ix;
1119c2c66affSColin Finck 
1120c2c66affSColin Finck     DPRINT("USBPORT_AllocateUsbAddress \n");
1121c2c66affSColin Finck 
1122c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
1123c2c66affSColin Finck 
1124c2c66affSColin Finck     for (ix = 0; ix < 4; ++ix)
1125c2c66affSColin Finck     {
1126c2c66affSColin Finck         BitMapIdx = 1;
1127c2c66affSColin Finck 
1128c2c66affSColin Finck         for (BitNumber = 0; BitNumber < 32; ++BitNumber)
1129c2c66affSColin Finck         {
1130c2c66affSColin Finck             if (!(FdoExtension->UsbAddressBitMap[ix] & BitMapIdx))
1131c2c66affSColin Finck             {
1132c2c66affSColin Finck                 FdoExtension->UsbAddressBitMap[ix] |= BitMapIdx;
1133c2c66affSColin Finck                 return 32 * ix + BitNumber;
1134c2c66affSColin Finck             }
1135c2c66affSColin Finck 
1136c2c66affSColin Finck             BitMapIdx <<= 2;
1137c2c66affSColin Finck         }
1138c2c66affSColin Finck     }
1139c2c66affSColin Finck 
1140c2c66affSColin Finck     return 0;
1141c2c66affSColin Finck }
1142c2c66affSColin Finck 
1143c2c66affSColin Finck VOID
1144c2c66affSColin Finck NTAPI
1145c2c66affSColin Finck USBPORT_FreeUsbAddress(IN PDEVICE_OBJECT FdoDevice,
1146c2c66affSColin Finck                        IN USHORT DeviceAddress)
1147c2c66affSColin Finck {
1148c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION  FdoExtension;
1149c2c66affSColin Finck     ULONG ix;
1150c2c66affSColin Finck     ULONG BitMapIdx;
1151c2c66affSColin Finck     ULONG BitNumber;
1152c2c66affSColin Finck     USHORT CurrentAddress;
1153c2c66affSColin Finck 
1154c2c66affSColin Finck     DPRINT("USBPORT_FreeUsbAddress: DeviceAddress - %x\n", DeviceAddress);
1155c2c66affSColin Finck 
1156c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
1157c2c66affSColin Finck 
1158c2c66affSColin Finck     for (ix = 0; ix < 4; ++ix)
1159c2c66affSColin Finck     {
1160c2c66affSColin Finck         BitMapIdx = 1;
1161c2c66affSColin Finck         CurrentAddress = 32 * ix;
1162c2c66affSColin Finck 
1163c2c66affSColin Finck         for (BitNumber = 0; BitNumber < 32; ++BitNumber)
1164c2c66affSColin Finck         {
1165c2c66affSColin Finck             if (CurrentAddress == DeviceAddress)
1166c2c66affSColin Finck             {
1167c2c66affSColin Finck                 FdoExtension->UsbAddressBitMap[ix] &= ~BitMapIdx;
1168c2c66affSColin Finck                 return;
1169c2c66affSColin Finck             }
1170c2c66affSColin Finck 
1171c2c66affSColin Finck             BitMapIdx <<= 2;
1172c2c66affSColin Finck             CurrentAddress++;
1173c2c66affSColin Finck         }
1174c2c66affSColin Finck     }
1175c2c66affSColin Finck }
1176c2c66affSColin Finck 
1177c2c66affSColin Finck NTSTATUS
1178c2c66affSColin Finck NTAPI
1179c2c66affSColin Finck USBPORT_InitializeDevice(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
1180c2c66affSColin Finck                          IN PDEVICE_OBJECT FdoDevice)
1181c2c66affSColin Finck {
1182c2c66affSColin Finck     PUSBPORT_ENDPOINT Endpoint;
1183c2c66affSColin Finck     USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
1184c2c66affSColin Finck     ULONG TransferedLen;
1185c2c66affSColin Finck     USHORT DeviceAddress = 0;
1186c2c66affSColin Finck     UCHAR MaxPacketSize;
1187c2c66affSColin Finck     NTSTATUS Status;
1188c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1189c2c66affSColin Finck 
1190c2c66affSColin Finck     DPRINT("USBPORT_InitializeDevice: ... \n");
1191c2c66affSColin Finck 
1192c2c66affSColin Finck     ASSERT(DeviceHandle != NULL);
1193c2c66affSColin Finck 
1194c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
1195c2c66affSColin Finck 
1196c2c66affSColin Finck     KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
1197c2c66affSColin Finck                           Executive,
1198c2c66affSColin Finck                           KernelMode,
1199c2c66affSColin Finck                           FALSE,
1200c2c66affSColin Finck                           NULL);
1201c2c66affSColin Finck 
1202c2c66affSColin Finck     DeviceAddress = USBPORT_AllocateUsbAddress(FdoDevice);
1203c2c66affSColin Finck     ASSERT(DeviceHandle->DeviceAddress == USB_DEFAULT_DEVICE_ADDRESS);
1204c2c66affSColin Finck 
1205c2c66affSColin Finck     RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1206c2c66affSColin Finck 
1207c2c66affSColin Finck     CtrlSetup.bRequest = USB_REQUEST_SET_ADDRESS;
1208c2c66affSColin Finck     CtrlSetup.wValue.W = DeviceAddress;
1209c2c66affSColin Finck 
1210c2c66affSColin Finck     Status = USBPORT_SendSetupPacket(DeviceHandle,
1211c2c66affSColin Finck                                      FdoDevice,
1212c2c66affSColin Finck                                      &CtrlSetup,
1213c2c66affSColin Finck                                      NULL,
1214c2c66affSColin Finck                                      0,
1215c2c66affSColin Finck                                      NULL,
1216c2c66affSColin Finck                                      NULL);
1217c2c66affSColin Finck 
1218c2c66affSColin Finck     DPRINT("USBPORT_InitializeDevice: DeviceAddress - %x. SendSetupPacket Status - %x\n",
1219c2c66affSColin Finck            DeviceAddress,
1220c2c66affSColin Finck            Status);
1221c2c66affSColin Finck 
1222c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1223c2c66affSColin Finck         goto ExitError;
1224c2c66affSColin Finck 
1225c2c66affSColin Finck     DeviceHandle->DeviceAddress = DeviceAddress;
1226c2c66affSColin Finck     Endpoint = DeviceHandle->PipeHandle.Endpoint;
1227c2c66affSColin Finck 
1228c2c66affSColin Finck     Endpoint->EndpointProperties.TotalMaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0;
1229c2c66affSColin Finck     Endpoint->EndpointProperties.DeviceAddress = DeviceAddress;
1230c2c66affSColin Finck 
1231c2c66affSColin Finck     Status = USBPORT_ReopenPipe(FdoDevice, Endpoint);
1232c2c66affSColin Finck 
1233c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1234c2c66affSColin Finck         goto ExitError;
1235c2c66affSColin Finck 
1236c2c66affSColin Finck     USBPORT_Wait(FdoDevice, 10);
1237c2c66affSColin Finck 
1238c2c66affSColin Finck     RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1239c2c66affSColin Finck 
1240c2c66affSColin Finck     CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
1241c2c66affSColin Finck     CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
1242c2c66affSColin Finck     CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
1243c2c66affSColin Finck     CtrlSetup.bmRequestType.B = 0x80;
1244c2c66affSColin Finck 
1245c2c66affSColin Finck     Status = USBPORT_SendSetupPacket(DeviceHandle,
1246c2c66affSColin Finck                                      FdoDevice,
1247c2c66affSColin Finck                                      &CtrlSetup,
1248c2c66affSColin Finck                                      &DeviceHandle->DeviceDescriptor,
1249c2c66affSColin Finck                                      sizeof(USB_DEVICE_DESCRIPTOR),
1250c2c66affSColin Finck                                      &TransferedLen,
1251c2c66affSColin Finck                                      NULL);
1252c2c66affSColin Finck 
1253c2c66affSColin Finck     if (NT_SUCCESS(Status))
1254c2c66affSColin Finck     {
1255c2c66affSColin Finck         ASSERT(TransferedLen == sizeof(USB_DEVICE_DESCRIPTOR));
1256c2c66affSColin Finck         ASSERT(DeviceHandle->DeviceDescriptor.bLength >= sizeof(USB_DEVICE_DESCRIPTOR));
1257c2c66affSColin Finck         ASSERT(DeviceHandle->DeviceDescriptor.bDescriptorType == USB_DEVICE_DESCRIPTOR_TYPE);
1258c2c66affSColin Finck 
1259c2c66affSColin Finck         MaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0;
1260c2c66affSColin Finck 
1261c2c66affSColin Finck         ASSERT((MaxPacketSize == 8) ||
1262c2c66affSColin Finck                (MaxPacketSize == 16) ||
1263c2c66affSColin Finck                (MaxPacketSize == 32) ||
1264c2c66affSColin Finck                (MaxPacketSize == 64));
1265c2c66affSColin Finck     }
1266c2c66affSColin Finck     else
1267c2c66affSColin Finck     {
1268c2c66affSColin Finck ExitError:
1269c2c66affSColin Finck         DPRINT1("USBPORT_InitializeDevice: ExitError. Status - %x\n", Status);
1270c2c66affSColin Finck     }
1271c2c66affSColin Finck 
1272c2c66affSColin Finck     KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1273c2c66affSColin Finck                        LOW_REALTIME_PRIORITY,
1274c2c66affSColin Finck                        1,
1275c2c66affSColin Finck                        FALSE);
1276c2c66affSColin Finck 
1277c2c66affSColin Finck     return Status;
1278c2c66affSColin Finck }
1279c2c66affSColin Finck 
1280c2c66affSColin Finck NTSTATUS
1281c2c66affSColin Finck NTAPI
1282c2c66affSColin Finck USBPORT_GetUsbDescriptor(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
1283c2c66affSColin Finck                          IN PDEVICE_OBJECT FdoDevice,
1284c2c66affSColin Finck                          IN UCHAR Type,
1285c2c66affSColin Finck                          IN PUCHAR ConfigDesc,
1286c2c66affSColin Finck                          IN PULONG ConfigDescSize)
1287c2c66affSColin Finck {
1288c2c66affSColin Finck     USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
1289c2c66affSColin Finck 
1290c2c66affSColin Finck     DPRINT("USBPORT_GetUsbDescriptor: Type - %x\n");
1291c2c66affSColin Finck 
1292c2c66affSColin Finck     RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1293c2c66affSColin Finck 
1294c2c66affSColin Finck     SetupPacket.bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
1295c2c66affSColin Finck     SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
1296c2c66affSColin Finck     SetupPacket.wValue.HiByte = Type;
1297c2c66affSColin Finck     SetupPacket.wLength = (USHORT)*ConfigDescSize;
1298c2c66affSColin Finck 
1299c2c66affSColin Finck     return USBPORT_SendSetupPacket(DeviceHandle,
1300c2c66affSColin Finck                                    FdoDevice,
1301c2c66affSColin Finck                                    &SetupPacket,
1302c2c66affSColin Finck                                    ConfigDesc,
1303c2c66affSColin Finck                                    *ConfigDescSize,
1304c2c66affSColin Finck                                    ConfigDescSize,
1305c2c66affSColin Finck                                    NULL);
1306c2c66affSColin Finck }
1307c2c66affSColin Finck 
1308c2c66affSColin Finck PUSBPORT_INTERFACE_HANDLE
1309c2c66affSColin Finck NTAPI
1310c2c66affSColin Finck USBPORT_GetInterfaceHandle(IN PUSBPORT_CONFIGURATION_HANDLE ConfigurationHandle,
1311c2c66affSColin Finck                            IN UCHAR InterfaceNumber)
1312c2c66affSColin Finck {
1313c2c66affSColin Finck     PUSBPORT_INTERFACE_HANDLE InterfaceHandle;
1314c2c66affSColin Finck     PLIST_ENTRY iHandleList;
1315c2c66affSColin Finck     UCHAR InterfaceNum;
1316c2c66affSColin Finck 
1317c2c66affSColin Finck     DPRINT("USBPORT_GetInterfaceHandle: ConfigurationHandle - %p, InterfaceNumber - %p\n",
1318c2c66affSColin Finck            ConfigurationHandle,
1319c2c66affSColin Finck            InterfaceNumber);
1320c2c66affSColin Finck 
1321c2c66affSColin Finck     iHandleList = ConfigurationHandle->InterfaceHandleList.Flink;
1322c2c66affSColin Finck 
1323c2c66affSColin Finck     while (iHandleList &&
1324c2c66affSColin Finck            (iHandleList != &ConfigurationHandle->InterfaceHandleList))
1325c2c66affSColin Finck     {
1326c2c66affSColin Finck         InterfaceHandle = CONTAINING_RECORD(iHandleList,
1327c2c66affSColin Finck                                             USBPORT_INTERFACE_HANDLE,
1328c2c66affSColin Finck                                             InterfaceLink);
1329c2c66affSColin Finck 
1330c2c66affSColin Finck         InterfaceNum = InterfaceHandle->InterfaceDescriptor.bInterfaceNumber;
1331c2c66affSColin Finck 
1332c2c66affSColin Finck         if (InterfaceNum == InterfaceNumber)
1333c2c66affSColin Finck             return InterfaceHandle;
1334c2c66affSColin Finck 
1335c2c66affSColin Finck         iHandleList = InterfaceHandle->InterfaceLink.Flink;
1336c2c66affSColin Finck     }
1337c2c66affSColin Finck 
1338c2c66affSColin Finck     return NULL;
1339c2c66affSColin Finck }
1340c2c66affSColin Finck 
1341c2c66affSColin Finck NTSTATUS
1342c2c66affSColin Finck NTAPI
1343c2c66affSColin Finck USBPORT_HandleSelectInterface(IN PDEVICE_OBJECT FdoDevice,
1344c2c66affSColin Finck                               IN PIRP Irp,
1345c2c66affSColin Finck                               IN PURB Urb)
1346c2c66affSColin Finck {
1347c2c66affSColin Finck     PUSBPORT_DEVICE_HANDLE DeviceHandle;
1348c2c66affSColin Finck     PUSBPORT_CONFIGURATION_HANDLE ConfigurationHandle;
1349c2c66affSColin Finck     PUSBD_INTERFACE_INFORMATION Interface;
1350c2c66affSColin Finck     PUSBPORT_INTERFACE_HANDLE InterfaceHandle;
1351c2c66affSColin Finck     PUSBPORT_INTERFACE_HANDLE iHandle;
1352c2c66affSColin Finck     PUSBPORT_PIPE_HANDLE PipeHandle;
1353c2c66affSColin Finck     USBD_STATUS USBDStatus;
1354c2c66affSColin Finck     USHORT Length;
1355c2c66affSColin Finck     ULONG ix;
1356c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1357c2c66affSColin Finck 
1358c2c66affSColin Finck     DPRINT("USBPORT_HandleSelectInterface: ... \n");
1359c2c66affSColin Finck 
1360c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
1361c2c66affSColin Finck 
1362c2c66affSColin Finck     KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
1363c2c66affSColin Finck                           Executive,
1364c2c66affSColin Finck                           KernelMode,
1365c2c66affSColin Finck                           FALSE,
1366c2c66affSColin Finck                           NULL);
1367c2c66affSColin Finck 
1368c2c66affSColin Finck     ConfigurationHandle = Urb->UrbSelectInterface.ConfigurationHandle;
1369c2c66affSColin Finck 
1370c2c66affSColin Finck     Interface = &Urb->UrbSelectInterface.Interface;
1371c2c66affSColin Finck 
1372c2c66affSColin Finck     Length = Interface->Length + sizeof(USBD_PIPE_INFORMATION);
1373c2c66affSColin Finck     Urb->UrbHeader.Length = Length;
1374c2c66affSColin Finck 
1375c2c66affSColin Finck     USBDStatus = USBPORT_InitInterfaceInfo(Interface, ConfigurationHandle);
1376c2c66affSColin Finck 
1377c2c66affSColin Finck     if (USBDStatus)
1378c2c66affSColin Finck     {
1379c2c66affSColin Finck         Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)-1;
1380c2c66affSColin Finck         return USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
1381c2c66affSColin Finck     }
1382c2c66affSColin Finck 
1383c2c66affSColin Finck     DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle;
1384c2c66affSColin Finck 
1385c2c66affSColin Finck     InterfaceHandle = USBPORT_GetInterfaceHandle(ConfigurationHandle,
1386c2c66affSColin Finck                                                  Interface->InterfaceNumber);
1387c2c66affSColin Finck 
1388c2c66affSColin Finck     if (InterfaceHandle)
1389c2c66affSColin Finck     {
1390c2c66affSColin Finck         RemoveEntryList(&InterfaceHandle->InterfaceLink);
1391c2c66affSColin Finck 
1392c2c66affSColin Finck         if (InterfaceHandle->InterfaceDescriptor.bNumEndpoints)
1393c2c66affSColin Finck         {
1394c2c66affSColin Finck             PipeHandle = &InterfaceHandle->PipeHandle[0];
1395c2c66affSColin Finck 
1396c2c66affSColin Finck             for (ix = 0;
1397c2c66affSColin Finck                  ix < InterfaceHandle->InterfaceDescriptor.bNumEndpoints;
1398c2c66affSColin Finck                  ix++)
1399c2c66affSColin Finck             {
1400c2c66affSColin Finck                 USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle);
1401c2c66affSColin Finck                 PipeHandle += 1;
1402c2c66affSColin Finck             }
1403c2c66affSColin Finck         }
1404c2c66affSColin Finck     }
1405c2c66affSColin Finck 
1406c2c66affSColin Finck     iHandle = 0;
1407c2c66affSColin Finck 
1408c2c66affSColin Finck     USBDStatus = USBPORT_OpenInterface(Urb,
1409c2c66affSColin Finck                                        DeviceHandle,
1410c2c66affSColin Finck                                        FdoDevice,
1411c2c66affSColin Finck                                        ConfigurationHandle,
1412c2c66affSColin Finck                                        Interface,
1413c2c66affSColin Finck                                        &iHandle,
1414c2c66affSColin Finck                                        1);
1415c2c66affSColin Finck 
1416c2c66affSColin Finck     if (USBDStatus)
1417c2c66affSColin Finck     {
1418c2c66affSColin Finck         Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)-1;
1419c2c66affSColin Finck     }
1420c2c66affSColin Finck     else
1421c2c66affSColin Finck     {
1422c2c66affSColin Finck         if (InterfaceHandle)
1423c2c66affSColin Finck             ExFreePoolWithTag(InterfaceHandle, USB_PORT_TAG);
1424c2c66affSColin Finck 
1425c2c66affSColin Finck         Interface->InterfaceHandle = iHandle;
1426c2c66affSColin Finck 
1427c2c66affSColin Finck         InsertTailList(&ConfigurationHandle->InterfaceHandleList,
1428c2c66affSColin Finck                        &iHandle->InterfaceLink);
1429c2c66affSColin Finck     }
1430c2c66affSColin Finck 
1431c2c66affSColin Finck     KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1432c2c66affSColin Finck                        LOW_REALTIME_PRIORITY,
1433c2c66affSColin Finck                        1,
1434c2c66affSColin Finck                        FALSE);
1435c2c66affSColin Finck 
1436c2c66affSColin Finck     return USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
1437c2c66affSColin Finck }
1438c2c66affSColin Finck 
1439c2c66affSColin Finck NTSTATUS
1440c2c66affSColin Finck NTAPI
1441c2c66affSColin Finck USBPORT_RemoveDevice(IN PDEVICE_OBJECT FdoDevice,
1442c2c66affSColin Finck                      IN OUT PUSBPORT_DEVICE_HANDLE DeviceHandle,
1443c2c66affSColin Finck                      IN ULONG Flags)
1444c2c66affSColin Finck {
1445c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION FdoExtension;
1446c2c66affSColin Finck 
1447c2c66affSColin Finck     DPRINT("USBPORT_RemoveDevice: DeviceHandle - %p, Flags - %x\n",
1448c2c66affSColin Finck            DeviceHandle,
1449c2c66affSColin Finck            Flags);
1450c2c66affSColin Finck 
1451c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
1452c2c66affSColin Finck 
1453c2c66affSColin Finck     if ((Flags & USBD_KEEP_DEVICE_DATA) ||
1454c2c66affSColin Finck         (Flags & USBD_MARK_DEVICE_BUSY))
1455c2c66affSColin Finck     {
1456c2c66affSColin Finck         return STATUS_SUCCESS;
1457c2c66affSColin Finck     }
1458c2c66affSColin Finck 
1459c2c66affSColin Finck     KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
1460c2c66affSColin Finck                           Executive,
1461c2c66affSColin Finck                           KernelMode,
1462c2c66affSColin Finck                           FALSE,
1463c2c66affSColin Finck                           NULL);
1464c2c66affSColin Finck 
1465c2c66affSColin Finck     if (!USBPORT_ValidateDeviceHandle(FdoDevice, DeviceHandle))
1466c2c66affSColin Finck     {
1467c2c66affSColin Finck         KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1468c2c66affSColin Finck                            LOW_REALTIME_PRIORITY,
1469c2c66affSColin Finck                            1,
1470c2c66affSColin Finck                            FALSE);
1471c2c66affSColin Finck 
1472c2c66affSColin Finck         DPRINT1("USBPORT_RemoveDevice: Not valid device handle\n");
1473c2c66affSColin Finck         return STATUS_DEVICE_NOT_CONNECTED;
1474c2c66affSColin Finck     }
1475c2c66affSColin Finck 
1476c2c66affSColin Finck     USBPORT_RemoveDeviceHandle(FdoDevice, DeviceHandle);
1477c2c66affSColin Finck 
1478c2c66affSColin Finck     DeviceHandle->Flags |= DEVICE_HANDLE_FLAG_REMOVED;
1479c2c66affSColin Finck 
1480c2c66affSColin Finck     USBPORT_AbortTransfers(FdoDevice, DeviceHandle);
1481c2c66affSColin Finck 
1482c2c66affSColin Finck     DPRINT("USBPORT_RemoveDevice: DeviceHandleLock - %x\n",
1483c2c66affSColin Finck            DeviceHandle->DeviceHandleLock);
1484c2c66affSColin Finck 
1485c2c66affSColin Finck     while (InterlockedDecrement(&DeviceHandle->DeviceHandleLock) >= 0)
1486c2c66affSColin Finck     {
1487c2c66affSColin Finck         InterlockedIncrement(&DeviceHandle->DeviceHandleLock);
1488c2c66affSColin Finck         USBPORT_Wait(FdoDevice, 100);
1489c2c66affSColin Finck     }
1490c2c66affSColin Finck 
1491c2c66affSColin Finck     DPRINT("USBPORT_RemoveDevice: DeviceHandleLock ok\n");
1492c2c66affSColin Finck 
1493c2c66affSColin Finck     if (DeviceHandle->ConfigHandle)
1494c2c66affSColin Finck     {
1495c2c66affSColin Finck         USBPORT_CloseConfiguration(DeviceHandle, FdoDevice);
1496c2c66affSColin Finck     }
1497c2c66affSColin Finck 
1498c2c66affSColin Finck     USBPORT_ClosePipe(DeviceHandle, FdoDevice, &DeviceHandle->PipeHandle);
1499c2c66affSColin Finck 
1500c2c66affSColin Finck     if (DeviceHandle->DeviceAddress)
1501c2c66affSColin Finck     {
1502c2c66affSColin Finck         USBPORT_FreeUsbAddress(FdoDevice, DeviceHandle->DeviceAddress);
1503c2c66affSColin Finck     }
1504c2c66affSColin Finck 
1505c2c66affSColin Finck     KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1506c2c66affSColin Finck                        LOW_REALTIME_PRIORITY,
1507c2c66affSColin Finck                        1,
1508c2c66affSColin Finck                        FALSE);
1509c2c66affSColin Finck 
1510c2c66affSColin Finck     if (!(DeviceHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB))
1511c2c66affSColin Finck     {
1512c2c66affSColin Finck         ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG);
1513c2c66affSColin Finck     }
1514c2c66affSColin Finck 
1515c2c66affSColin Finck     return STATUS_SUCCESS;
1516c2c66affSColin Finck }
1517c2c66affSColin Finck 
1518c2c66affSColin Finck NTSTATUS
1519c2c66affSColin Finck NTAPI
1520c2c66affSColin Finck USBPORT_RestoreDevice(IN PDEVICE_OBJECT FdoDevice,
1521c2c66affSColin Finck                       IN OUT PUSBPORT_DEVICE_HANDLE OldDeviceHandle,
1522c2c66affSColin Finck                       IN OUT PUSBPORT_DEVICE_HANDLE NewDeviceHandle)
1523c2c66affSColin Finck {
1524c2c66affSColin Finck     PUSBPORT_DEVICE_EXTENSION  FdoExtension;
1525c2c66affSColin Finck     PLIST_ENTRY iHandleList;
1526c2c66affSColin Finck     PUSBPORT_ENDPOINT Endpoint;
1527c2c66affSColin Finck     ULONG EndpointRequirements[2] = {0};
1528c2c66affSColin Finck     USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
1529c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
1530c2c66affSColin Finck     USBD_STATUS USBDStatus;
1531c2c66affSColin Finck     KIRQL OldIrql;
1532c2c66affSColin Finck     PUSBPORT_INTERFACE_HANDLE InterfaceHandle;
1533c2c66affSColin Finck     PUSBPORT_PIPE_HANDLE PipeHandle;
1534c2c66affSColin Finck     PUSBPORT_REGISTRATION_PACKET Packet;
1535c2c66affSColin Finck 
1536c2c66affSColin Finck     DPRINT("USBPORT_RestoreDevice: OldDeviceHandle - %p, NewDeviceHandle - %p\n",
1537c2c66affSColin Finck            OldDeviceHandle,
1538c2c66affSColin Finck            NewDeviceHandle);
1539c2c66affSColin Finck 
1540c2c66affSColin Finck     FdoExtension = FdoDevice->DeviceExtension;
1541c2c66affSColin Finck 
1542c2c66affSColin Finck     KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
1543c2c66affSColin Finck                           Executive,
1544c2c66affSColin Finck                           KernelMode,
1545c2c66affSColin Finck                           FALSE,
1546c2c66affSColin Finck                           NULL);
1547c2c66affSColin Finck 
1548c2c66affSColin Finck     if (!USBPORT_ValidateDeviceHandle(FdoDevice, OldDeviceHandle))
1549c2c66affSColin Finck     {
1550c2c66affSColin Finck         KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1551c2c66affSColin Finck                            LOW_REALTIME_PRIORITY,
1552c2c66affSColin Finck                            1,
1553c2c66affSColin Finck                            FALSE);
1554c2c66affSColin Finck 
1555c2c66affSColin Finck #ifndef NDEBUG
1556c2c66affSColin Finck         DPRINT("USBPORT_RestoreDevice: OldDeviceHandle not valid\n");
1557c2c66affSColin Finck         DbgBreakPoint();
1558c2c66affSColin Finck #endif
1559c2c66affSColin Finck         return STATUS_DEVICE_NOT_CONNECTED;
1560c2c66affSColin Finck     }
1561c2c66affSColin Finck 
1562c2c66affSColin Finck     if (!USBPORT_ValidateDeviceHandle(FdoDevice, NewDeviceHandle))
1563c2c66affSColin Finck     {
1564c2c66affSColin Finck         KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1565c2c66affSColin Finck                            LOW_REALTIME_PRIORITY,
1566c2c66affSColin Finck                            1,
1567c2c66affSColin Finck                            FALSE);
1568c2c66affSColin Finck #ifndef NDEBUG
1569c2c66affSColin Finck         DPRINT("USBPORT_RestoreDevice: NewDeviceHandle not valid\n");
1570c2c66affSColin Finck         DbgBreakPoint();
1571c2c66affSColin Finck #endif
1572c2c66affSColin Finck         return STATUS_DEVICE_NOT_CONNECTED;
1573c2c66affSColin Finck     }
1574c2c66affSColin Finck 
1575c2c66affSColin Finck     USBPORT_RemoveDeviceHandle(FdoDevice, OldDeviceHandle);
1576c2c66affSColin Finck     USBPORT_AbortTransfers(FdoDevice, OldDeviceHandle);
1577c2c66affSColin Finck 
1578c2c66affSColin Finck     while (InterlockedDecrement(&OldDeviceHandle->DeviceHandleLock) >= 0)
1579c2c66affSColin Finck     {
1580c2c66affSColin Finck         InterlockedIncrement(&OldDeviceHandle->DeviceHandleLock);
1581c2c66affSColin Finck         USBPORT_Wait(FdoDevice, 100);
1582c2c66affSColin Finck     }
1583c2c66affSColin Finck 
1584c2c66affSColin Finck     if (sizeof(USB_DEVICE_DESCRIPTOR) == RtlCompareMemory(&NewDeviceHandle->DeviceDescriptor,
1585c2c66affSColin Finck                                                           &OldDeviceHandle->DeviceDescriptor,
1586c2c66affSColin Finck                                                           sizeof(USB_DEVICE_DESCRIPTOR)))
1587c2c66affSColin Finck     {
1588c2c66affSColin Finck         NewDeviceHandle->ConfigHandle = OldDeviceHandle->ConfigHandle;
1589c2c66affSColin Finck 
1590c2c66affSColin Finck         if (OldDeviceHandle->ConfigHandle)
1591c2c66affSColin Finck         {
1592c2c66affSColin Finck             RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1593c2c66affSColin Finck 
1594c2c66affSColin Finck             SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1595c2c66affSColin Finck             SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION;
1596c2c66affSColin Finck             SetupPacket.wValue.W = OldDeviceHandle->ConfigHandle->ConfigurationDescriptor->bConfigurationValue;
1597c2c66affSColin Finck             SetupPacket.wIndex.W = 0;
1598c2c66affSColin Finck             SetupPacket.wLength = 0;
1599c2c66affSColin Finck 
1600c2c66affSColin Finck             USBPORT_SendSetupPacket(NewDeviceHandle,
1601c2c66affSColin Finck                                     FdoDevice,
1602c2c66affSColin Finck                                     &SetupPacket,
1603c2c66affSColin Finck                                     NULL,
1604c2c66affSColin Finck                                     0,
1605c2c66affSColin Finck                                     NULL,
1606c2c66affSColin Finck                                     &USBDStatus);
1607c2c66affSColin Finck 
1608c2c66affSColin Finck             if (USBD_ERROR(USBDStatus))
1609c2c66affSColin Finck                 Status = USBPORT_USBDStatusToNtStatus(NULL, USBDStatus);
1610c2c66affSColin Finck 
1611c2c66affSColin Finck             if (NT_SUCCESS(Status))
1612c2c66affSColin Finck             {
1613c2c66affSColin Finck                 iHandleList = NewDeviceHandle->ConfigHandle->InterfaceHandleList.Flink;
1614c2c66affSColin Finck 
1615c2c66affSColin Finck                 while (iHandleList &&
1616c2c66affSColin Finck                        iHandleList != &NewDeviceHandle->ConfigHandle->InterfaceHandleList)
1617c2c66affSColin Finck                 {
1618c2c66affSColin Finck                     InterfaceHandle = CONTAINING_RECORD(iHandleList,
1619c2c66affSColin Finck                                                         USBPORT_INTERFACE_HANDLE,
1620c2c66affSColin Finck                                                         InterfaceLink);
1621c2c66affSColin Finck 
1622c2c66affSColin Finck                     if (InterfaceHandle->AlternateSetting)
1623c2c66affSColin Finck                     {
1624c2c66affSColin Finck                         RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1625c2c66affSColin Finck 
1626c2c66affSColin Finck                         SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
1627c2c66affSColin Finck                         SetupPacket.bmRequestType.Type = BMREQUEST_STANDARD;
1628c2c66affSColin Finck                         SetupPacket.bmRequestType.Recipient = BMREQUEST_TO_INTERFACE;
1629c2c66affSColin Finck 
1630c2c66affSColin Finck                         SetupPacket.bRequest = USB_REQUEST_SET_INTERFACE;
1631c2c66affSColin Finck                         SetupPacket.wValue.W = InterfaceHandle->InterfaceDescriptor.bAlternateSetting;
1632c2c66affSColin Finck                         SetupPacket.wIndex.W = InterfaceHandle->InterfaceDescriptor.bInterfaceNumber;
1633c2c66affSColin Finck                         SetupPacket.wLength = 0;
1634c2c66affSColin Finck 
1635c2c66affSColin Finck                         USBPORT_SendSetupPacket(NewDeviceHandle,
1636c2c66affSColin Finck                                                 FdoDevice,
1637c2c66affSColin Finck                                                 &SetupPacket,
1638c2c66affSColin Finck                                                 NULL,
1639c2c66affSColin Finck                                                 0,
1640c2c66affSColin Finck                                                 NULL,
1641c2c66affSColin Finck                                                 &USBDStatus);
1642c2c66affSColin Finck                     }
1643c2c66affSColin Finck 
1644c2c66affSColin Finck                     iHandleList = iHandleList->Flink;
1645c2c66affSColin Finck                 }
1646c2c66affSColin Finck             }
1647c2c66affSColin Finck         }
1648c2c66affSColin Finck 
1649c2c66affSColin Finck         if (NewDeviceHandle->Flags & DEVICE_HANDLE_FLAG_INITIALIZED)
1650c2c66affSColin Finck         {
1651c2c66affSColin Finck             DPRINT1("USBPORT_RestoreDevice: FIXME Transaction Translator\n");
1652c2c66affSColin Finck             NewDeviceHandle->TtCount = OldDeviceHandle->TtCount;
1653c2c66affSColin Finck         }
1654c2c66affSColin Finck 
1655c2c66affSColin Finck         while (!IsListEmpty(&OldDeviceHandle->PipeHandleList))
1656c2c66affSColin Finck         {
1657c2c66affSColin Finck             PipeHandle = CONTAINING_RECORD(OldDeviceHandle->PipeHandleList.Flink,
1658c2c66affSColin Finck                                            USBPORT_PIPE_HANDLE,
1659c2c66affSColin Finck                                            PipeLink);
1660c2c66affSColin Finck 
1661c2c66affSColin Finck             DPRINT("USBPORT_RestoreDevice: PipeHandle - %p\n", PipeHandle);
1662c2c66affSColin Finck 
1663c2c66affSColin Finck             USBPORT_RemovePipeHandle(OldDeviceHandle, PipeHandle);
1664c2c66affSColin Finck 
1665c2c66affSColin Finck             if (PipeHandle != &OldDeviceHandle->PipeHandle)
1666c2c66affSColin Finck             {
1667c2c66affSColin Finck                 USBPORT_AddPipeHandle(NewDeviceHandle, PipeHandle);
1668c2c66affSColin Finck 
1669c2c66affSColin Finck                 if (!(PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE))
1670c2c66affSColin Finck                 {
1671c2c66affSColin Finck                     Endpoint = PipeHandle->Endpoint;
1672c2c66affSColin Finck                     Endpoint->DeviceHandle = NewDeviceHandle;
1673c2c66affSColin Finck                     Endpoint->EndpointProperties.DeviceAddress = NewDeviceHandle->DeviceAddress;
1674c2c66affSColin Finck 
1675c2c66affSColin Finck                     Packet = &FdoExtension->MiniPortInterface->Packet;
1676c2c66affSColin Finck 
1677c2c66affSColin Finck                     if (!(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
1678c2c66affSColin Finck                     {
1679c2c66affSColin Finck                         KeAcquireSpinLock(&FdoExtension->MiniportSpinLock,
1680c2c66affSColin Finck                                           &OldIrql);
1681c2c66affSColin Finck 
1682c2c66affSColin Finck                         Packet->ReopenEndpoint(FdoExtension->MiniPortExt,
1683c2c66affSColin Finck                                                &Endpoint->EndpointProperties,
1684c2c66affSColin Finck                                                Endpoint + 1);
1685c2c66affSColin Finck 
1686c2c66affSColin Finck                         Packet->SetEndpointDataToggle(FdoExtension->MiniPortExt,
1687c2c66affSColin Finck                                                       Endpoint + 1,
1688c2c66affSColin Finck                                                       0);
1689c2c66affSColin Finck 
1690c2c66affSColin Finck                         Packet->SetEndpointStatus(FdoExtension->MiniPortExt,
1691c2c66affSColin Finck                                                   Endpoint + 1,
1692c2c66affSColin Finck                                                   USBPORT_ENDPOINT_RUN);
1693c2c66affSColin Finck 
1694c2c66affSColin Finck                         KeReleaseSpinLock(&FdoExtension->MiniportSpinLock,
1695c2c66affSColin Finck                                           OldIrql);
1696c2c66affSColin Finck                     }
1697c2c66affSColin Finck                     else
1698c2c66affSColin Finck                     {
1699c2c66affSColin Finck                         MiniportCloseEndpoint(FdoDevice, Endpoint);
1700c2c66affSColin Finck 
1701c2c66affSColin Finck                         RtlZeroMemory(Endpoint + 1, Packet->MiniPortEndpointSize);
1702c2c66affSColin Finck 
1703c2c66affSColin Finck                         RtlZeroMemory((PVOID)Endpoint->EndpointProperties.BufferVA,
1704c2c66affSColin Finck                                       Endpoint->EndpointProperties.BufferLength);
1705c2c66affSColin Finck 
1706c2c66affSColin Finck                         KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
1707c2c66affSColin Finck 
1708c2c66affSColin Finck                         Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt,
1709c2c66affSColin Finck                                                           &Endpoint->EndpointProperties,
1710c2c66affSColin Finck                                                           EndpointRequirements);
1711c2c66affSColin Finck 
1712c2c66affSColin Finck                         KeReleaseSpinLock(&FdoExtension->MiniportSpinLock,
1713c2c66affSColin Finck                                           OldIrql);
1714c2c66affSColin Finck 
1715c2c66affSColin Finck                         MiniportOpenEndpoint(FdoDevice, Endpoint);
1716c2c66affSColin Finck 
1717c2c66affSColin Finck                         Endpoint->Flags &= ~(ENDPOINT_FLAG_NUKE |
1718c2c66affSColin Finck                                              ENDPOINT_FLAG_ABORTING);
1719c2c66affSColin Finck 
1720c2c66affSColin Finck                         KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
1721c2c66affSColin Finck                                           &Endpoint->EndpointOldIrql);
1722c2c66affSColin Finck 
1723c2c66affSColin Finck                         if (Endpoint->StateLast == USBPORT_ENDPOINT_ACTIVE)
1724c2c66affSColin Finck                         {
1725c2c66affSColin Finck                             KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
1726c2c66affSColin Finck 
1727c2c66affSColin Finck                             Packet->SetEndpointState(FdoExtension->MiniPortExt,
1728c2c66affSColin Finck                                                      Endpoint + 1,
1729c2c66affSColin Finck                                                      USBPORT_ENDPOINT_ACTIVE);
1730c2c66affSColin Finck 
1731c2c66affSColin Finck                             KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
1732c2c66affSColin Finck                         }
1733c2c66affSColin Finck 
1734c2c66affSColin Finck                         KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
1735c2c66affSColin Finck                                           Endpoint->EndpointOldIrql);
1736c2c66affSColin Finck                     }
1737c2c66affSColin Finck                 }
1738c2c66affSColin Finck             }
1739c2c66affSColin Finck         }
1740c2c66affSColin Finck 
1741c2c66affSColin Finck         USBPORT_AddPipeHandle(OldDeviceHandle, &OldDeviceHandle->PipeHandle);
1742c2c66affSColin Finck     }
1743c2c66affSColin Finck     else
1744c2c66affSColin Finck     {
1745c2c66affSColin Finck #ifndef NDEBUG
1746c2c66affSColin Finck         DPRINT("USBPORT_RestoreDevice: New DeviceDescriptor != Old DeviceDescriptor\n");
1747c2c66affSColin Finck         DbgBreakPoint();
1748c2c66affSColin Finck #endif
1749c2c66affSColin Finck         Status = STATUS_UNSUCCESSFUL;
1750c2c66affSColin Finck     }
1751c2c66affSColin Finck 
1752c2c66affSColin Finck     USBPORT_ClosePipe(OldDeviceHandle, FdoDevice, &OldDeviceHandle->PipeHandle);
1753c2c66affSColin Finck 
1754c2c66affSColin Finck     if (OldDeviceHandle->DeviceAddress != 0)
1755c2c66affSColin Finck         USBPORT_FreeUsbAddress(FdoDevice, OldDeviceHandle->DeviceAddress);
1756c2c66affSColin Finck 
1757c2c66affSColin Finck     KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
1758c2c66affSColin Finck                        LOW_REALTIME_PRIORITY,
1759c2c66affSColin Finck                        1,
1760c2c66affSColin Finck                        FALSE);
1761c2c66affSColin Finck 
1762c2c66affSColin Finck     ExFreePoolWithTag(OldDeviceHandle, USB_PORT_TAG);
1763c2c66affSColin Finck 
1764c2c66affSColin Finck     return Status;
1765c2c66affSColin Finck }
1766c2c66affSColin Finck 
1767c2c66affSColin Finck NTSTATUS
1768c2c66affSColin Finck NTAPI
1769c2c66affSColin Finck USBPORT_InitializeTT(IN PDEVICE_OBJECT FdoDevice,
1770c2c66affSColin Finck                      IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle,
1771c2c66affSColin Finck                      IN ULONG TtNumber)
1772c2c66affSColin Finck {
1773c2c66affSColin Finck     DPRINT1("USBPORT_InitializeTT: UNIMPLEMENTED. FIXME. \n");
1774c2c66affSColin Finck     return STATUS_SUCCESS;
1775c2c66affSColin Finck }
1776c2c66affSColin Finck 
1777c2c66affSColin Finck NTSTATUS
1778c2c66affSColin Finck NTAPI
1779c2c66affSColin Finck USBPORT_Initialize20Hub(IN PDEVICE_OBJECT FdoDevice,
1780c2c66affSColin Finck                         IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle,
1781c2c66affSColin Finck                         IN ULONG TtCount)
1782c2c66affSColin Finck {
1783c2c66affSColin Finck     NTSTATUS Status;
1784c2c66affSColin Finck     ULONG ix;
1785c2c66affSColin Finck 
1786c2c66affSColin Finck     DPRINT("USBPORT_Initialize20Hub \n");
1787c2c66affSColin Finck 
1788c2c66affSColin Finck     if (!HubDeviceHandle)
1789c2c66affSColin Finck     {
1790c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
1791c2c66affSColin Finck     }
1792c2c66affSColin Finck 
1793c2c66affSColin Finck     if (HubDeviceHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB)
1794c2c66affSColin Finck     {
1795c2c66affSColin Finck         return STATUS_SUCCESS;
1796c2c66affSColin Finck     }
1797c2c66affSColin Finck 
1798c2c66affSColin Finck     if (TtCount == 0)
1799c2c66affSColin Finck     {
1800c2c66affSColin Finck         HubDeviceHandle->TtCount = 0;
1801c2c66affSColin Finck         return STATUS_SUCCESS;
1802c2c66affSColin Finck     }
1803c2c66affSColin Finck 
1804c2c66affSColin Finck     for (ix = 0; ix < TtCount; ++ix)
1805c2c66affSColin Finck     {
1806c2c66affSColin Finck         Status = USBPORT_InitializeTT(FdoDevice, HubDeviceHandle, ix + 1);
1807c2c66affSColin Finck 
1808c2c66affSColin Finck         if (!NT_SUCCESS(Status))
1809c2c66affSColin Finck             break;
1810c2c66affSColin Finck     }
1811c2c66affSColin Finck 
1812c2c66affSColin Finck     HubDeviceHandle->TtCount = TtCount;
1813c2c66affSColin Finck 
1814c2c66affSColin Finck     return Status;
1815c2c66affSColin Finck }