1 /* libusb-win32, Generic Windows USB Library
2 * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 #include "libusb_driver.h"
21
22
23
get_descriptor(libusb_device_t * dev,void * buffer,int size,int type,int recipient,int index,int language_id,int * received,int timeout)24 NTSTATUS get_descriptor(libusb_device_t *dev,
25 void *buffer, int size, int type, int recipient,
26 int index, int language_id, int *received, int timeout)
27 {
28 NTSTATUS status = STATUS_SUCCESS;
29 URB urb;
30
31 USBMSG("buffer size: %d type: %04d recipient: %04d index: %04d language id: %04d timeout: %d\n",
32 size, type, recipient, index, language_id, timeout);
33
34 memset(&urb, 0, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
35
36 switch (recipient)
37 {
38 case USB_RECIP_DEVICE:
39 urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
40 break;
41 case USB_RECIP_INTERFACE:
42 urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE;
43 break;
44 case USB_RECIP_ENDPOINT:
45 urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT;
46 break;
47 default:
48 USBERR0("invalid recipient\n");
49 return STATUS_INVALID_PARAMETER;
50 }
51
52 urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
53 urb.UrbControlDescriptorRequest.TransferBufferLength = size;
54 urb.UrbControlDescriptorRequest.TransferBuffer = buffer;
55 urb.UrbControlDescriptorRequest.DescriptorType = (UCHAR)type;
56 urb.UrbControlDescriptorRequest.Index = (UCHAR)index;
57 urb.UrbControlDescriptorRequest.LanguageId = (USHORT)language_id;
58
59 // the device and active config descriptors are cached. If the request
60 // is for one of these and we have already retrieved it, then this is
61 // a non-blocking non-i/o call.
62
63 if (type == USB_DEVICE_DESCRIPTOR_TYPE &&
64 recipient == USB_RECIP_DEVICE &&
65 index == 0 &&
66 language_id == 0 &&
67 size >= sizeof(USB_DEVICE_DESCRIPTOR))
68 {
69 // this is a device descriptor request.
70 if (dev->device_descriptor.bLength == 0)
71 {
72 // this is the first request made for the device descriptor.
73 // Cache it now and forever
74 status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
75 if (NT_SUCCESS(status) && urb.UrbControlDescriptorRequest.TransferBufferLength < sizeof(USB_DEVICE_DESCRIPTOR))
76 {
77 USBERR("Invalid device decriptor length %d\n", urb.UrbControlDescriptorRequest.TransferBufferLength);
78 status = STATUS_BAD_DEVICE_TYPE;
79 *received = 0;
80 goto Done;
81 }
82
83 if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
84 {
85 USBERR("getting descriptor failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
86 *received = 0;
87 goto Done;
88 }
89
90 // valid device descriptor
91 size = sizeof(USB_DEVICE_DESCRIPTOR);
92 RtlCopyMemory(&dev->device_descriptor, buffer, size);
93 *received = size;
94
95 }
96 else
97 {
98 // device descriptor is already cached.
99 size = sizeof(USB_DEVICE_DESCRIPTOR);
100 RtlCopyMemory(buffer, &dev->device_descriptor, size);
101 *received = size;
102 }
103
104 goto Done;
105 }
106
107 if (type == USB_CONFIGURATION_DESCRIPTOR_TYPE &&
108 recipient == USB_RECIP_DEVICE &&
109 language_id == 0 &&
110 size >= sizeof(USB_CONFIGURATION_DESCRIPTOR))
111 {
112 if (dev->device_descriptor.bLength != 0 && index >=dev->device_descriptor.bNumConfigurations)
113 {
114 USBWRN("config descriptor index %d out of range.\n", index);
115 status = STATUS_NO_MORE_ENTRIES;
116 *received = 0;
117 goto Done;
118 }
119
120 // this is a config descriptor request.
121 if (!dev->config.descriptor || dev->config.index != index)
122 {
123 // this is either:
124 // * The first request made for a config descriptor.
125 // * A request for a config descriptor other than the cached index.
126 status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
127
128 if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
129 {
130 USBERR("getting descriptor failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
131 *received = 0;
132 goto Done;
133 }
134
135 if (!dev->config.descriptor &&
136 urb.UrbControlDescriptorRequest.TransferBufferLength >= ((PUSB_CONFIGURATION_DESCRIPTOR)buffer)->wTotalLength)
137 {
138 //
139 // This is a special case scenario where we cache the first
140 // config deescriptor requested when dev->config.descriptor == NULL
141 // and this was a request for the *entire* descriptor.
142 //
143 // Nearly all windows USB devices will only have one configuration.
144 // In the case a the filter driver, it does *not* auto configure the
145 // device which is where the *active* config descriptor caching occurs.
146 //
147 // This code ensures the first config descriptor requested is always cached
148 // even if the device is not configured yet.
149 //
150
151 PUSB_CONFIGURATION_DESCRIPTOR config_desc;
152 size = ((PUSB_CONFIGURATION_DESCRIPTOR)buffer)->wTotalLength;
153
154 if (!( config_desc = ExAllocatePool(NonPagedPool, size)))
155 {
156 USBERR0("memory allocation error\n");
157 status = STATUS_NO_MEMORY;
158 goto Done;
159 }
160
161 dev->config.descriptor=config_desc;
162
163 RtlCopyMemory(dev->config.descriptor,buffer,size);
164 dev->config.value=0;
165 dev->config.total_size=size;
166 dev->config.index=index;
167
168 *received = size;
169 }
170 else
171 {
172 *received = urb.UrbControlDescriptorRequest.TransferBufferLength;
173 }
174 goto Done;
175 }
176 else
177 {
178 // This is a request for the active configuration descriptor.
179 // This is only updated upon a successful set_configuration().
180 size = (size > dev->config.descriptor->wTotalLength) ? dev->config.descriptor->wTotalLength : size;
181 RtlCopyMemory(buffer, dev->config.descriptor, size);
182
183 *received = size;
184 goto Done;
185 }
186 }
187
188 // this is not a device or config descriptor reequest
189 status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
190
191
192 if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
193 {
194 USBERR("getting descriptor failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
195 *received = 0;
196 }
197 else
198 {
199 *received = urb.UrbControlDescriptorRequest.TransferBufferLength;
200 }
201
202 Done:
203 return status;
204 }
205
get_config_descriptor(libusb_device_t * dev,int value,int * size,int * index)206 PUSB_CONFIGURATION_DESCRIPTOR get_config_descriptor(
207 libusb_device_t *dev,
208 int value,
209 int *size,
210 int* index)
211 {
212 NTSTATUS status;
213 USB_CONFIGURATION_DESCRIPTOR *desc = NULL;
214 USB_DEVICE_DESCRIPTOR device_descriptor;
215 int i;
216 volatile int desc_size;
217
218 *index = 0;
219
220 status = get_descriptor(dev, &device_descriptor,
221 sizeof(USB_DEVICE_DESCRIPTOR),
222 USB_DEVICE_DESCRIPTOR_TYPE,
223 USB_RECIP_DEVICE,
224 0, 0, size, LIBUSB_DEFAULT_TIMEOUT);
225
226 if (!NT_SUCCESS(status) || *size != sizeof(USB_DEVICE_DESCRIPTOR))
227 {
228 USBERR0("getting device descriptor failed\n");
229 return NULL;
230 }
231
232 if (!(desc = ExAllocatePool(NonPagedPool,
233 sizeof(USB_CONFIGURATION_DESCRIPTOR))))
234 {
235 USBERR0("memory allocation error\n");
236 return NULL;
237 }
238
239 for (i = 0; i < device_descriptor.bNumConfigurations; i++)
240 {
241
242 if (!NT_SUCCESS(get_descriptor(dev, desc,
243 sizeof(USB_CONFIGURATION_DESCRIPTOR),
244 USB_CONFIGURATION_DESCRIPTOR_TYPE,
245 USB_RECIP_DEVICE,
246 i, 0, size, LIBUSB_DEFAULT_TIMEOUT)))
247 {
248 USBERR0("getting configuration descriptor failed\n");
249 break;
250 }
251
252 // if value is negative, get the descriptor by index
253 // if positive, get it by value.
254 if ((value > 0 && desc->bConfigurationValue == value) ||
255 (value < 0 && -(i+1) == (value)))
256 {
257 desc_size = desc->wTotalLength;
258 ExFreePool(desc);
259
260 if (!(desc = ExAllocatePool(NonPagedPool, desc_size)))
261 {
262 USBERR0("memory allocation error\n");
263 break;
264 }
265
266 if (!NT_SUCCESS(get_descriptor(dev, desc, desc_size,
267 USB_CONFIGURATION_DESCRIPTOR_TYPE,
268 USB_RECIP_DEVICE,
269 i, 0, size, LIBUSB_DEFAULT_TIMEOUT)))
270 {
271 USBERR0("getting configuration descriptor failed\n");
272 break;
273 }
274 else
275 {
276 *index = i;
277 }
278
279 return desc;
280 }
281 }
282
283 if (desc)
284 {
285 ExFreePool(desc);
286 }
287
288 return NULL;
289 }
290