I'm developing a USB RNDIS and HID composite device. For the RNDIS device, I'm using MS OS 2.0 Descriptors described in the Microsoft document "Microsoft OS 2.0 Descriptors Specification" dated April, 2017 (linked at the bottom of https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors). I'm working with a Windows 10 host.
Both devices are recognized but only the HID device is recognized correctly; windows assigns the RNDIS device to be a serial port.
Here's some of the pertinents.
Device descriptor:
.bLength = 18
.bDescriptorType = 1
.bcdUSB = 0x0201
.bDeviceClass = 0xef
.bDeviceSubClass = 2
.bDeviceProtocol = 1
.bMaxPacketSize0 = 64
.idVendor = USB_DEVICE_VENDOR_ID,
.idProduct = USB_DEVICE_PRODUCT_ID,
.bcdDevice = (USB_DEVICE_MAJOR_VERSION << 8) | USB_DEVICE_MINOR_VERSION,
.iManufacturer = 1
.iProduct = 2
.iSerialNumber = 3
.bNumConfigurations = 1
Configuration descriptor
Configuration Header:
.bLength = 9
.bDescriptorType = 2
.wTotalLength = 100
.bNumInterfaces = 3
.bConfigurationValue = 1
.iConfiguration = 0,
.bmAttributes = 0xc0
.bMaxPower = 0xfa
Interface Association Descritpor
.bLength = 8
.bDescriptorType = 11
.bFirstInterface = 0
.bInterfaceCount = 2
.bFunctionClass = 2
.bFunctionSubClass = 2
.bFunctionProtocol = 0xff,
.iFunction = 0
RNDIS Descriptor
CDC IF Descriptor
.bLength = 9
.bDescriptorType = 4
.bInterfaceNumber = 0
.bAlternateSetting = 0,
.bNumEndpoints = 1
.bInterfaceClass = 2
.bInterfaceSubClass = 2
.bInterfaceProtocol = 0xff,
.iInterface = 0
[Remainder of RNDIS Control & Data interface]
HID Descriptor
[HID Descriptor details]
BOS Descriptor
Header
.bLength = 5
.bDescriptorType = 15
.wTotalLength = 33
.bNumDeviceCaps = 1
Platform Capabilities Descriptor
.bLength = 28
.bDescriptorType = 16
.bDevCapability = 5
.bReserved = 0,
.capabilityId = {0xdf, 0x60, 0xdd, 0xd8, 0x89, 0x45, 0xc7, 0x4c, 0x9c, 0xd2, 0x65, 0x9d, 0x9e, 0x64, 0x8a, 0x9f}
Windows Descriptor Set
.dwWindowsVersion = 0x06030000
.wLength = 46
.bMsVendorCode = 1
.bAltEnumCode = 0
MS Compatibility Descriptor:
Header
.wLength = 10
.wDescriptorType = 0
.dwWindowsVersion = 0x06030000
.wTotalLength = 46
Configuration Subset Header
.wLength = 8
.wDescriptorType = 1
.bConfigurationValue = 1
.bReserved = 0,
.wTotalLength = 36
Function Subset Header
.wLength = 8
.wDescriptorType = 2
.bFirstInterface = 0
.bReserved = 0,
.wSubsetLength = 28
Compatibility ID
.wLength = 20
.wDescriptorType = 3
.compatibleId = {'R', 'N', 'D', 'I', 'S', 0, 0, 0},
.subCompatibleId = {'5', '1', '6', '2', '0', '0', '1', 0}
If I build my device to be a strictly RNDIS device then all works as expected - the device is recognized by Windows as an RNDIS device; I do not install any drivers. Here's a summary of the modifications I make for an RNDIS-only device (needed size changes were also made):
Change the Device Descriptor device class fields
Remove the IAD & HID sections of the Configuration Descriptor
Reduce the Configuration Descriptor bNumInterfaces count to 2
Remove the Configuration Subset Header & Function Subset Header from the MS Compatibility Descriptor
Note that if I leave the Configuration Subset Header & Function Subset Header in the MS Compatibility Descriptor, Windows responds as above - assigns the RNDIS device to be a serial port.
I've tried various permutations but can't seem to get beyond this point. I have not yet tried creating an INF for a custom device, but that is something I want to avoid.
Any help or suggestions?
Thanks.
Try changing the bConfigurationValue in your Microsoft OS 2.0 Descriptors (specifically the Configuration Subset Header) from 1 to 0. It is actually an index in the array of configurations; it is not the same as the thing that is named bConfigurationValue in the USB 2.0 specification.
I had the same problem, as described here:
https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/ae64282c-3bc3-49af-8391-4d174479d9e7/microsoft-os-20-descriptors-not-working-on-an-interface-of-a-composite-usb-device?forum=wdk
I did not check the rest of your descriptors so there very well might be other issues.
Related
I'm trying to use the DIO SPI mode on the ESP32 with the espidf (version 4.4).
But I encountered problems.
I have a ram device (ref 23LC1024) than can be accessed with several modes (single, dual, quad).
The single mode works perfectly (can write and read back)
The dual mode creates problems.
Here is how I configure the SPI bus (same setup for single or dual mode)
memset(&config, 0, sizeof(spi_bus_config_t));
config.mosi_io_num = MOSI_PIN;
config.miso_io_num = MISO_PIN;
config.sclk_io_num = SCLK_PIN;
config.quadwp_io_num = -1; // -1 not used
config.quadhd_io_num = -1; // -1 not used
config.flags = SPICOMMON_BUSFLAG_DUAL | SPICOMMON_BUSFLAG_MASTER;
spi_bus_initialize(VSPI_HOST, &config, SPI_DMA_DISABLED); // 0 DMA not used
Now the setup for the device (same setup for single mode or dual):
spi_device_interface_config_t devcfg = {
.clock_speed_hz = freq,
.command_bits = 8,
.address_bits = 24,
.dummy_bits = 8,
.mode = 0, // SPI MODE 0
.flags = 0,
.spics_io_num = _cs,
.queue_size = 1,
.pre_cb = NULL,
.post_cb = NULL};
ESP_ERROR_CHECK(spi_bus_add_device(VSPI_HOST, &devcfg, &data_Ram));
Now the setup for the transaction:
spi_transaction_t t;
memset(&t, 0, sizeof(t)); // Zero out the transaction
t.cmd = WRITE;
t.tx_buffer = data;
t.rx_buffer = NULL;
t.addr = address;
t.length = size * 8;
if (USE_DIO) // configure these flags in case of DIO
t.flags = SPI_TRANS_MODE_DIO | SPI_TRANS_MULTILINE_ADDR | SPI_TRANS_MULTILINE_CMD;
ESP_ERROR_CHECK(spi_device_transmit(data_Ram, &t)); // Transmit!
It works nicely in the single mode but with the dual mode I got the error:
E (1618) spi_master: check_trans_valid(699): Incompatible when setting to both multi-line mode and half duplex mode
Does it mean I cannot use DIO in half duplex mode with the SPI master library?
Is there something I should change in my setup ?
I tried to specify the SPI_DEVICE_HALFDUPLEX flag in the spi_device_interface_config_t. Does not help.
Unfortunately I did not find any example on internet.
Thanks for your heads up!
E (1618) spi_master: check_trans_valid(699): Incompatible when setting to both multi-line mode and half duplex mode means that you cannot use MISO and MOSI for transfering (multiline) AND use them at the same time (full duplex).
Set your device to half duplex to fix the problem:
spi_device_interface_config_t devcfg = {
.flags = SPI_DEVICE_HALFDUPLEX,
...
};
In my experience, SPI_TRANS_MULTILINE_ADDR doesn't work, at least with spi_device_transmit.
If your ram device allows it, try without the "multilined" address and command.
I'm using an NTAG I2C plus 2k memory tag and using the react-native-nfc-manager library to interface with the tag.
Is there a way to specify the sector that you're intending to write to?
I know there is an API to specify the page offset to write to, but how do you specify the sector the page offsets are in?
(Updated to include below code sample)
let tech = Platform.OS === 'ios' ? NfcTech.MifareIOS : NfcTech.NfcA;
await NfcManager.requestTechnology(tech, {
alertMessage: 'Hold your phone close to the NFC tag.',
});
let fullLength = data.length + 7;
let payloadLength = data.length + 3;
let cmd =
Platform.OS === 'ios'
? NfcManager.sendMifareCommandIOS
: NfcManager.transceive;
// select sector 2 prior to writing data
await cmd([0xc2, 0xff]);
await cmd([0x02, 0x00, 0x00, 0x00]);
await cmd([
0xa2,
MEMORY_MAPPING[`${chunkToWriteTo}`][1],
0x03,
fullLength,
0xd1,
0x01,
]);
await cmd([
0xa2,
MEMORY_MAPPING[`${chunkToWriteTo}`][2],
payloadLength,
0x54,
0x02,
0x65,
]);
let currentPage = MEMORY_MAPPING[`${chunkToWriteTo}`][0] + 2;
let currentPayload = [0xa2, currentPage, 0x6e];
for (let i = 0; i < data.length; i++) {
currentPayload.push(parseInt(data[i]));
if (currentPayload.length == 6) {
try {
await cmd(currentPayload);
} catch (error) {
console.log(error);
}
currentPage += 1;
currentPayload = [0xa2, currentPage];
}
}
Thanks in advance.
So "NTAG I2C plus 2k" seems to be a Certified Type 2 tag using NfcA comms.
It's datasheet
This Tag has additional commands over the Type 2 Standard to select the sector because Type 2 Tag's don't normally have Sectors.
So reading the datasheet Section 10.12 you would transceive the following commands bytes an example
C2h FFh - Select Sector
03h 00h 00h 00h - Sector 3
Then write to page address as normal with the A2h command byte
react-native-nfc-manage offers an nfcAHandler with a transceive method to send and receive these low level commands to the NFC chip.
Update:
For iOS it treats Type 2 Tags as Mifare Ultralight's and thus sendMifareCommandIOS from the API to send the same commands.
(Both Android and iOS have the nfcAHandler)
Note I've not tried this, I just do things with normal Type 2 Tags
I am using mdb on Solaris 11. I have opened a file by using " tail -f file_name" command in another ssh session. I got the pid of tail command and Vnode of the file opened by tail command. After getting the Vnode, I fired "walk page" on this file. Unfortunately, I am not getting any pages in walk. How to get Virtual Pages and Physical pages?
I have done following.
1) Opened the file with 'tail -f'.
2) Get the pid in mdb. Get the Vnode of the opened file.
3) Get the page_t from Vnode_t of the opened file.
4) Left shift to the page number with 0xD, it will give pp2pa effect.
Here are the dcmds in mdb.
> ::pgrep tail
S PID PPID PGID SID UID FLAGS ADDR NAME
R 2889 2882 2889 2850 0 0x4a004000 0000060013f29890 tail
> 0000060013f29890::pfiles
FD TYPE VNODE INFO
0 REG 00000600162f6740 /export/home/chaitanya/OpenSolaris/README.opensolaris
1 CHR 000006001a290400 /devices/pseudo/pts#0:2
2 CHR 000006001a290400 /devices/pseudo/pts#0:2
> 00000600162f6740::walk page
70004781480
700040b0400
> 70004781480::print -at page_t
{
70004781480 u_offset_t p_offset = 0x2000
70004781488 struct vnode *p_vnode = 0x600162f6740
70004781490 selock_t p_selock = 0
70004781494 uint_t p_vpmref = 0x11d9d
70004781498 struct page *p_hash = 0x70002f79b00
700047814a0 struct page *p_vpnext = 0x700040b0400
700047814a8 struct page *p_vpprev = 0x700040b0400
700047814b0 struct page *p_next = 0x70004781480
700047814b8 struct page *p_prev = 0x70004781480
700047814c0 ushort_t p_lckcnt = 0
700047814c2 ushort_t p_cowcnt = 0
700047814c4 kcondvar_t p_cv = {
700047814c4 ushort_t _opaque = 0
}
700047814c6 kcondvar_t p_io_cv = {
700047814c6 ushort_t _opaque = 0
}
700047814c8 uchar_t p_iolock_state = 0
700047814c9 volatile uchar_t p_szc = 0
700047814ca uchar_t p_fsdata = 0
700047814cb uchar_t p_state = 0x40
700047814cc uchar_t p_nrm = 0x2
700047814cd uchar_t p_vcolor = 0x2
700047814ce uchar_t p_index = 0
700047814cf uchar_t p_toxic = 0
700047814d0 void *p_mapping = 0
700047814d8 pfn_t p_pagenum = 0x80f029
700047814e0 uint_t p_share = 0
700047814e4 uint_t p_sharepad = 0
700047814e8 uint_t p_slckcnt = 0
700047814ec uint_t p_kpmref = 0
700047814f0 struct kpme *p_kpmelist = 0
700047814f8 kmutex_t p_ilock = {
700047814f8 void *[1] _opaque = [ 0 ]
}
}
Left shift to the page number 0x80f029 with 0xD, it will give pp2pa
> 101E052000,100::dump -p
\/ 1 2 3 4 5 6 7 8 9 a b c d e f v123456789abcdef
101e052000: 75742069 742e2020 4e6f7220 646f2079 ut it. Nor do y
101e052010: 6f752068 61766520 746f206b 65657020 ou have to keep
101e052020: 7468650a 20202020 206e616d 65206f70 the. name op
101e052030: 656e736f 6c617269 732e7368 2c206275 ensolaris.sh, bu
101e052040: 74207468 61742773 20746865 206e616d t that's the nam
101e052050: 65207765 276c6c20 75736520 696e2074 e we'll use in t
101e052060: 68657365 206e6f74 65732e0a 0a202020 hese notes...
101e052070: 20205468 656e206d 616b6520 74686520 Then make the
101e052080: 666f6c6c 6f77696e 67206368 616e6765 following change
101e052090: 7320696e 20796f75 72206f70 656e736f s in your openso
101e0520a0: 6c617269 732e7368 3a0a0a20 20202d20 laris.sh:.. -
101e0520b0: 6368616e 67652047 41544520 746f2074 change GATE to t
101e0520c0: 6865206e 616d6520 6f662074 68652074 he name of the t
101e0520d0: 6f702d6c 6576656c 20646972 6563746f op-level directo
101e0520e0: 72792028 652e672e 2c0a2020 20202022 ry (e.g.,. "
101e0520f0: 74657374 77732229 2e0a0a20 20202d20 testws")... -
I have this in wvdial.conf:
[Dialer Defaults]
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0
Modem Type = USB Modem
Phone = *99#
New PPD = yes
ISDN = 0
Username = foo
Init1 = ATZ
Password = foo
Modem = /dev/ttyUSB1
Baud = 9600
Stupid Mode = 0
#Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CFUN=1
Init4 = AT+CGDCONT=1,"ip","internet"
Auto Reconnect = on
(PIN disabled)
This is working for 4G USB Dongle Huawei E3131 # T-mobile.pl.
And now I have 2 questions:
1 How to translate this config to /etc/conf.d/net for connect as net.ppp1 (Gentoo) (I would connecting without wvdial)
2 After connecting I get default route with metric 0, How to change metric to say 100? (I'm interested in setting metric for both wvdial & pppd way)
I wish to create an "enum-like" list of constants with the following properties:
The values of each identifier are sequential, with a few gaps. (I believe iota and the blank identifier help in this regard).
The identifiers are private to the module.
The constants can only be compared with other constants of the same type.
The enumeration is based on the enum fuse_opcode from FUSE. Here's some code for what I'm trying to accomplish (and also very wrong):
const Opcode (
_ = iota // skip 0
lookupOp
forgetOp
getattrOp
setattrOp
readlinkOp
symlinkOp // 6
_ // skip 7
mknodOp // 8
// et cetera ad nauseam
)
You want something like this. You can still compare these constants against literal integers (there's no way to prevent that) but any comparison or assignment to other integer values will get a compiler error.
type opCode int
const (
lookupOp opCode = iota+1
forgetOp
getattrOp
setattrOp
readlinkOp
symlinkOp // 6
_ // skip 7
mknodOp // 8
// et cetera ad nauseam
)
If you really want to prevent external packages from seeing the fact that these are integer constants, but you still want it comparable, you might consider doing something like this,
type OpCode struct {
code opCode
}
and only exposing OpCode in your API. I'd also suggest explicitly documenting that it's comparable.
package fuse
type opCode int32
const (
opLookup opCode = 1
opForget opCode = 2
opGetattr opCode = 3
opSetattr opCode = 4
opReadlink opCode = 5
opSymlink opCode = 6
opMknod opCode = 8
opMkdir opCode = 9
opUnlink opCode = 10
)
Here's the Go code for the FUSE opcodes. It was created from enum fuse_opcode. Typically you would write a script to do that; I used a text editor. Since the constant values match the C enum values, explicit values are used.
package fuse
type opCode int32
const (
opLookup = 1
opForget = 2
opGetattr = 3
opSetattr = 4
opReadlink = 5
opSymlink = 6
opMknod = 8
opMkdir = 9
opUnlink = 10
opRmdir = 11
opRename = 12
opLink = 13
opOpen = 14
opRead = 15
opWrite = 16
opStatfs = 17
opRelease = 18
opFsync = 20
opSetxattr = 21
opGetxattr = 22
opListxattr = 23
opRemovexattr = 24
opFlush = 25
opInit = 26
opOpendir = 27
opReaddir = 28
opReleasedir = 29
opFsyncdir = 30
opGetlk = 31
opSetlk = 32
opSetlkw = 33
opAccess = 34
opCreate = 35
opInterrupt = 36
opBmap = 37
opDestroy = 38
opIoctl = 39
opPoll = 40
opNotifyReply = 41
)