daynix / UsbDk

Usb Drivers Development Kit for Windows
Apache License 2.0
535 stars 142 forks source link

ReadPipe example #48

Closed nikola-matic closed 7 years ago

nikola-matic commented 7 years ago

I'm trying to read data from a 3D mouse after acquiring (redirecting) the device. The device redirection is successful and disables the device, until I release it back. However, when attempting to read data, I get INVALID_HANDLE (0x6) error from GetLastError(). I've been looking through the libusb source code for example reads - however, I'm not sure I'm configuring the packets correctly. It would seem there are no read/write examples in UsbDk (controller).

This is my device endpoint descriptor: bEndpointAddress: 0x81 IN Transfer Type: Interrupt wMaxPacketSize: 0x0008 (8) bInterval: 0x0A

And this is my code:

void Device::ReadPipe()
{
    PUSB_DK_TRANSFER_REQUEST transferRequest = (PUSB_DK_TRANSFER_REQUEST)malloc(sizeof(tag_USB_DK_TRANSFER_REQUEST));
    LPOVERLAPPED overlapped = (LPOVERLAPPED)malloc(sizeof(_OVERLAPPED));
    DWORD error;

    transferRequest->TransferType = InterruptTransferType;
    transferRequest->EndpointAddress = 0x81;
    transferRequest->Buffer = (PVOID64)malloc(8);
    transferRequest->BufferLength = 0x08;
    transferRequest->IsochronousPacketsArraySize = NULL;
    transferRequest->IsochronousPacketsArraySize = 0;

    TransferResult result = Device::api.ReadPipe()(deviceHandle_, transferRequest, overlapped);

    switch (result)
    {
    case TransferSuccess:
        std::cout << "success" << std::endl;
        break;
    case TransferSuccessAsync:
        std::cout << "success async" << std::endl;
        break;
    case TransferFailure:
        error = GetLastError();
        std::cout << "failure with error code: " << error << std::endl;
        break;
    default:
        std::cout << "no result" << std::endl;
    }

    free(transferRequest->Buffer);
    free(transferRequest);
    free(overlapped);
}

I have to mention that I'm very new to such low level device interaction, so it may be that I'm doing something stupid, but I've been attempting to read from the device for a couple of days now without success. I'd be happy to do a pull request and write some examples - perhaps by extending the UsbDkController class. Thanks.

Edit: Note that I haven't sent a control transfer, which I'm guessing I should have?

sameehj commented 7 years ago

Hi @nikola-matic,

From what I understand you are using the function "UsbDk_ReadPipe" and getting "INVALID_HANDLE (0x6)", I think it may be an issue with the devicehandle that you are providing for the function, are you sure it is valid?

In order to debug the issue please run DebugView and reproduce the issue, an error should show up there. Just open DebugView without any additional settings, reproduce the issue and post the error here so I can help you further investigate the issue. You can download DebugView from Microsoft here: https://docs.microsoft.com/en-us/sysinternals/downloads/debugview.

I'd be happy to do a pull request and write some examples - perhaps by extending the UsbDkController class. Thanks.

That would be great, please send a pull request once it is ready.

nikola-matic commented 7 years ago

Hi @sameehj,

Yes, I'm using UsbDk_ReadPipe. I'm passing it the handle I get from UsbDk_StartRedirect. Now, the redirect function works with a hitch - it disables the device on the host machine, and enables it again once UsbDk_StopRedirect is called (similar to the UsbDkController example). I'm also check the handle to make sure it's not a null pointer or INVALID_HANDLE_VALUE.

I'll run it through debugview and get to you tomorrow. Thanks for the quick reply.

sameehj commented 7 years ago

I'll run it through debugview and get to you tomorrow. Thanks for the quick reply.

No problem, I'd like to further clarify that there are two tracing options for UsbDk, the one that I explained above which collects traces from User Mode components of UsbDk and there is the complete traces logs which collects traces from the UsbDk driver too. Both of these are explained in great detail here: https://github.com/daynix/UsbDk/blob/master/Documentation/Tracing.txt.

I suggest starting with the first approach and see if the logs are sufficient and can help us resolve the issue. Keep me updated =)

nikola-matic commented 7 years ago

Just ran it through debugview, and unfortunately there is nothing of particular use. It just outputs this line: Driver file operation error. DeviceIoControl failed (The handle is invalid. Error code = 6) and that's it. I'll debug the driver tomorrow and report as soon as I have any new info.

nikola-matic commented 7 years ago

@sameehj,

This is the log I got (UsbDkLogman.bat && tracefmt.exe) - usbdk.txt. The log should contain device redirection and attempted read - however, I'm not seeing anything of particular use in the logs. Perhaps you'll see something that I'm missing. Thanks.

sameehj commented 7 years ago

@nikola-matic,

The log that you provided seems like a successful run, what I suspect is that you have a bug lying somewhere in your code where you mess the device handle somehow. In order to debug this I suggest that you print the value of the device handle just after you receive it from StartRedirect function and print it's value once again just before providing it to the ReadPipe function.

In case this doesn't help you solve the issue, please post the whole code somewhere (maybe github) and I'll take a look.

nikola-matic commented 7 years ago

@sameehj,

Good news. It turns out I was allocating LPOVERLAPPED without actually assigning any values to it (even though I wanted a synchronous read). Once I set it to NULL, it started working. However, now I'm getting the same value every time I make read, no matter in which direction I move the 3D mouse. My understanding is that I should get different values depending on the direction of movement (to indicate said direction).

I'm checking the result by parsing the USB_DK_TRANSFER_REQUEST's Result field, which is of USB_DK_TRANSFER_RESULT type, which has USB_DK_GEN_TRANSFER_RESULT GenResult field in it, which in turn has a ULONG64 BytesTransferred field in it. Is the BytesTransferred field a counter indicating the number of transferred bytes, or the actual transferred bytes read from the endpoint buffer?

sameehj commented 7 years ago

Good news. It turns out I was allocating LPOVERLAPPED without actually assigning any values to it (even though I wanted a synchronous read). Once I set it to NULL, it started working. However, now I'm getting the same value every time I make read, no matter in which direction I move the 3D mouse. My understanding is that I should get different values depending on the direction of movement (to indicate said direction).

Great! regarding the values, did you set the interface using "UsbDk_SetAltsetting" API function after Starting redirection and prior to executing ReadPipe? If not, this could be the reason you are getting this behaviour.

The length field contains the number of bytes that were sent. You can see that in the UsbDk driver code the structure "PWDF_REQUEST_COMPLETION_PARAMS" is used to fill the GenResult. In WritePipe scenario the CUsbDkRedirectorStrategy::WritePipe function is executed and the value of GenResult is filled in the function CompleteTransferRequest using the "Parameters.PipeWrite.Length" and "UsbdStatus" fields of usbCompletionParams.

You can read about these fields here: https://msdn.microsoft.com/en-us/library/windows/hardware/ff553049(v=vs.85).aspx

nikola-matic commented 7 years ago

@sameehj, I did not in fact set the interface using UsbDk_Setaltsetting. What values should InterfaceIdx and AltSettingIdx be? For instance, my interface (only have one) looks like this:

Interface Descriptor:
bInterfaceNumber:     0x00
bAlternateSetting:    0x00
bNumEndpoints:        0x02
bInterfaceClass:      0x03 (HID)
bInterfaceSubClass:   0x00
bInterfaceProtocol:   0x00
iInterface:           0x00
sameehj commented 7 years ago

bInterfaceNumber: 0x00 bAlternateSetting: 0x00

So set InterfaceIdx and InterfaceIdx both to zero.

nikola-matic commented 7 years ago

@sameehj, that was the first thing I tried, unfortunately it didn't change anything. I'll fiddle around and try with another device tomorrow, and report my findings.

nikola-matic commented 7 years ago

@sameehj, the actual buffer result I was trying to read was in PUSB_DK_TRANSFER_REQUEST (Buffer) :)

By the way, it seems setting an alternative setting is not required in order to read data.

Also, the UsbDkHelper API does not have way to get infterface/endpoint descriptors directly - i.e. this would require doing a control read on endpoint zero, right?

sameehj commented 7 years ago

Also, the UsbDkHelper API does not have way to get infterface/endpoint descriptors directly - i.e. this would require doing a control read on endpoint zero, right?

You can use "UsbDk_GetConfigurationDescriptor" and "UsbDk_ReleaseConfigurationDescriptor" to accomplish that, you can find all UsbDk's API functions here: https://github.com/daynix/UsbDk/blob/master/UsbDkHelper/UsbDkHelper.h

nikola-matic commented 7 years ago

You can use "UsbDk_GetConfigurationDescriptor" and "UsbDk_ReleaseConfigurationDescriptor" to accomplish that

Are you sure? The function only returns PUSB_CONFIGURATION_DESCRIPTOR, and from what I can see, in UsbDkCompat.h, the only defined structs are for device and configuration descriptors, which makes sense, since the API only provides functions to get device and configuration descriptors, i.e. UsbDk_GetDevicesList and UsbDk_GetConfigurationDescriptor. In any case, this still provides enough information to get the rest of the descriptors 'manually', i.e. through control endpoint reads.

sameehj commented 7 years ago

Are you sure? The function only returns PUSB_CONFIGURATION_DESCRIPTOR, and from what I can see, in UsbDkCompat.h, the only defined structs are for device and configuration descriptors, which makes sense, since the API only provides functions to get device and configuration descriptors, i.e. UsbDk_GetDevicesList and UsbDk_GetConfigurationDescriptor.

True, I am sorry I apparently misread the question, there is no API functions which directly fetches the interface/endpoint descriptors.

nikola-matic commented 7 years ago

No worries. Thanks for all the help - I'll try to make a pull request in the next couple of months to extend the UsbDkController component (or make an entirely new one) to demonstrate ReadPipe/WritePipe usage.

sameehj commented 7 years ago

You're welcome =),

I suggest that you add a new standalone example project, it'll be much neater than bloating up the controller with superfluous functionality.

Thanks =)

nikola-matic commented 7 years ago

Sounds good!