On 12/07/12 19:31, Peter Stuge wrote:
> Hi Toby,
>
> As Pete likes to point out I have no authority in the libusbx
> project, so as far as libusbx is concerned I think the best
> might be if you could pretend that I had never posted this
> feedback on the libusbx list.

Thank you for spending time to provide your feedback. I've been lurking 
on the libusb-devel list from before libusbx branched so I'm familiar 
with the history of the two projects and how that relates to the 
individuals involved.

> I've attached a series of patches, split up into the backend and
> various changes to common code.
> I think you've split too much actually, but this is always easier to
> fix than the other way around, so no big problem.

Fair enough. I was going for bite-sized chunks for the common code 
changes with the intention that it would be easier to discuss individual 
changes.

>> This backend requires the Windows CE Standard 5.00 SDK.
> * Why? - I mean: What parts of the SDK are required?

I'm not quite sure what question you are asking here. The SDK provides 
OS header files and libraries for the code to be compiled against; 
without the SDK there wouldn't be any anything for the compiler and 
linker to compile the source code against.

I think I possibly should have expanded this statement considerably 
more. The information I was trying to convey was:

Currently the WinCE project files target the "STANDARDSDK_500" 
platforms. These are provided by the Windows CE Standard 5.00 SDK. You 
should be able to compile libusb for WinCE by installing the SDK at the 
provided link.

As far as I can tell WinCE 5 was the last WinCE release which had a 
standard SDK from Microsoft. If you want to compile for a more recent 
WinCE release then you will need to talk to the company providing the 
hardware or baseport for the SDK for your platform. Once you've got this 
SDK you'll need to add a new platform to the WinCE solution for your 
platform of interest.

As the WinCE libusbx port doesn't need any features which are only 
available in versions beyond 5.0 it seemed sensible to target 
STANDARDSDK_500 as it's a platform that anyone can build for by 
installing the standard SDK from Microsoft.

On a slight tangent: the CEUSBKWrapper driver currently only supports 
the memory model in Windows CE 6, but as the model in Windows CE 5 is 
simpler it shouldn't be too hard to change the UserBuffer class to 
support Windows CE 5 if someone wants to.

> * The SDK is from 2004. What C compiler can be used, and which
> capabilities does it have? I.e. corresponding to roughly which
> Windows Visual Studio version?

I've been using STANDARDSDK_500 with VS 2005, but running on a WinCE 6.0 
platform. I believe that the SDK comes with appropriate C compilers, 
although they are in C:\Program Files\Microsoft Visual Studio 
8\vc\ce\bin\x86_arm so it's hard to tell.

Do you have a particular alternative compiler that you want to build 
WinCE binaries on? I'd be happy to help you to work out how to get it 
building on that. Can you send a link to it?

Or were you just wondering about how to compile this?

>
>> Windows CE doesn't expose any user side USB APIs so we've also
>> developed a kernel driver. This kernel driver is released under
>> the LGPL and can be found on github at
>> https://github.com/RealVNC/CEUSBKWrapper
> Note that an LGPL kernel driver for the WinCE kernel may be
> problematic as far as licensing goes. But that's separate to
> the libusb backend, in any case.

Drivers in the WinCE kernel are dynamically loaded and linked, sitting 
around as (kernel) dlls inside \windows waiting to be loaded. My reading 
of the LGPL is that it is acceptable to dynamically link to non-LGPL 
code. This also seems to be compatible with the license for WinCE.

However if you do see a problem then can you say what you think it is? 
Is there an alternative license you can suggest that we could consider 
for CEUSBKWrapper? We obviously don't want to release code under an open 
source license which is incompatible with the licensing terms of the 
software it is intended to interact with.
>> The current limitations of this backend are:
>> * It only supports control and bulk transfers. The CEUSBKWrapper
>> driver doesn't (yet) support isochronous or interrupt transfers.
>> The kernel APIs do exist, so they just need to be exposed to user-side.
> What kind of effort does that require?

Implementing UkwIssueInterruptTransfer and UkwIssueIsochronousTransfer 
:). I imagine UkwIssueInterruptTransfer will have lots of common code 
with the bulk transfer. Currently an attempt to issue and interrupt 
transfer will go via the bulk transfer code, which might just work as 
expected, we've not tested this.

I have no idea about UkwIssueIsochronousTransfer as I've never done any 
USB development which has needed to use isochronous transfers directly.

>
>
> Try to change this in a good way where getenv() is called, instead.
> Is there an equivalent to environment variables in Windows CE? Maybe
> the registry? The question is in which key the value would be.
>
> If no, then you can always simply make autoconf check for getenv and
> put the code in libusb_init() within #ifdef HAVE_GETENV. Just don't
> forget to initialize the dbg stack variable if you go that route.

I've updated it to use a registry setting, see my other post.

>> Subject: [PATCH 1/6] WinCE: Add backend and build files for Windows CE
>>   backend.
>>
>> This backend requires the CEUSBKWrapper driver to be installed
>> on the WinCE device. Without this no devices will be listed.
> How about making libusb_init() return an error instead? Is any part
> of the libusb API useful without the ukw driver?

I can't think of any use for the libusb API if you don't have the ukw 
driver. Is failing if no driver is available the behavior of all the 
other backends?

>
>
>> ---
>>   libusb/os/poll_wince.c             |  656 +++++++++++++++++++
>>   libusb/os/poll_wince.h             |  117 ++++
>>   libusb/os/wince_usb.c              | 1222 
>> +++++++++++++++++++++++++++++++++++
>>   libusb/os/wince_usb.h              |  156 +++++
> How about refactoring the existing Windows code so that everything
> that is common between the two systems will exist only in a single
> place? There seems to be an awful lot of code duplication between
> them.

When I started the WinCE port I wasn't sure how close it would be to the 
Windows backend so I just copied and pasted so that I could hack away at 
the code as I pleased. I was also thinking that it would be more likely 
to be accepted as an experimental feature if the majority of code 
changes were outside common code.

I can appreciate that a maintainer taking the approach of "make it 
perfect first time" is an valid viewpoint. However my personality is 
more that I would prefer to not have the risk of changing all the code 
of a pre-existing feature to add a new, unproven, feature.

I would view that as something to be done later once it's been shown to 
be working and stable. That might just be because I don't trust myself 
to write code which works first time :)

>
> If you consider that infeasible then please sell that a; write
> about why, and write about what is different between the normal
> windows backend and the wince one.

One is two years old, one is only a few months old. As a user of libusbx 
on Windows I'd be hesitant about upgrading to a new release where I knew 
that the previously working Windows backend had been ripped apart and 
put back together with the backend from another OS by a couple of 
developers who were new to the libusb code structure.

>>   wince/config.h                     |   21 +
>>   wince/errno.h                      |   12 +
>>   wince/inttypes.h                   |  295 +++++++++
>>   wince/libusb-1.0/libusb-1.0.vcproj | 1229 
>> ++++++++++++++++++++++++++++++++++++
>>   wince/libusb.sln                   |  114 ++++
> Why not libusb-1.0.sln ?

I started work on this WinCE backend before libusbx was forked. At the 
time the desktop windows build had a single solution file called 
libusb.sln.

Why are the currently solution files for libusb on windows not called 
libusb-1.0_2005.sln and libusb-1.0_2010.sln?

>
>>   wince/signal.h                     |    1 +
>>   wince/stdint.h                     |  256 ++++++++
>>   wince/sys/types.h                  |    1 +
>>   wince/winresrc.h                   |    1 +
> Are the above simply duplicated? Please strive for heavy code reuse.

The empty header files are, again, to simplify the changes to common 
code. I felt it would make reviewing the changes to common code harder 
than necessary if the majority of changes was just putting #ifndef 
OS_WINCE blocks around various header file includes.

But thinking about it some more I can just do this change in a separate 
git commit. I'll update my branch appropriately.

>
>
>> +++ b/libusb/os/wince_usb.c
> ..
>> +static int wince_open(struct libusb_device_handle *handle)
>> +{
>> +    // Nothing to do to open devices as a handle to it has
>> +    // been retrieved by wince_get_device_list
>> +    return LIBUSB_SUCCESS;
>> +}
> What happens in the kernel driver during _get_device_list?

It returns a list of handles to the devices it knows about.

> That should be a rather easy operation, and _open should be
> what establishes communications with the device. It's completely
> possible that open will indeed be a no-op, but please confirm.

What communication with the device should _open be performing? My 
reading of the documentation for open inside the backend structure is 
that is shouldn't communicate with the device:

     * This function should not generate any bus I/O and should not block.


>> +static void wince_close(struct libusb_device_handle *handle)
>> +{
>> +    // Nothing to do as wince_open does nothing.
>> +}
> Can multiple applications perform control transfers to the same
> device simultaneously?

I believe so. We've certainly tested it with different libusb contexts 
within the same process.

> What happens in the kernel driver?

It will issue multiple control transfer requests. The USB driver inside 
WinCE then queues up these transfer requests, completing each one 
asynchronously when it completes.

> What happens when two devices try to claim the same device interface?

Assuming you mean two processes trying to claim the same device 
interface; then they are both currently allowed to. If another WinCE 
driver has claimed the interface, such as the mass storage driver, then 
no libusb processes will be able to claim the interface.

>
>
>> +static int wince_submit_control_transfer(struct usbi_transfer *itransfer)
>> +{
>> +    struct libusb_transfer *transfer = 
>> USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
>> +    struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
>> +    struct wince_transfer_priv *transfer_priv = (struct 
>> wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
>> +    struct wince_device_priv *priv = 
>> _device_priv(transfer->dev_handle->dev);
>> +    BOOL direction_in, ret;
>> +    struct winfd wfd;
>> +    DWORD flags;
>> +    HANDLE eventHandle;
>> +    
>> +    // Split out control setup header and data buffer
>> +    PUKW_CONTROL_HEADER setup = (PUKW_CONTROL_HEADER) transfer->buffer;
>> +    DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
>> +    PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];
>> +
>> +    transfer_priv->pollable_fd = INVALID_WINFD;
>> +    direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
>> +    flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
>> +    flags |= UKW_TF_SHORT_TRANSFER_OK;
>> +
>> +    eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
>> +    if (eventHandle == NULL) {
>> +            usbi_err(ctx, "Failed to create event for async transfer");
>> +            return LIBUSB_ERROR_NO_MEM;
>> +    }
>> +
>> +    wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, 
>> itransfer, &wince_cancel_transfer);
>> +    if (wfd.fd < 0) {
>> +            CloseHandle(eventHandle);
>> +            return LIBUSB_ERROR_NO_MEM;
>> +    }
>> +
>> +    transfer_priv->pollable_fd = wfd;
>> +    ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, 
>> &transfer->actual_length, wfd.overlapped);
>> +    if (!ret) {
>> +            int libusbErr = translate_driver_error(GetLastError());
>> +            usbi_err(ctx, "UkwIssueControlTransfer failed: error %d", 
>> GetLastError());
>> +            wince_clear_transfer_priv(itransfer);
>> +            return libusbErr;
>> +    }
>> +    usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? 
>> POLLIN : POLLOUT);
>> +    itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
>> +
>> +    return LIBUSB_SUCCESS;
>> +}
>> +
>> +static int wince_submit_bulk_transfer(struct usbi_transfer *itransfer)
>> +{
>> +    struct libusb_transfer *transfer = 
>> USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
>> +    struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
>> +    struct wince_transfer_priv *transfer_priv = (struct 
>> wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
>> +    struct wince_device_priv *priv = 
>> _device_priv(transfer->dev_handle->dev);
>> +    BOOL direction_in, ret;
>> +    struct winfd wfd;
>> +    DWORD flags;
>> +    HANDLE eventHandle;
>> +            
>> +    transfer_priv->pollable_fd = INVALID_WINFD;
>> +    direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
>> +    flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
>> +    flags |= UKW_TF_SHORT_TRANSFER_OK;
>> +
>> +    eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
>> +    if (eventHandle == NULL) {
>> +            usbi_err(ctx, "Failed to create event for async transfer");
>> +            return LIBUSB_ERROR_NO_MEM;
>> +    }
>> +
>> +    wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, 
>> itransfer, &wince_cancel_transfer);
>> +    if (wfd.fd < 0) {
>> +            CloseHandle(eventHandle);
>> +            return LIBUSB_ERROR_NO_MEM;
>> +    }
>> +
>> +    transfer_priv->pollable_fd = wfd;
>> +    ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, 
>> transfer->buffer,
>> +            transfer->length, &transfer->actual_length, wfd.overlapped);
>> +    if (!ret) {
>> +            int libusbErr = translate_driver_error(GetLastError());
>> +            usbi_err(ctx, "UkwIssueBulkTransfer failed: error %d", 
>> GetLastError());
>> +            wince_clear_transfer_priv(itransfer);
>> +            return libusbErr;
>> +    }
>> +    usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? 
>> POLLIN : POLLOUT);
>> +    itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
>> +
>> +    return LIBUSB_SUCCESS;
>> +}
> The code for control is quite similar to that for bulk transfers. Can
> this really not be refactored?

Possibly. I'll have a look and see if it looks any neater with them 
sharing whatever code they can.

>
>
>> +static void wince_transfer_callback(struct usbi_transfer *itransfer, 
>> uint32_t io_result, uint32_t io_size)
>> +{
>> +    struct libusb_transfer *transfer = 
>> USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
>> +    struct wince_transfer_priv *transfer_priv = (struct 
>> wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
>> +    struct wince_device_priv *priv = 
>> _device_priv(transfer->dev_handle->dev);
>> +    int status;
>> +
>> +    usbi_dbg("handling I/O completion with errcode %d", io_result);
>> +
>> +    if (io_result == ERROR_NOT_SUPPORTED) {
>> +            /* The WinCE USB layer (and therefore the USB Kernel Wrapper 
>> Driver) will report
>> +             * USB_ERROR_STALL/ERROR_NOT_SUPPORTED in situations where the 
>> endpoint isn't actually
>> +             * stalled.
>> +             *
>> +             * One example of this is that some devices will occasionally 
>> fail to reply to an IN
>> +             * token. The WinCE USB layer carries on with the transaction 
>> until it is completed
>> +             * (or cancelled) but then completes it with USB_ERROR_STALL.
>> +             *
>> +             * This code therefore needs to confirm that there really is a 
>> stall error, but checking
>> +             * the pipe status and requesting the endpoint status from the 
>> device.
>> +             */
> That's quite invasive, and potentially a significant performance
> hit. :( Also, did you do extensive testing to determine that it
> will actually work with devices? (I know it's supposed to, but..)

This does seem to work for the device which fail to reply to an IN token 
in time and for devices which genuinely stall. However I do agree that 
it is an ugly hack.

If I get the time I do want to look into seeing if it's possible to 
patch the WinCE USB layer to return an error code other than 
USB_ERROR_STALL. That will probably break other USB drivers running on 
the same system so it isn't a trivial change to do.

>
>
>> +    default:
>> +            usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", 
>> windows_error_str(io_result));
> Maybe include the error number, which may be easier to look up in
> systems programming documentation.

windows_error_str() does include the error code value at the start of the 
string it returns:

        safe_sprintf(wErr_string, ERR_BUFFER_SIZE, _T("[%d] "), error_code);


>
>
>> +const struct usbi_os_backend wince_backend = {
> ..
>> +        wince_clock_gettime,
>> +#if defined(USBI_TIMERFD_AVAILABLE)
>> +        NULL,
>> +#endif
> I think neither Windows nor CE has timerfd, so no need to copypaste
> this unneccessary check around.

Good point :)

>
>
>> +};
>> \ No newline at end of file
> Please make sure that the last line of every file includes a newline.

Sorry, I should have checked that before submitting.

>
>
>> +++ b/wince/config.h
>> @@ -0,0 +1,21 @@
>> +/* config.h.  Manual config for WinCE.  */
>> +
>> +#ifndef _MSC_VER
>> +#warn "wince/config.h shouldn't be included for your development 
>> environment."
>> +#error "Please make sure the msvc/ directory is removed from your build 
>> path."
> I think this check is redundant since you have not added any support
> for WinCE to the autotools build files. I guess that there is simply
> no gcc+binutils for WinCE? Also note the msvc/ copypaste error in the
> error message.

Good point. I'll adjust the error message to one which describes the 
actual problem of attempting to compile on a non-Microsoft compiler not 
being supported.

>
>
>> +++ b/wince/errno.h
>> @@ -0,0 +1,12 @@
>> +/* Dummy file to support lack of errno.h on WinCE. */
>> +
>> +#define EPERM   1
>> +#define EINTR   4
>> +#define EIO     5
>> +#define EBADF   9
>> +#define ENOMEM 12
>> +#define EACCES 13
>> +#define EBUSY  16
>> +#define EINVAL 22
>> +
>> +extern int errno;
> So is it actually a dummy file, or are those values being used? If
> they are being used then I think dummy is a misnomer, perhaps
> compatibility is better? And perhaps there are WinCE defines that
> could be used rather than the magic numbers?

You are correct that it's not actually a dummy file, I'll adjust that 
comment.

As errno isn't a WinCE concept this is really just present for 
compatibility. As such the defines are just reflecting the standard 
POSIX values. I'll add an appropriate comment.

>
>
>> +++ b/wince/inttypes.h
> Did this file change between Windows and WinCE?

No. I'll sort this out with the dummy header files.

>
>
>> +++ b/wince/libusb-1.0/libusb-1.0.vcproj
> Was this file generated completely by the SDK Visual Studio, or did
> you start with a file in msvc/ ?

I think it's generated completely by Visual Studio, is it just the line 
endings which are a bit wrong?

>
> Does MSVC enforce any particular style of line endings in the file
> for the WinCE project?

I don't know. I'll find out and make it match the other vcproj files as 
necessary.

>
>
>> +++ b/wince/libusb.sln
>> @@ -0,0 +1,114 @@
>> +
> Is the BOM required?

The tool creating the file seemed to think it was. I'm not sure there is 
any value in removing it. Does it break something on other systems?

>
>
>> +++ b/wince/signal.h
>> @@ -0,0 +1 @@
>> +/* Dummy file to support lack of signal.h on WinCE. */
>> \ No newline at end of file
> Why not fix the include instead?

See my comment above about avoid adding lots of #ifndef OS_WINCE to 
common code.

>
>
>> +++ b/wince/stdint.h
> I guess this file is similar between Windows and WinCE.

I think it's identical.

>
>
>> +++ b/wince/sys/types.h
>> @@ -0,0 +1 @@
>> +/* Dummy file to support lack of sys/types.h on WinCE. */
> ..
>
>> +++ b/wince/winresrc.h
>> @@ -0,0 +1 @@
>> +/* Dummy file to support lack of winresrc.h on WinCE. */
>> \ No newline at end of file
> Same here, why not fix the includes?
>
>
>> +++ b/.gitignore
> ..
>> @@ -37,3 +39,5 @@ doc/html
>>   Debug
>>   Release
>>   *.user
>> +*.suo
>> +STANDARDSDK_500 (*)
> What is .suo?

.suo files are "Solution User Options": 
http://msdn.microsoft.com/en-us/library/bb165909(v=vs.80).aspx 
<http://msdn.microsoft.com/en-us/library/bb165909%28v=vs.80%29.aspx>

>> Subject: [PATCH 4/6] WinCE: Adding workaround for getenv() not existing on
>>   WinCE.
> Please make this change in a more excellent way.

I have attempted to increase the excellence of this change by at least 
74% in the following commit :)

https://github.com/tobygray/libusbx/commit/4b0f2413ae85d197db8721e2fda5a85355d95e1b

>
>
>> +++ b/libusb/core.c
>> @@ -47,6 +47,11 @@ const struct usbi_os_backend * const usbi_backend = 
>> &wince_backend;
>>   #error "Unsupported OS"
>>   #endif
>>   
>> +#ifdef OS_WINCE
>> +// Workaround for WinCE not supporting getenv
>> +#define getenv(x) NULL
>> +#endif
> If there is absolutely nothing in WinCE which corresponds to an
> environment variable then put the call within #ifdef instead.
>
>
>> Subject: [PATCH 5/6] WinCE: Updating time function calls to use appropriate
>>   APIs on WinCE.
> Squash together with the other WinCE commits.
>
>
>> From: Simon Haggett <simon.hagg...@realvnc.com>
>> Date: Tue, 10 Jul 2012 16:07:45 +0100
>> Subject: [PATCH 6/6] Windows: usbi_cond_destroy() should free handles created
>>   by usbi_cond_intwait().
> Thanks, I've applied this fix to libusb.git.
>

Excellent. Thanks for your review comments.

Regards,

Toby

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
libusbx-devel mailing list
libusbx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libusbx-devel

Reply via email to