I think having this discussion is great because it exposes new and different use cases. Writing a driver API is hard because there's so many different needs, split up in different ways. Hopefully getting this working well will make the driver API even better and workable for more use cases.
I think it might be a good idea to answer these anyway even though most of the code will be redone, just to check a few things.
The problem here is that it's a USB/hotpluggable device: it can be present at one time, gone the next, and then back again later - maybe as different hardware with different parameters. It looked like this function was only intended to be a sanity check before calling driver_init().
I would say that always returning true here might be the way to go. Here's how I'm thinking about it: I'd argue that the USB host really is always present, which is kind of like a proxy to the things connected to it. Now, initialization might fail if something isn't actually connected, but the hardware might "technically" be there.
The function's (driver_has_hardware()) existence is to be able to determine whether to avoid even attempting to initialize the Ethernet device.
On Teeny 4.1, I don't always return true because a Teensy 4.1 can exist without a PHY chip, either because it was removed, broke off, or it's the no-Ethernet version.
Technically there is, once the USB_RNDIS class receives a single block of data from the device (which may contain multiple packets but typically only one) it won't attempt to fetch any more until it's all drained by recv() being called. Ideally I want to pass empty pbufs to USB_RNDIS so it can receive data directly into them to avoid copying, but this will involve some trickery balancing packet lengths with endpoint sizes to make sure there are no overruns.
I just trust the driver writer to do what's best, and if that's the best, then cool. It's just something I try to do for robustness, to set upper bounds on things. You'll note that in the Teensy 4.1 driver, I only loop up to "RX_SIZE*2" so that other parts of the system get a chance to run too, in a guaranteed way.
There is no "probe" as such; when a USB device matching the RNDIS class is inserted, it gets picked up by the USB_RNDIS instance (via offer() and attach() ). That automatically starts the initialization procedure which retrieves the MAC address, MTU, etc.
So I'm not really sure what this driver function should do; maybe it should return true at any time after a device is connected/disconnected to indicate driver_has_hardware() needs to be rechecked?
In this case, I think returning false, as you have it, is the best choice for this driver.
The link speed is available, I just didn't bother coding it. Although for RNDIS the link speed seems to be more reliable as an indicator of the link state; android always says the link is up if the state is queried directly, but it will return 0 for link speed if it's actually down.
It's also not very accurate i.e. for most implementations it seems to be a hardcoded value rather than having real world significance. The official description of the OID_GEN_LINK_SPEED parameter is "link speed in units of 100 bps". Android returns something like 4.125e6 so it seems to be using the USB bus speed (480mbps) and old windows mobile devices are hardcoded to return 1e5 (10mbps) which would have been a miracle considering most of those used GSM.
There is also a
OID_GEN_MAC_OPTIONS parameter that can indicate if the link is full duplex and if the MAC address can be overriden, but I'm pretty sure they will just return hardcoded values on nearly all devices.
The link speed should be the Ethernet link speed and not the USB<->Teensy link speed. (As you know. Driver writers do weird stuff sometimes.) If that's not possible to get, I might add a driver_is_link_speed_detectable() or something. (Along with some other "is detectable/settable" functions like driver_is_mac_settable(), etc.) (But it sounds like the functionality, in theory, should be there.)
MTU: 8050
MAX_FRAME_LEN: 8064
Link Speed: 100000
...
The joys of Windows CE/mobile:
It's a software link so... I guess the MTU/frame length can just be whatever it feels like. Looks like it's up so let's ask for an IP:
Code:
Local IP = 169.254.2.2
Subnet mask = 255.255.255.0
Gateway = 0.0.0.0
DNS = 0.0.0.0
*sad trombone noise*
(The device itself has internet access, over wifi... it just doesn't feel like sharing it.)
The 14 bytes for MAX_FRAME_LEN on top of the MTU seems right (if not including the 4-byte FCS (frame check sequence)). It just doesn't include the 4-byte 802.1Q tag. 8050 might be the actual MTU, but since that's a few times larger than a USB frame, I'm also curious about that. I'm curious what the datasheet for that USB device says about that.
I'm curious: Does sending/receiving traffic work with a static IP? Note that getting a self-assigned IP may just mean that DHCP isn't being relayed to wherever it needs to get relayed to, or that there isn't a DHCP server. Is there a DHCP server accessible to that network?