Sync with trunk head
[reactos.git] / drivers / usb / nt4compat / usbdriver / dmgrdisp.c
1 /**
2 * dmgrdisp.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "usbdriver.h"
23
24 VOID
25 disp_urb_completion(PURB purb, PVOID context)
26 {
27 PUSB_DEV_MANAGER dev_mgr;
28 ULONG ctrl_code;
29 NTSTATUS status;
30 PDEVEXT_HEADER dev_hdr;
31
32 UNREFERENCED_PARAMETER(context);
33
34 if (purb == NULL)
35 return;
36
37 ctrl_code = (ULONG) purb->reference;
38 dev_mgr = (PUSB_DEV_MANAGER) purb->context;
39
40 // at this stage, the irp can not be canceled since the urb
41 // won't be found in any queue and the irp is not in any queue.
42 // see line 4685 in hub.c
43 // Sometimes, it may be very fast to enter this routine before
44 // the dev_mgr_register_irp to be called in dispatch routine in
45 // usb2.0 environment as
46 // we did in usb1.1 driver. We can not simply add a loop to wait
47 // for the dispatch thread to add the irp to the list, because
48 // here we are at DPC level higher than the dispatch thread
49 // running level. And the solution is to register the irp
50 // before the urb is scheduled instead of registering it after
51 // urb is scheduled.
52 if (purb->pirp)
53 {
54 PIO_STACK_LOCATION irp_stack;
55 dev_mgr_remove_irp(dev_mgr, purb->pirp);
56
57 status = purb->status;
58 irp_stack = IoGetCurrentIrpStackLocation(purb->pirp);
59
60 if (purb->status != STATUS_SUCCESS)
61 {
62 purb->pirp->IoStatus.Information = 0;
63 }
64 else
65 {
66 // currently only IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL
67 // are allowed. And we do not need to set information
68 // for IRP_MJ_INTERNAL_DEVICE_CONTROL
69 if (irp_stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
70 purb->pirp->IoStatus.Information = purb->data_length;
71 }
72 purb->pirp->IoStatus.Status = status;
73 if (irp_stack)
74 {
75 dev_hdr = irp_stack->DeviceObject->DeviceExtension;
76 if (dev_hdr->start_io)
77 {
78 IoStartNextPacket(irp_stack->DeviceObject, TRUE);
79 }
80 }
81 IoCompleteRequest(purb->pirp, IO_NO_INCREMENT);
82 }
83 return;
84 }
85
86 VOID
87 disp_noio_urb_completion(PURB purb, PVOID context)
88 {
89 PUSB_CTRL_SETUP_PACKET psetup;
90 PURB purb2;
91 PUSB_DEV_MANAGER dev_mgr;
92 NTSTATUS status = STATUS_SUCCESS;
93 PIO_STACK_LOCATION irp_stack;
94 PDEVEXT_HEADER dev_hdr;
95
96 if (purb == NULL)
97 return;
98
99 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
100
101 if ((psetup->bmRequestType == 0x2) &&
102 (psetup->bRequest == USB_REQ_CLEAR_FEATURE) &&
103 (psetup->wIndex == 0)) //reset pipe
104 {
105 purb2 = (PURB) context;
106 }
107 else
108 {
109 purb2 = purb;
110 }
111
112 if (purb2->pirp == NULL)
113 return;
114
115 dev_mgr = (PUSB_DEV_MANAGER) purb2->context;
116
117 dev_mgr_remove_irp(dev_mgr, purb2->pirp);
118
119 if (purb->status != STATUS_SUCCESS)
120 status = STATUS_IO_DEVICE_ERROR;
121
122 purb2->pirp->IoStatus.Information = 0;
123 purb2->pirp->IoStatus.Status = status;
124 irp_stack = IoGetCurrentIrpStackLocation(purb->pirp);
125 if (irp_stack)
126 {
127 dev_hdr = irp_stack->DeviceObject->DeviceExtension;
128 if (dev_hdr->start_io)
129 {
130 IoStartNextPacket(irp_stack->DeviceObject, TRUE);
131 }
132 }
133 IoCompleteRequest(purb2->pirp, IO_NO_INCREMENT);
134 return;
135 }
136
137 //this function is called by the hcd's
138 //dispatch when they have done their job.
139 NTSTATUS
140 dev_mgr_dispatch(IN PUSB_DEV_MANAGER dev_mgr, IN PIRP irp)
141 {
142 PIO_STACK_LOCATION irp_stack;
143 NTSTATUS status;
144 ULONG ctrl_code;
145 USE_NON_PENDING_IRQL;
146
147 ASSERT(irp);
148 if (dev_mgr == NULL)
149 {
150 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
151 }
152
153 status = STATUS_SUCCESS;
154 irp_stack = IoGetCurrentIrpStackLocation(irp);
155 ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
156
157 switch (irp_stack->MajorFunction)
158 {
159 case IRP_MJ_CREATE:
160 {
161 InterlockedIncrement(&dev_mgr->open_count);
162 EXIT_DISPATCH(STATUS_SUCCESS, irp);
163 }
164 case IRP_MJ_CLOSE:
165 {
166 InterlockedDecrement(&dev_mgr->open_count);
167 EXIT_DISPATCH(STATUS_SUCCESS, irp);
168 }
169 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
170 case IRP_MJ_DEVICE_CONTROL:
171 {
172 switch (ctrl_code)
173 {
174 case IOCTL_GET_DEV_COUNT:
175 {
176 LONG dev_count;
177
178 irp->IoStatus.Information = 0;
179 if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LONG))
180 {
181 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
182 }
183
184 KeAcquireSpinLock(&dev_mgr->dev_list_lock, &old_irql);
185 dev_count = usb_count_list(&dev_mgr->dev_list);
186 KeReleaseSpinLock(&dev_mgr->dev_list_lock, old_irql);
187
188 *((PLONG) irp->AssociatedIrp.SystemBuffer) = dev_count;
189 irp->IoStatus.Information = sizeof(LONG);
190 EXIT_DISPATCH(STATUS_SUCCESS, irp);
191 }
192 case IOCTL_ENUM_DEVICES:
193 {
194 PLIST_ENTRY pthis, pnext;
195 LONG dev_count, array_size, i, j = 0;
196 PUSB_DEV pdev;
197 PENUM_DEV_ARRAY peda;
198
199 irp->IoStatus.Information = 0;
200 if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(LONG))
201 {
202 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
203 }
204 if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ENUM_DEV_ARRAY))
205 {
206 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
207 }
208 array_size = *((PULONG) irp->AssociatedIrp.SystemBuffer);
209
210 KeAcquireSpinLock(&dev_mgr->dev_list_lock, &old_irql);
211 dev_count = usb_count_list(&dev_mgr->dev_list);
212 dev_count = dev_count > array_size ? array_size : dev_count;
213 peda = (PENUM_DEV_ARRAY) irp->AssociatedIrp.SystemBuffer;
214 RtlZeroMemory(peda, sizeof(ENUM_DEV_ARRAY) + (dev_count - 1) * sizeof(ENUM_DEV_ELEMENT));
215
216 if (dev_count)
217 {
218 ListFirst(&dev_mgr->dev_list, pthis);
219 for(i = 0, j = 0; i < dev_count; i++)
220 {
221 pdev = struct_ptr(pthis, USB_DEV, dev_link);
222 ListNext(&dev_mgr->dev_list, pthis, pnext);
223 pthis = pnext;
224
225 lock_dev(pdev, FALSE);
226 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
227 {
228 unlock_dev(pdev, FALSE);
229 continue;
230 }
231
232 if (dev_state(pdev) < USB_DEV_STATE_ADDRESSED)
233 {
234 unlock_dev(pdev, FALSE);
235 continue;
236 }
237
238 peda->dev_arr[i].dev_handle = (pdev->dev_id << 16);
239 //may not get the desc yet
240 if (pdev->pusb_dev_desc)
241 {
242 peda->dev_arr[i].product_id = pdev->pusb_dev_desc->idProduct;
243 peda->dev_arr[i].vendor_id = pdev->pusb_dev_desc->idVendor;
244 }
245 else
246 {
247 peda->dev_arr[i].product_id = 0xffff;
248 peda->dev_arr[i].vendor_id = 0xffff;
249 }
250 peda->dev_arr[i].dev_addr = pdev->dev_addr;
251 unlock_dev(pdev, FALSE);
252 j++;
253 }
254 }
255 peda->dev_count = dev_count ? j : 0;
256 KeReleaseSpinLock(&dev_mgr->dev_list_lock, old_irql);
257
258 irp->IoStatus.Information =
259 sizeof(ENUM_DEV_ARRAY) + (dev_count - 1) * sizeof(ENUM_DEV_ELEMENT);
260 EXIT_DISPATCH(STATUS_SUCCESS, irp);
261 }
262 case IOCTL_GET_DEV_DESC:
263 {
264 GET_DEV_DESC_REQ gddr;
265 PUSB_DESC_HEADER pusb_desc_header;
266 PUSB_DEV pdev;
267 LONG buf_size;
268
269 if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(GET_DEV_DESC_REQ))
270 {
271 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
272 }
273
274 if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < 8)
275 {
276 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
277 }
278
279 status = STATUS_SUCCESS;
280 buf_size = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
281 RtlCopyMemory(&gddr, irp->AssociatedIrp.SystemBuffer, sizeof(GET_DEV_DESC_REQ));
282 pusb_desc_header = irp->AssociatedIrp.SystemBuffer;
283
284 if (gddr.desc_type != USB_DT_CONFIG && gddr.desc_type != USB_DT_DEVICE)
285 {
286 EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp);
287 }
288
289 if (usb_query_and_lock_dev(dev_mgr, gddr.dev_handle, &pdev) != STATUS_SUCCESS)
290 {
291 EXIT_DISPATCH(STATUS_IO_DEVICE_ERROR, irp);
292 }
293
294 lock_dev(pdev, FALSE);
295 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
296 {
297 status = STATUS_INVALID_DEVICE_STATE;
298 goto ERROR_OUT;
299 }
300 if (dev_state(pdev) != USB_DEV_STATE_ADDRESSED &&
301 dev_state(pdev) != USB_DEV_STATE_CONFIGURED)
302 {
303 status = STATUS_DEVICE_NOT_READY;
304 goto ERROR_OUT;
305 }
306
307 if (pdev->pusb_dev_desc == NULL)
308 {
309 status = STATUS_DEVICE_NOT_READY;
310 goto ERROR_OUT;
311 }
312
313 if (gddr.desc_type == USB_DT_DEVICE)
314 {
315 RtlCopyMemory(pusb_desc_header,
316 pdev->pusb_dev_desc,
317 buf_size > sizeof(USB_DEVICE_DESC)
318 ? sizeof(USB_DEVICE_DESC) : buf_size);
319
320 irp->IoStatus.Information =
321 buf_size >= sizeof(USB_DEVICE_DESC) ? sizeof(USB_DEVICE_DESC) : buf_size;
322 }
323 else if (gddr.desc_type == USB_DT_CONFIG)
324 {
325 PUSB_CONFIGURATION_DESC pusb_config_desc;
326 if (pdev->pusb_dev_desc->bNumConfigurations <= gddr.desc_idx)
327 {
328 status = STATUS_INVALID_PARAMETER;
329 goto ERROR_OUT;
330 }
331
332 pusb_config_desc = usb_find_config_desc_by_idx((PUCHAR) & pdev->pusb_dev_desc[1],
333 gddr.desc_idx,
334 pdev->pusb_dev_desc->
335 bNumConfigurations);
336
337 if (pusb_config_desc == NULL)
338 {
339 status = STATUS_DEVICE_NOT_READY;
340 goto ERROR_OUT;
341 }
342
343 RtlCopyMemory(pusb_desc_header,
344 pusb_config_desc,
345 buf_size >= pusb_config_desc->wTotalLength
346 ? pusb_config_desc->wTotalLength : buf_size);
347
348 irp->IoStatus.Information =
349 buf_size >= pusb_config_desc->wTotalLength
350 ? pusb_config_desc->wTotalLength : buf_size;
351 }
352 ERROR_OUT:
353 unlock_dev(pdev, FALSE);
354 usb_unlock_dev(pdev);
355 EXIT_DISPATCH(status, irp);
356 }
357 case IOCTL_SUBMIT_URB_RD:
358 case IOCTL_SUBMIT_URB_WR:
359 case IOCTL_SUBMIT_URB_NOIO:
360 {
361 PURB purb;
362 ULONG endp_idx, if_idx, user_buffer_length = 0;
363 PUCHAR user_buffer = NULL;
364 PUSB_DEV pdev;
365 DEV_HANDLE endp_handle;
366 PUSB_ENDPOINT pendp;
367
368 if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(URB))
369 {
370 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
371 }
372
373 purb = (PURB) irp->AssociatedIrp.SystemBuffer;
374 endp_handle = purb->endp_handle;
375
376 if (ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR)
377 {
378 if (irp_stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
379 {
380 user_buffer_length = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
381 if (user_buffer_length == 0)
382 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
383 user_buffer = MmGetSystemAddressForMdl(irp->MdlAddress);
384 }
385 else
386 {
387 if (purb->data_buffer == NULL || purb->data_length == 0)
388 EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
389 user_buffer_length = purb->data_length;
390 user_buffer = purb->data_buffer;
391 }
392 }
393
394 if (usb_query_and_lock_dev(dev_mgr, endp_handle & ~0xffff, &pdev) != STATUS_SUCCESS)
395 {
396 EXIT_DISPATCH(STATUS_IO_DEVICE_ERROR, irp);
397 }
398
399
400 lock_dev(pdev, FALSE);
401 if (dev_state(pdev) == USB_DEV_STATE_ZOMB || (dev_state(pdev) < USB_DEV_STATE_ADDRESSED))
402
403 {
404 status = STATUS_INVALID_DEVICE_STATE;
405 goto ERROR_OUT1;
406 }
407
408 if (dev_state(pdev) == USB_DEV_STATE_ADDRESSED && !default_endp_handle(endp_handle))
409 {
410 status = STATUS_DEVICE_NOT_READY;
411 goto ERROR_OUT1;
412 }
413
414 if_idx = if_idx_from_handle(endp_handle);
415 endp_idx = endp_idx_from_handle(endp_handle);
416
417 //if_idx exceeds the upper limit
418 if (pdev->usb_config)
419 {
420 if (if_idx >= pdev->usb_config->if_count
421 || endp_idx >= pdev->usb_config->interf[if_idx].endp_count)
422 {
423 if (!default_endp_handle(endp_handle))
424 {
425 status = STATUS_INVALID_DEVICE_STATE;
426 goto ERROR_OUT1;
427 }
428 }
429 }
430
431 endp_from_handle(pdev, endp_handle, pendp);
432 // FIXME: don't know what evil will let loose
433 if (endp_type(pendp) != USB_ENDPOINT_XFER_CONTROL)
434 {
435 if (user_buffer_length > 0x100000)
436 {
437 status = STATUS_INVALID_PARAMETER;
438 goto ERROR_OUT1;
439 }
440 }
441
442 purb->pirp = irp;
443 purb->context = dev_mgr;
444 purb->reference = ctrl_code;
445
446 if (ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR)
447 {
448 if (ctrl_code == IOCTL_SUBMIT_URB_RD)
449 KeFlushIoBuffers(irp->MdlAddress, TRUE, TRUE);
450 else
451 KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
452
453 purb->data_buffer = user_buffer;
454 purb->data_length = user_buffer_length;
455 purb->completion = disp_urb_completion;
456 }
457 else
458 {
459 purb->completion = disp_noio_urb_completion;
460 }
461
462 unlock_dev(pdev, FALSE);
463
464 // we have to mark irp before the urb is scheduled to
465 // avoid race condition
466 IoMarkIrpPending(irp);
467 ASSERT(dev_mgr_register_irp(dev_mgr, irp, purb));
468 status = usb_submit_urb(dev_mgr, purb);
469 if (status != STATUS_PENDING)
470 {
471 IoGetCurrentIrpStackLocation((irp))->Control &= ~SL_PENDING_RETURNED;
472 dev_mgr_remove_irp(dev_mgr, irp);
473 }
474 usb_unlock_dev(pdev);
475 if (status != STATUS_PENDING)
476 {
477 irp->IoStatus.Status = status;
478 IoCompleteRequest(irp, IO_NO_INCREMENT);
479 }
480 return status;
481 ERROR_OUT1:
482 unlock_dev(pdev, FALSE);
483 usb_unlock_dev(pdev);
484 irp->IoStatus.Information = 0;
485 EXIT_DISPATCH(status, irp);
486 }
487 default:
488 {
489 irp->IoStatus.Information = 0;
490 EXIT_DISPATCH(STATUS_NOT_IMPLEMENTED, irp);
491 }
492 }
493 }
494 default:
495 {
496 irp->IoStatus.Information = 0;
497 break;
498 }
499 }
500 EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp);
501 }
502
503 /*#define IOCTL_GET_DEV_COUNT CTL_CODE( FILE_HCD_DEV_TYPE, 4093, METHOD_BUFFERED, FILE_ANY_ACCESS )
504 //input_buffer and input_buffer_length is zero, output_buffer is to receive a dword value of the
505 //dev count, output_buffer_length must be no less than sizeof( long ).
506
507 #define IOCTL_ENUM_DEVICES CTL_CODE( FILE_HCD_DEV_TYPE, 4094, METHOD_BUFFERED, FILE_ANY_ACCESS )
508 //input_buffer is a dword value to indicate the count of elements in the array
509 //input_buffer_length is sizeof( long ), output_buffer is to receive a
510 //structure ENUM_DEV_ARRAY where dev_count is the elements hold in this array.
511
512 #define IOCTL_GET_DEV_DESC CTL_CODE( FILE_HCD_DEV_TYPE, 4095, METHOD_BUFFERED, FILE_ANY_ACCESS )
513 //input_buffer is a structure GET_DEV_DESC_REQ, and the input_buffer_length is
514 //no less than sizeof( input_buffer ), output_buffer is a buffer to receive the
515 //requested dev's desc, and output_buffer_length specifies the length of the
516 //buffer
517
518 #define IOCTL_SUBMIT_URB_RD CTL_CODE( FILE_HCD_DEV_TYPE, 4096, METHOD_IN_DIRECT, FILE_ANY_ACCESS )
519 #define IOCTL_SUBMIT_URB_WR CTL_CODE( FILE_HCD_DEV_TYPE, 4097, METHOD_OUT_DIRECT, FILE_ANY_ACCESS )
520 // input_buffer is a URB, and input_buffer_length is equal to or greater than
521 // sizeof( URB ); the output_buffer is a buffer to receive data from or send data
522 // to device. only the following urb fields can be accessed, others must be zeroed.
523 // DEV_HANDLE endp_handle;
524 // UCHAR setup_packet[8]; //for control pipe
525 // the choosing of IOCTL_SUBMIT_URB_RD or IOCTL_SUBMIT_URB_WR should be determined
526 // by the current URB, for example, a request string from device will use XXX_RD,
527 // and a write to the bulk endpoint will use XXX_WR
528
529 #define IOCTL_SUBMIT_URB_NOIO CTL_CODE( FILE_HCD_DEV_TYPE, 4098, METHOD_BUFFERED, FILE_ANY_ACCESS )
530 // input_buffer is a URB, and input_buffer_length is equal to or greater than
531 // sizeof( URB ); the output_buffer is null and no output_buffer_length,
532 // only the following fields in urb can be accessed, others must be zeroed.
533 // DEV_HANDLE endp_handle;
534 // UCHAR setup_packet[8]; //for control pipe
535 */