|
From: Paul Q. <pa...@wo...> - 2018-05-31 09:43:15
|
Thank you David, having DeviceInterfaceGUIDs in the registry seems to have fixed the issue and WinUSB can now access the WinUSB part of the composite device. It's rather frustrating that this is necessary as it requires using the old SetupDI API and consumes around 180 bytes of flash memory on the device, but at least it works. Best of all, dfu-util seems to be working with the patch I wrote to libusb. If there is anything I can do to help get it tested and merged then please let me know. Thanks to everyone who helped resolve this. Regards, Paul On Thu, 31 May 2018 at 09:07, Paul Qureshi <pa...@wo...> wrote: > > Thanks guys, I'll go and try adding the GUID. WinUSB works without it > just fine for non-composite devices (and by extension libusb does as > well), and that's how I did my DFU bootloader because adding the GUID > just consumes more flash memory which is rather scarce. > > As for how to set up DFU runtime stuff, the DFU runtime needs its own > interface. That interface has no endpoints, it only accepts commands > over the control interface (EP0) with the recipient set as "Interface" > in bmRequestType. Unfortunately, adding this interface makes the > device composite on Windows. In fact its only purpose seems to be to > advertise that the device supports DFU, but I guess there is no reason > why you couldn't send the DFU_DETACH command without it. > > The device I am trying to set up at the moment looks like this: > > Interface 0: HID (HID driver) > Interface 1: DFU (WinUSB driver via WCID) > > Windows is a real mess. There is the older SetupDI API, but it seems > that it's not recommended now because it's not fully supported for > Universal Apps or something. Microsoft has a guide for porting to > cfgmgr32 here: https://docs.microsoft.com/en-us/windows-hardware/drivers/install/porting-from-setupapi-to-cfgmgr32 > > Cfgmgr32 seems nicer and lets you see the children of composite > devices. Unfortunately you can't get the Device Path you need to open > the children... Maybe it can be read from the registry somehow, but > they certainly don't make it easy to find out how. Hopefully adding a > GUID will help. > > Regards, > Paul > > On Wed, 30 May 2018 at 19:57, <Phi...@mi...> wrote: > > > > If you are expecting the DFU mode device descriptor to come back as HID, then this is probably not going to happen (hence your frustration). In most cases, the bDeviceClass of the DFU mode device descriptor would come back as 0x00 (which mean to “see the interface descriptor”). There will only be one interface descriptor in DFU mode, and its bInterfaceClass should be 0xFE (application specifc) with bInterfaceSubClass of 0x01 (DFU) and bInterfaceProtocol of 0x02 (DFU mode protocol). Unfortunately, I don’t think that Windows HID will recognize this (though I have never pursued this line of access). > > > > If on the other hand, you can live with WinUsb as the associated driver for the DFU mode VID/PID of your device, then the following might help. > > > > Let’s take a fictitious device as an example. This device has one configuration with three interfaces. These are as follows: > > > > Interface 0: HID (Interrupt endpoints) > > Interface 1: Bulk > > Interface 2: Bulk > > > > The assumption, in this example, is that the HID interface supports the handling of the DFU_DETACH command in runtime mode (or at least there is some vendor unique command that can be issued to that endpoint to bump the unit into DFU mode). The runtime mode descriptors should include a DFU runtime interface descriptor and related DFU functional descriptor (this allows the host to see that the unit supports DFU and specifies its characteristics). If the unit does not supply these descriptors, then you will have to use some other criteria to determine if the unit is a unit you know supports DFU (such as the runtime PID). > > > > Let’s say it handles DFU and the DFU_DETACH setup packet. > > > > For libusb, you could use the libusb_control_transfer to send that detach request (see my caveat comment way below about libusb_control_transfer). If not using libusb, then on Windows, you can use the HidD_SetOutputReport( ) method. For a device whose first interface is say bulk, and it has been associated with WinUsb, then you can use the WinUsb_ControlTransfer method to send the DFU_DETACH packet (see example code below). These all write through the control endpoint (EP0). > > > > Whether interface 0 is HID or bulk (and associated with WinUsb), it would be opened using the CreateFile method (though the HID path used is different than from the “normal” path and is obtained during your unit detection process). I am not sure what libusb uses, but I would think it would boil down to a call to CreateFile on Windows. > > > > If you retrieve the DFU spec from usb.org (and yes, the spec has a very old date on it), it will outline the sequence of steps associated with using the DFU_DETACH command. Depending upon the contents of the DFU functional descriptor, the targeted device can indicate whether it expects a bus reset or not to re-enumerate once it has received the DFU_DETACH packet. See the document, "Universal Serial Bus Device Class Specification for Device Firmware Upgrade", Version 1.1, dated 05 August 2004 (which is the latest revision), taken from http://www.usb.org/developers/docs/devclass_docs and the item "Device Firmware Upgrade Group". > > > > Now if the unit supports DFU mode, but does not support the DFU_DETACH packet, then the unit would have to implement some vendor unique command that bumps the unit into DFU mode and re-enumerates. > > > > Whether interface 0 is either HID or bulk, the DFU_DETACH packet sent to the “write control pipe” function in runtime mode would be: > > > > data[0] = (BYTE)0x21; // host-to-device xfer > > data[1] = (BYTE)0x00; // DFU_DETACH > > data[2] = (BYTE)(msTimeout & 0x00FF); // wValue = timeout (not used if device is NOT waiting for bus reset) > > data[3] = (BYTE)((msTimeout >> 8) & 0x00FF); > > data[4] = (BYTE)0x00; // wIndex = interface (should be zero, 0, since it is the only interface in DFU mode) > > data[5] = (BYTE)0x00; // " > > data[6] = (BYTE)0x00; // wLength > > data[7] = (BYTE)0x00; // " > > > > If interface 0 were bulk (and associated with WinUsb), then the following code would send the DFU_DETACH packet. The first eight bytes will be interpreted as a packed WINUSB_SETUP_PACKET structure. The data associated with the setup packet and passed to the WinUsb_ControlTransfer routine will start at location [8]. In this case, there is no data associated with the setup packet and so the “byteCount” is zero. “pData” is a pointer to the packed unsigned char (BYTE) array “data” above. > > > > if (!pWinUsb_ControlTransfer(wusbH, // Interface Handle > > *(PWINUSB_SETUP_PACKET)pData, > > (pData+8), // buffer pointer (skip the setup packet) > > (ULONG)byteCount, // byteCount==0 for this > > &actual, > > NULL)) > > result = GetLastError(); > > else > > result = (int)actual; > > } > > > > If interface 0 were HID, then use the HidD_SetOutputReport method instead of WinUsb_ControlTransfer. > > > > With libusb, I presume you would use libusb_control_transfer. Whether this is handled properly by the respective libusb OS backend (Windows or OS X), I am not sure. I am pretty sure it is handled OK on Linux. > > > > After the DFU_DETACH command is issued and processed by the device, the device is supposed to re-enumerate on the bus into DFU mode and come back with a different PID. If this PID is associated with WinUsb (via an INF file), then you can use the WinUsb_ControlTransfer to do all the communication with the device in DFU mode (and this is regardless of whether the runtime mode interface 0 were HID or bulk). In DFU mode, it is essentially a different entity. It has one configuration, one interface, and only the control endpoint (EP0). The other DFU_xxxx commands will use EP0 through which to communicate. > > > > After any firmware updates, the host instructs the unit (still in DFU mode) to reset, after which it re-enumerates, but this time comes back on the bus with its original PID and in runtime mode (hopefully now running the new firmware). > > > > Of course, this is all assuming that interface 0 of the runtime mode of the device is the interface that can handle the DFU_DETACH request (or a vendor unique command equivalent). > > > > As a clarification, for composite devices, an INF file can specify, along with the VID/PID combo, an interface number. That triple combo can be associated with WinUsb for a given interface. So for our example device, given a proper INF file, the result could be that Windows “sees” and reports three entities, one handled by the HID driver, and two handled by WinUsb: > > > > Interface 0: HID (Interrupt endpoints) --> HID > > Interface 1: Bulk --> WinUsb > > Interface 2: Bulk --> WinUsb > > > > where in the INF file, if the VID were 1234, and the PID were ABCD, interfaces 1 and 2 would be represented by: > > > > USB\VID_1234&PID_ABCD&MI_01 > > And > > USB\VID_1234&PID_ABCD&MI_02 > > > > both of which would be associated with WinUsb in the INF file. > > > > Hope I have not muddied the waters with all this. And, unfortunately, if you don’t want to use an INF file and WinUsb to handle the DFU mode VID/PID, then I believe you would have to write a specific driver to access it (still using an INF file). I am sure there are others more knowledgeable than I that can jump into this discussion. > > > > > > ________________________________________ > > From: Paul Qureshi [pa...@wo...] > > Sent: Wednesday, May 30, 2018 8:29 AM > > To: lib...@li... > > Subject: Re: [libusb] Windows composite device fix > > > > Hi Philip. > > > > How do you send the DFU_DETACH command? If the device is composite with say > > HID and WinUSB, then WinUSB can't open it to send the DFU_DETACH command. > > At least that's my experience here with Windows 7 x64. > > > > How are you opening the runtime device with WinUSB? Is it via a CreateFile > > handle or via the OpenDevice library function and a custom > > DeviceInterfaceGUID? > > > > Do you perhaps have any example code demonstrating this? > > > > Regards, > > Paul > > > > > > On Wed, 30 May 2018 at 16:15, <Phi...@mi...> wrote: > > > > > We have the capability of using WinUSB and DFU when updating composite > > devices. > > > > > The device's firmware would be bumped into DFU mode by the normal > > DFU_DETACH (setup) command or by any other mechanism you might want to > > employ. When your device re-enumerates into DFU mode (which will have a > > different PID), then that VID/PID can be specified in an INF file to use > > WinUSB (which can be used to access EP0, which is the only endpoint that > > DFU uses). > > > > > This is regardless of the configuration of the device in non-DFU (normal > > operation) mode, be that HID, CDC, bulk or whatever other endpoints that > > configuration might contain (as a composite device). Your "normal" device's > > configurations no longer apply when your device is in DFU mode. > > > > > Yes, you need an INF that specifies the VID and DFU PID to be handled by > > WinUSB, but this is a pretty trivial matter (unless you want absolutely no > > drivers involved). > > > > > Am I missing something here? > > > > > ________________________________________ > > > From: Paul Qureshi [pa...@wo...] > > > Sent: Wednesday, May 30, 2018 7:19 AM > > > To: lib...@li... > > > Subject: Re: [libusb] Windows composite device fix > > > > > I'm back now, and have spent a bit more time on this problem. > > > > > In short I think composite devices are not well supported on Windows, and > > > full DFU support is probably impossible with WinUSB. > > > > > The issue is that WinUSB only supports composite devices where all the > > > interfaces use the WinUSB driver. If you try to have something like an HID > > > device with WinUSB for the DFU interface, it just doesn't work. You can't > > > open the WinUSB interface. Therefore, DFU cannot be supported for another > > > other than pure WinUSB devices. > > > > > I also looked at ways to create a new but at least consistent runtime > > > bootloader protocol, but because of this limitation of WinUSB there isn't > > > one. You would need to have a separate protocol for HID, CDC, mass storage > > > and every other type of device. This has also scuppered my plan to have an > > > HID device with WinUSB bulk endpoints. > > > > > There is nothing that can be done to fix libusb because the problem is > > with > > > WinUSB. The only solutions all involve installing alternative drivers. > > > > > I'm giving up. > > > > > Regards, > > > Paul Qureshi > > > > > On Thu, 3 May 2018 at 09:05, Paul Qureshi <pa...@wo...> wrote: > > > > > > Hi Tim. > > > > > > On Wed, 2 May 2018 at 18:41, Tim Roberts <ti...@pr...> wrote: > > > > > > > Of course it is. WinUSB handles composite devices and multiple > > > > > interfaces. It just requires an INF. > > > > > > Yes, I was talking in the context of having the alternative driver > > > selected > > > > via WCID. This does not seem to be possible, only WinUSB can be > > selected. > > > > > > INF files are an unsatisfactory solution, especially for open source > > > > projects where the cost of getting them signed is prohibitive. More > > over, > > > > users prefer devices that "just work" and don't require manual driver > > > > installation. That is particularly true of things like keyboards and > > mice. > > > > > > So the goal here is to find a solution that works with WCID. Ideally > > > > without GUIDs too, because code space in a 4k bootloader is tight. > > > > > > > Now, there may be a slimy way to handle this. In the Enum tree of the > > > > > registry, each device has a "Service" entry that identifies the driver > > > > > service that will handle the device. It is possible to overwrite that > > > > > entry on the fly, then restart the device. When it comes back it, it > > > > > will load the alternative driver. You could do the DFU thing, then > > > > > rewrite the Service entry back to "usbccgp". You'd have to make sure > > > > > the entries for WinUsb were properly set up, but it might work. > > > > > > At the moment I am prototyping some WinUSB code to see what is possible > > > and > > > > if it could possibly be integrated into libusb somehow. libusb is aware > > of > > > > the sub-interfaces, but it sees them as already being claimed by the > > > > composite driver. Perhaps there is a way to find the correct sub-device > > at > > > > that stage. Alternatively, perhaps it would be possible to open the sub > > > > device with a special open function that takes the interface number. > > > > > > If none of that proves possible then a new WinUSB based DFU utility is > > the > > > > next option. I will be away for a few weeks so there won't be any > > progress > > > > this month. > > > > > > Regards, > > > > Paul > > > > > > ------------------------------------------------------------------------------ > > > Check out the vibrant tech community on one of the world's most > > > engaging tech sites, Slashdot.org! http://sdm.link/slashdot > > > _______________________________________________ > > > libusb-devel mailing list > > > lib...@li... > > > https://lists.sourceforge.net/lists/listinfo/libusb-devel > > > > ------------------------------------------------------------------------------ > > Check out the vibrant tech community on one of the world's most > > engaging tech sites, Slashdot.org! http://sdm.link/slashdot > > _______________________________________________ > > libusb-devel mailing list > > lib...@li... > > https://lists.sourceforge.net/lists/listinfo/libusb-devel |