1 /* libusb-win32, Generic Windows USB Library
2 * Copyright (c) 2010 Travis Robinson <libusbdotnet@gmail.com>
3 * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20
21 #include "libusb_driver.h"
22 #include "libusb-win32_version.h"
23
24 // used but all transfer functions to get a valid libusb_endpoint_t *
25 // for the request.
26 //
27 #define TRANSFER_IOCTL_GET_PIPEINFO() \
28 /* check if the pipe exists and get the pipe information */ \
29 if (!get_pipe_info(dev, request->endpoint.endpoint,&pipe_info)) \
30 { \
31 USBERR("%s: failed getting pipe info for endpoint: %02Xh\n", \
32 dispCtlCode, request->endpoint.endpoint); \
33 status = STATUS_INVALID_PARAMETER; \
34 goto IOCTL_Done; \
35 }
36
37 // warns if receive buffer is not an interval of the maximum packet size.
38 #define TRANSFER_IOCTL_CHECK_READ_BUFFER() \
39 /* read buffer lengthd must be equal to or an interval of the max */ \
40 /* packet size */ \
41 if (!pipe_info->maximum_packet_size) \
42 { \
43 USBWRN("%s: wMaxPacketSize=0 for endpoint %02Xh.\n", \
44 dispCtlCode, request->endpoint.endpoint); \
45 status = STATUS_INVALID_PARAMETER; \
46 goto IOCTL_Done; \
47 } \
48 else if (transfer_buffer_length % pipe_info->maximum_packet_size) \
49 { \
50 USBWRN("%s: buffer length %d is not an interval wMaxPacketSize " \
51 "for endpoint %02Xh.\n", \
52 dispCtlCode, transfer_buffer_length, request->endpoint.endpoint); \
53 }
54
55 // validates the urb function and direction against libusb_endpoint_t
56 #define TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION() \
57 if (urbFunction != UrbFunctionFromEndpoint(pipe_info) || \
58 usbdDirection != UsbdDirectionFromEndpoint(pipe_info)) \
59 { \
60 USBERR("%s: not compatible with endpoint %02Xh.\n" \
61 "\turbFunction =%Xh usbdDirection =%Xh\n" \
62 "\tpipeFunction =%Xh pipeDirection =%Xh\n", \
63 dispCtlCode, \
64 pipe_info->address, \
65 urbFunction,usbdDirection, \
66 UrbFunctionFromEndpoint(pipe_info), \
67 UsbdDirectionFromEndpoint(pipe_info)); \
68 status = STATUS_INVALID_PARAMETER; \
69 goto IOCTL_Done; \
70 }
71
72 // calls the transfer function and returns NTSTATUS
73 #define TRANSFER_IOCTL_EXECUTE() \
74 if (transfer_buffer_length > (ULONG)(maxTransferSize)) \
75 /* split large transfers */ \
76 return large_transfer(dev, irp, \
77 usbdDirection, \
78 urbFunction, \
79 pipe_info, \
80 request->endpoint.packet_size, \
81 maxTransferSize, \
82 request->endpoint.transfer_flags, \
83 request->endpoint.iso_start_frame_latency, \
84 transfer_buffer_mdl, \
85 transfer_buffer_length); \
86 else \
87 /* normal transfer */ \
88 return transfer(dev, irp, \
89 usbdDirection, \
90 urbFunction, \
91 pipe_info, \
92 request->endpoint.packet_size, \
93 request->endpoint.transfer_flags, \
94 request->endpoint.iso_start_frame_latency, \
95 transfer_buffer_mdl, \
96 transfer_buffer_length);
97
dispatch_ioctl(libusb_device_t * dev,IRP * irp)98 NTSTATUS dispatch_ioctl(libusb_device_t *dev, IRP *irp)
99 {
100 int maxTransferSize;
101 int ret = 0;
102 NTSTATUS status = STATUS_SUCCESS;
103
104 IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
105
106 ULONG control_code = stack_location->Parameters.DeviceIoControl.IoControlCode;
107
108 ULONG input_buffer_length = stack_location->Parameters.DeviceIoControl.InputBufferLength;
109 ULONG output_buffer_length = stack_location->Parameters.DeviceIoControl.OutputBufferLength;
110 ULONG transfer_buffer_length = stack_location->Parameters.DeviceIoControl.OutputBufferLength;
111
112 libusb_request *request = (libusb_request *)irp->AssociatedIrp.SystemBuffer;
113 char *output_buffer = (char *)irp->AssociatedIrp.SystemBuffer;
114 char *input_buffer = (char *)irp->AssociatedIrp.SystemBuffer;
115 MDL *transfer_buffer_mdl = irp->MdlAddress;
116 libusb_endpoint_t* pipe_info = NULL;
117 const char* dispCtlCode = NULL;
118 int urbFunction = -1;
119 int usbdDirection = -1;
120
121 status = remove_lock_acquire(dev);
122
123 if (!NT_SUCCESS(status))
124 {
125 status = complete_irp(irp, status, 0);
126 remove_lock_release(dev);
127 return status;
128 }
129
130 ///////////////////////////////////
131 // DIRECT control codes //
132 ///////////////////////////////////
133 switch(control_code)
134 {
135 case LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ:
136
137 dispCtlCode = "INTERRUPT_OR_BULK_READ";
138
139 // check if the request and buffer is valid
140 if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
141 {
142 USBERR("%s: invalid transfer request\n",
143 dispCtlCode);
144 status = STATUS_INVALID_PARAMETER;
145 goto IOCTL_Done;
146 }
147
148 // check if the pipe exists and get the pipe information
149 TRANSFER_IOCTL_GET_PIPEINFO();
150
151 // must be a bulk or interrupt pipe
152 if (!IS_BULK_PIPE(pipe_info) && !IS_INTR_PIPE(pipe_info))
153 {
154 goto IoctlIsochronousRead;
155 /*
156 USBERR("%s: incorrect pipe type: %02Xh\n",
157 dispCtlCode, pipe_info->pipe_type);
158 status = STATUS_INVALID_PARAMETER;
159 goto IOCTL_Done;
160 */
161 }
162
163 // read buffer length must be equal to or an interval of the max packet size
164 TRANSFER_IOCTL_CHECK_READ_BUFFER();
165
166 urbFunction = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
167 usbdDirection = USBD_TRANSFER_DIRECTION_IN;
168 maxTransferSize = GetMaxTransferSize(pipe_info, request->endpoint.max_transfer_size);
169
170 // ensure that the urb function and direction we set matches the
171 // pipe information
172 //
173 TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
174
175 // calls the transfer function and returns NTSTATUS
176 TRANSFER_IOCTL_EXECUTE();
177
178 case LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE:
179
180 dispCtlCode = "INTERRUPT_OR_BULK_WRITE";
181
182 /* we don't check 'transfer_buffer_mdl' here because it might be NULL */
183 /* if the DLL requests to send a zero-length packet */
184 if (!request || input_buffer_length < sizeof(libusb_request))
185 {
186 USBERR("%s: invalid transfer request\n", dispCtlCode);
187 status = STATUS_INVALID_PARAMETER;
188 goto IOCTL_Done;
189 }
190
191 // check if the pipe exists and get the pipe information
192 TRANSFER_IOCTL_GET_PIPEINFO();
193
194 // must be a bulk or interrupt pipe
195 if (!IS_BULK_PIPE(pipe_info) && !IS_INTR_PIPE(pipe_info))
196 {
197 goto IoctlIsochronousWrite;
198 /*
199 USBERR("%s: incorrect pipe type: %02Xh\n",
200 dispCtlCode, pipe_info->pipe_type);
201 status = STATUS_INVALID_PARAMETER;
202 goto IOCTL_Done;
203 */
204 }
205
206 urbFunction = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
207 usbdDirection = USBD_TRANSFER_DIRECTION_OUT;
208 maxTransferSize = GetMaxTransferSize(pipe_info, request->endpoint.max_transfer_size);
209
210 // ensure that the urb function and direction we set matches the
211 // pipe information
212 //
213 //TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
214
215 // calls the transfer function and returns NTSTATUS
216 TRANSFER_IOCTL_EXECUTE();
217
218 case LIBUSB_IOCTL_ISOCHRONOUS_READ:
219
220 dispCtlCode = "ISOCHRONOUS_READ";
221
222 // check if the request and buffer is valid
223 if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
224 {
225 USBERR("%s: invalid transfer request\n", dispCtlCode);
226 status = STATUS_INVALID_PARAMETER;
227 goto IOCTL_Done;
228 }
229
230 // check if the pipe exists and get the pipe information
231 TRANSFER_IOCTL_GET_PIPEINFO();
232
233 IoctlIsochronousRead:
234 dispCtlCode = "ISOCHRONOUS_READ";
235 // must be an isochronous endpoint
236 if (!IS_ISOC_PIPE(pipe_info))
237 {
238 USBERR("%s: incorrect pipe type: %02Xh\n",
239 dispCtlCode, pipe_info->pipe_type);
240 status = STATUS_INVALID_PARAMETER;
241 goto IOCTL_Done;
242 }
243
244 // read buffer length must be equal to or an interval of the max packet size
245 TRANSFER_IOCTL_CHECK_READ_BUFFER();
246
247 urbFunction = URB_FUNCTION_ISOCH_TRANSFER;
248 usbdDirection = USBD_TRANSFER_DIRECTION_IN;
249
250 // Do not use large transfers/splitting for ISO.
251 maxTransferSize = 0x7fffffff;
252
253 // ensure that the urb function and direction we set matches the
254 // pipe information
255 //
256 TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
257
258 // calls the transfer function and returns NTSTATUS
259 TRANSFER_IOCTL_EXECUTE();
260
261 case LIBUSB_IOCTL_ISOCHRONOUS_WRITE:
262
263 dispCtlCode = "ISOCHRONOUS_WRITE";
264
265 // check if the request and buffer is valid
266 if (!transfer_buffer_mdl || !request || input_buffer_length < sizeof(libusb_request))
267 {
268 USBERR("%s: invalid transfer request\n", dispCtlCode);
269 status = STATUS_INVALID_PARAMETER;
270 goto IOCTL_Done;
271 }
272
273 // check if the pipe exists and get the pipe information
274 TRANSFER_IOCTL_GET_PIPEINFO();
275
276 IoctlIsochronousWrite:
277 dispCtlCode = "ISOCHRONOUS_WRITE";
278 // must be an isochronous endpoint
279 if (!IS_ISOC_PIPE(pipe_info))
280 {
281 USBERR("%s: incorrect pipe type: %02Xh\n",
282 dispCtlCode, pipe_info->pipe_type);
283 status = STATUS_INVALID_PARAMETER;
284 goto IOCTL_Done;
285 }
286
287 urbFunction = URB_FUNCTION_ISOCH_TRANSFER;
288 usbdDirection = USBD_TRANSFER_DIRECTION_OUT;
289 TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
290
291 // Do not use large transfers/splitting for ISO.
292 maxTransferSize = 0x7fffffff;
293
294 // ensure that the urb function and direction we set matches the
295 // pipe information
296 //
297 TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
298
299 TRANSFER_IOCTL_EXECUTE();
300 }
301
302 ///////////////////////////////////
303 // METHOD_BUFFERED control codes //
304 ///////////////////////////////////
305 if (!request || input_buffer_length < sizeof(libusb_request)
306 || input_buffer_length > LIBUSB_MAX_READ_WRITE
307 || output_buffer_length > LIBUSB_MAX_READ_WRITE
308 || transfer_buffer_length > LIBUSB_MAX_READ_WRITE)
309 {
310 USBERR0("invalid input or output buffer\n");
311
312 status = complete_irp(irp, STATUS_INVALID_PARAMETER, 0);
313 remove_lock_release(dev);
314 return status;
315 }
316
317 switch(control_code)
318 {
319 case LIBUSB_IOCTL_SET_CONFIGURATION:
320
321 status = set_configuration(dev,
322 request->configuration.configuration,
323 request->timeout);
324 break;
325
326 case LIBUSB_IOCTL_GET_CACHED_CONFIGURATION:
327 case LIBUSB_IOCTL_GET_CONFIGURATION:
328
329 if (!output_buffer || output_buffer_length < 1)
330 {
331 USBERR0("get_configuration: invalid output buffer\n");
332 status = STATUS_INVALID_PARAMETER;
333 break;
334 }
335 if (control_code == LIBUSB_IOCTL_GET_CACHED_CONFIGURATION)
336 {
337 ret = 0;
338 if (dev->config.value >= 0)
339 {
340 *output_buffer = (char)dev->config.value;
341 ret = 1;
342 }
343 status = STATUS_SUCCESS;
344 }
345 else
346 {
347 status = get_configuration(dev, output_buffer, &ret, request->timeout);
348 }
349 break;
350
351 case LIBUSB_IOCTL_SET_INTERFACE:
352
353 status = set_interface(
354 dev,
355 request->intf.interface_number,
356 request->intf.altsetting_number,
357 request->timeout);
358
359 break;
360
361 case LIBUSB_IOCTL_GET_INTERFACE:
362
363 if (!output_buffer || output_buffer_length < 1)
364 {
365 USBERR0("get_interface: invalid output buffer\n");
366 status = STATUS_INVALID_PARAMETER;
367 break;
368 }
369
370 status = get_interface(
371 dev,
372 request->intf.interface_number,
373 output_buffer,
374 request->timeout);
375
376 if (NT_SUCCESS(status))
377 ret = 1;
378
379 break;
380
381 case LIBUSB_IOCTL_SET_FEATURE:
382
383 status = set_feature(dev, request->feature.recipient,
384 request->feature.index, request->feature.feature,
385 request->timeout);
386
387 break;
388
389 case LIBUSB_IOCTL_CLEAR_FEATURE:
390
391 status = clear_feature(dev, request->feature.recipient,
392 request->feature.index, request->feature.feature,
393 request->timeout);
394
395 break;
396
397 case LIBUSB_IOCTL_GET_STATUS:
398
399 if (!output_buffer || output_buffer_length < 2)
400 {
401 USBERR0("get_status: invalid output buffer\n");
402 status = STATUS_INVALID_PARAMETER;
403 break;
404 }
405
406 status = get_status(dev, request->status.recipient,
407 request->status.index, output_buffer,
408 &ret, request->timeout);
409
410 break;
411
412 case LIBUSB_IOCTL_SET_DESCRIPTOR:
413
414 if (input_buffer_length <= sizeof(libusb_request))
415 {
416 USBERR0("set_descriptor: invalid input buffer\n");
417 status = STATUS_INVALID_PARAMETER;
418 break;
419 }
420
421 status = set_descriptor(dev,
422 input_buffer + sizeof(libusb_request),
423 input_buffer_length - sizeof(libusb_request),
424 request->descriptor.type,
425 request->descriptor.recipient,
426 request->descriptor.index,
427 request->descriptor.language_id,
428 &ret, request->timeout);
429
430 break;
431
432 case LIBUSB_IOCTL_GET_DESCRIPTOR:
433
434 if (!output_buffer || !output_buffer_length)
435 {
436 USBERR0("get_descriptor: invalid output buffer\n");
437 status = STATUS_INVALID_PARAMETER;
438 break;
439 }
440
441 status = get_descriptor(dev, output_buffer,
442 output_buffer_length,
443 request->descriptor.type,
444 request->descriptor.recipient,
445 request->descriptor.index,
446 request->descriptor.language_id,
447 &ret, request->timeout);
448
449 break;
450
451 case LIBUSB_IOCTL_VENDOR_READ:
452
453 if (output_buffer_length && !output_buffer)
454 {
455 USBERR0("vendor_read: invalid output buffer\n");
456 status = STATUS_INVALID_PARAMETER;
457 break;
458 }
459
460 status = vendor_class_request(dev,
461 request->vendor.type,
462 request->vendor.recipient,
463 request->vendor.request,
464 request->vendor.value,
465 request->vendor.index,
466 output_buffer,
467 output_buffer_length,
468 USBD_TRANSFER_DIRECTION_IN,
469 &ret, request->timeout);
470 break;
471
472 case LIBUSB_IOCTL_VENDOR_WRITE:
473
474 status =
475 vendor_class_request(dev,
476 request->vendor.type,
477 request->vendor.recipient,
478 request->vendor.request,
479 request->vendor.value,
480 request->vendor.index,
481 input_buffer_length == sizeof(libusb_request) ?
482 NULL : input_buffer + sizeof(libusb_request),
483 input_buffer_length - sizeof(libusb_request),
484 USBD_TRANSFER_DIRECTION_OUT,
485 &ret, request->timeout);
486 break;
487
488 case LIBUSB_IOCTL_RESET_ENDPOINT:
489
490 status = reset_endpoint(dev, request->endpoint.endpoint,
491 request->timeout);
492 break;
493
494 case LIBUSB_IOCTL_ABORT_ENDPOINT:
495
496 status = abort_endpoint(dev, request->endpoint.endpoint,
497 request->timeout);
498 break;
499
500 case LIBUSB_IOCTL_RESET_DEVICE:
501
502 status = reset_device(dev, request->timeout);
503 break;
504
505 case LIBUSB_IOCTL_RESET_DEVICE_EX:
506
507 status = reset_device_ex(dev, request->timeout, request->reset_ex.reset_type);
508 break;
509
510 case LIBUSB_IOCTL_SET_DEBUG_LEVEL:
511 usb_log_set_level(request->debug.level);
512 break;
513
514 case LIBUSB_IOCTL_GET_VERSION:
515
516 if (!request || output_buffer_length < sizeof(libusb_request))
517 {
518 USBERR0("get_version: invalid output buffer\n");
519 status = STATUS_INVALID_PARAMETER;
520 break;
521 }
522
523 request->version.major = VERSION_MAJOR;
524 request->version.minor = VERSION_MINOR;
525 request->version.micro = VERSION_MICRO;
526 request->version.nano = VERSION_NANO;
527 request->version.mod_value = 1;
528
529 ret = sizeof(libusb_request);
530 break;
531
532 case LIBUSB_IOCTL_CLAIM_INTERFACE:
533 status = claim_interface(dev, stack_location->FileObject,
534 request->intf.interface_number);
535 break;
536
537 case LIBUSB_IOCTL_RELEASE_INTERFACE:
538 status = release_interface(dev, stack_location->FileObject,
539 request->intf.interface_number);
540 break;
541
542 case LIBUSB_IOCTL_GET_DEVICE_PROPERTY:
543 if (!request || output_buffer_length < sizeof(libusb_request))
544 {
545 USBERR0("get_device_property: invalid output buffer\n");
546 status = STATUS_INVALID_PARAMETER;
547 break;
548 }
549 status = reg_get_device_property(
550 dev->physical_device_object,
551 request->device_property.property,
552 output_buffer,
553 output_buffer_length, &ret);
554 break;
555
556 case LIBUSB_IOCTL_GET_CUSTOM_REG_PROPERTY:
557 if (!input_buffer || (input_buffer_length < sizeof(libusb_request)))
558 {
559 USBERR0("get_custom_reg_property: invalid buffer\n");
560 status = STATUS_INVALID_PARAMETER;
561 break;
562 }
563 status=reg_get_custom_property(
564 dev->physical_device_object,
565 input_buffer,
566 output_buffer_length,
567 request->device_registry_key.name_offset,
568 &ret);
569 break;
570
571 case LIBUSB_IOCTL_GET_OBJECT_NAME:
572 if (!request || output_buffer_length < 2)
573 {
574 USBERR0("get_object_name: invalid output buffer\n");
575 status = STATUS_INVALID_PARAMETER;
576 break;
577 }
578 switch (request->objname.objname_index)
579 {
580 case 0:
581 ret = (int)strlen(dev->objname_plugplay_registry_key)+1;
582 ret = ret > (int)output_buffer_length ? (int)output_buffer_length : ret;
583 RtlCopyMemory(output_buffer, dev->objname_plugplay_registry_key,(SIZE_T) (ret-1));
584 output_buffer[ret-1]='\0';
585 break;
586 default:
587 status = STATUS_INVALID_PARAMETER;
588 }
589 break;
590
591 case LIBUSB_IOCTL_QUERY_DEVICE_INFORMATION: // METHOD_BUFFERED (QUERY_DEVICE_INFORMATION)
592 status = STATUS_NOT_IMPLEMENTED;
593 break;
594
595 case LIBUSB_IOCTL_SET_PIPE_POLICY: // METHOD_BUFFERED (SET_PIPE_POLICY)
596 if (!request || !input_buffer || (input_buffer_length <= sizeof(libusb_request)))
597 {
598 USBERR0("set_pipe_policy: invalid output buffer\n");
599 status = STATUS_BUFFER_TOO_SMALL;
600 break;
601 }
602 input_buffer+=sizeof(libusb_request);
603 input_buffer_length-=sizeof(libusb_request);
604 if (request->pipe_policy.policy_type==PIPE_TRANSFER_TIMEOUT)
605 {
606 if (input_buffer_length < sizeof(ULONG))
607 {
608 USBERR0("set_pipe_policy:pipe_transfer_timeout: invalid input buffer\n");
609 status = STATUS_BUFFER_TOO_SMALL;
610 break;
611 }
612 if (request->pipe_policy.pipe_id & USB_ENDPOINT_ADDRESS_MASK)
613 {
614 status = STATUS_NOT_IMPLEMENTED;
615 break;
616 }
617
618 if (request->pipe_policy.pipe_id & USB_ENDPOINT_DIR_MASK)
619 dev->control_read_timeout=*((PULONG)input_buffer);
620 else
621 dev->control_write_timeout=*((PULONG)input_buffer);
622
623 status = STATUS_SUCCESS;
624 break;
625 }
626
627 break;
628
629 case LIBUSB_IOCTL_GET_PIPE_POLICY: // METHOD_BUFFERED (GET_PIPE_POLICY)
630 if (!request || input_buffer_length < sizeof(libusb_request) || !output_buffer || (output_buffer_length < 1))
631 {
632 USBERR0("get_pipe_policy: invalid output buffer\n");
633 status = STATUS_BUFFER_TOO_SMALL;
634 break;
635 }
636 if (request->pipe_policy.policy_type==PIPE_TRANSFER_TIMEOUT)
637 {
638 if (output_buffer_length < sizeof(ULONG))
639 {
640 USBERR0("get_pipe_policy:pipe_transfer_timeout: invalid output buffer\n");
641 status = STATUS_BUFFER_TOO_SMALL;
642 break;
643 }
644 if (request->pipe_policy.pipe_id & USB_ENDPOINT_ADDRESS_MASK)
645 {
646 status = STATUS_NOT_IMPLEMENTED;
647 break;
648 }
649 if (request->pipe_policy.pipe_id & USB_ENDPOINT_DIR_MASK)
650 *((PULONG)output_buffer) = dev->control_read_timeout;
651 else
652 *((PULONG)output_buffer) = dev->control_write_timeout;
653
654 status = STATUS_SUCCESS;
655 break;
656 }
657 break;
658
659 case LIBUSB_IOCTL_SET_POWER_POLICY: // METHOD_BUFFERED (SET_POWER_POLICY)
660 status = STATUS_NOT_IMPLEMENTED;
661 break;
662
663 case LIBUSB_IOCTL_GET_POWER_POLICY: // METHOD_BUFFERED (GET_POWER_POLICY)
664 status = STATUS_NOT_IMPLEMENTED;
665 break;
666
667 case LIBUSB_IOCTL_CONTROL_WRITE: // METHOD_IN_DIRECT (CONTROL_WRITE)
668 // check if the request and buffer is valid
669 if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
670 {
671 USBERR("%s: invalid transfer request\n", dispCtlCode);
672 status = STATUS_INVALID_PARAMETER;
673 goto IOCTL_Done;
674 }
675
676 status = control_transfer(
677 dev,
678 irp,
679 transfer_buffer_mdl,
680 transfer_buffer_length,
681 USBD_TRANSFER_DIRECTION_OUT,
682 &ret,
683 dev->control_write_timeout,
684 request->control.RequestType,
685 request->control.Request,
686 request->control.Value,
687 request->control.Index,
688 request->control.Length);
689
690 break;
691
692 case LIBUSB_IOCTL_CONTROL_READ: // METHOD_OUT_DIRECT (CONTROL_READ)
693 // check if the request and buffer is valid
694 if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
695 {
696 USBERR("%s: invalid transfer request\n", dispCtlCode);
697 status = STATUS_INVALID_PARAMETER;
698 goto IOCTL_Done;
699 }
700
701 status = control_transfer(
702 dev,
703 irp,
704 transfer_buffer_mdl,
705 transfer_buffer_length,
706 USBD_TRANSFER_DIRECTION_IN,
707 &ret,
708 dev->control_read_timeout,
709 request->control.RequestType,
710 request->control.Request,
711 request->control.Value,
712 request->control.Index,
713 request->control.Length);
714
715 break;
716
717 case LIBUSB_IOCTL_FLUSH_PIPE: // METHOD_BUFFERED (FLUSH_PIPE)
718
719 status = STATUS_SUCCESS;
720 break;
721
722
723 case LIBUSBK_IOCTL_CLAIM_INTERFACE: // METHOD_BUFFERED (CLAIM_INTERFACE)
724 if (!request || output_buffer_length < sizeof(libusb_request))
725 {
726 USBERR0("claim_interfaceK: invalid output buffer\n");
727 status = STATUS_BUFFER_TOO_SMALL;
728 break;
729 }
730
731 status = claim_interface_ex(dev, stack_location->FileObject, &request->intf);
732 if (NT_SUCCESS(status))
733 {
734 ret = sizeof(libusb_request);
735 }
736 break;
737
738 case LIBUSBK_IOCTL_RELEASE_INTERFACE: // METHOD_BUFFERED (RELEASE_INTERFACE)
739
740 if (!request || output_buffer_length < sizeof(libusb_request))
741 {
742 USBERR0("release_interfaceK: invalid output buffer\n");
743 status = STATUS_BUFFER_TOO_SMALL;
744 break;
745 }
746
747 status = release_interface_ex(dev, stack_location->FileObject, &request->intf);
748 if (NT_SUCCESS(status))
749 {
750 ret = sizeof(libusb_request);
751 }
752 break;
753
754 case LIBUSBK_IOCTL_SET_INTERFACE: // METHOD_BUFFERED (SET_INTERFACE)
755
756 if (!request || output_buffer_length < sizeof(libusb_request))
757 {
758 USBERR0("set_interfaceK: invalid output buffer\n");
759 status = STATUS_BUFFER_TOO_SMALL;
760 break;
761 }
762
763 status = set_interface_ex(dev, &request->intf, request->timeout);
764 if (NT_SUCCESS(status))
765 {
766 ret = sizeof(libusb_request);
767 }
768 break;
769
770 case LIBUSBK_IOCTL_GET_INTERFACE: // METHOD_BUFFERED (GET_INTERFACE)
771
772 if (!request || output_buffer_length < sizeof(libusb_request))
773 {
774 USBERR0("get_interfaceK: invalid output buffer\n");
775 status = STATUS_BUFFER_TOO_SMALL;
776 break;
777 }
778
779 status = get_interface_ex(dev, &request->intf, request->timeout);
780 if (NT_SUCCESS(status))
781 {
782 ret = sizeof(libusb_request);
783 }
784 break;
785
786 default:
787 status = STATUS_INVALID_PARAMETER;
788 }
789
790 IOCTL_Done:
791 status = complete_irp(irp, status, ret);
792 remove_lock_release(dev);
793
794 return status;
795 }
796