
Originally Posted by
KurtE
Let me know if you have something to play with. This is another area I thought would be good to have support for in the usb host code....
@KurtE:
Spent this Sunday checking out three USB WIFI dongles and USB2LAN Ethernet dongle. YIKES! as Paul would say.
Using Linux lsusb:
The one Realtech WLAN adapter showed 4 endpoints. Three BULK endpoints and one Interrupt endpoint.
The Ralink WLAN adapter showed 7 endpoints! All 7 endpoints are BULK type.
The CISCO WLAN adapter showed 4 endpoints. Again three BULK endpoints and one Interrupt endpoint.
The USB2LAN dongle showed 2 BULK endpoints and 1 Interrupt endpoint. This where I have started (Only 3 endpoints to deal with).
I have been reading the 'usbcdc11.pdf' reference manual and I am thinking that the Interrupt endpoint could be a notification endpoint.
I modified the MSC claim function to adapt to two BULK type endpoints and one Interrupt type endpoint.
Here is what I have so far:
Code:
/* USBEthernet Teensy36 USB Host Ethernet library
* Copyright (c) 2019 Warren Watson.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//ethernetDriver.cpp
#include <Arduino.h>
#include "usbEther.h"
#define print USBHost::print_
#define println USBHost::println_
// Big Endian/Little Endian
#define swap32(x) ((x >> 24) & 0xff) | \
((x << 8) & 0xff0000) | \
((x >> 8) & 0xff00) | \
((x << 24) & 0xff000000)
void ethernetController::init()
{
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t));
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
driver_ready_for_device(this);
}
bool ethernetController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{
println("ethernetController claim this=", (uint32_t)this, HEX);
// only claim at interface level
if (type != 1) return false;
if (len < 9+7+7+7) return false; // Interface descriptor + 3 endpoint decriptors
print_hexbytes(descriptors, len);
uint32_t numendpoint = descriptors[4];
if (numendpoint < 1) return false;
if (descriptors[5] != 255) return false; // bInterfaceClass, Vendor Specific
if (descriptors[6] != 255) return false; // bInterfaceSubClass, Vendor Specific
if (descriptors[7] != 0) return false; // bInterfaceProtocol, 0 = No class specific protocol required
uint8_t desc_index = 9;
uint8_t in_index = 0xff, out_index = 0xff, notify_index = 0xff;
println("numendpoint=", numendpoint, HEX);
while (numendpoint--) {
if ((descriptors[desc_index] != 7) || (descriptors[desc_index+1] != 5)) return false; // not an end point
if (descriptors[desc_index+3] == 2) { // Bulk end point
if (descriptors[desc_index+2] & 0x80)
in_index = desc_index;
else
out_index = desc_index;
} else {
if (descriptors[desc_index+3] == 3) { // Interrupt end point
if (descriptors[desc_index+2] & 0x80)
notify_index = desc_index;
}
}
desc_index += 7; // point to next one...
}
if ((in_index == 0xff) || (out_index == 0xff) || (notify_index == 0xff)) return false; // did not find end point
endpointIn = descriptors[in_index+2]; // bulk-in descriptor 1 81h
endpointOut = descriptors[out_index+2]; // bulk-out descriptor 2 02h
endpointNotifyIn = descriptors[notify_index+2]; // Notification descriptor 3 81h
println("endpointIn=", endpointIn, HEX);
println("endpointOut=", endpointOut, HEX);
println("endpointNotificationIn=", endpointNotifyIn, HEX);
uint32_t sizeIn = descriptors[in_index+4] | (descriptors[in_index+5] << 8);
println("packet size in (ethernetController) = ", sizeIn);
uint32_t sizeOut = descriptors[out_index+4] | (descriptors[out_index+5] << 8);
println("packet size out (ethernetController) = ", sizeOut);
uint32_t notifySizeIn = descriptors[notify_index+4] | (descriptors[notify_index+5] << 8);
println("packet notify in (ethernetController) = ", notifySizeIn);
packetSizeIn = sizeIn;
packetSizeOut = sizeOut;
packetSizeNotifyIn = notifySizeIn;
uint32_t intervalIn = descriptors[in_index+6];
uint32_t intervalOut = descriptors[out_index+6];
uint32_t notifyIntervalIn = descriptors[notify_index+6];
println("polling intervalIn = ", intervalIn);
println("polling intervalOut = ", intervalOut);
println("polling notifyIntervalIn = ", notifyIntervalIn);
datapipeIn = new_Pipe(dev, 2, endpointIn, 1, packetSizeIn, intervalIn);
datapipeOut = new_Pipe(dev, 2, endpointOut, 0, packetSizeOut, intervalOut);
notifypipeIn = new_Pipe(dev, 3, endpointNotifyIn, 1, packetSizeNotifyIn, notifyIntervalIn);
datapipeIn->callback_function = callbackIn;
datapipeOut->callback_function = callbackOut;
notifypipeIn->callback_function = callbackNotifyIn;
// mk_setup(setup, 0x21, 10, 0, 0, 0); // 10=SET_IDLE
// queue_Control_Transfer(dev, &setup, NULL, this);
ethernetOutCompleted = false;
ethernetInCompleted = false;
ethernetControlCompleted = false;
deviceAvailable = true;
return true;
}
void ethernetController::control(const Transfer_t *transfer)
{
println("control CallbackIn (ethernetController)");
print_hexbytes(report, 8);
ethernetControlCompleted = true;
}
void ethernetController::callbackIn(const Transfer_t *transfer)
{
println("ethernetController CallbackIn (static)");
if (transfer->driver) {
print("transfer->qtd.token = ");
println(transfer->qtd.token & 255);
((ethernetController *)(transfer->driver))->new_dataIn(transfer);
}
}
void ethernetController::callbackOut(const Transfer_t *transfer)
{
println("ethernetController CallbackOut (static)");
if (transfer->driver) {
print("transfer->qtd.token = ");
println(transfer->qtd.token & 255);
((ethernetController *)(transfer->driver))->new_dataOut(transfer);
}
}
void ethernetController::callbackNotifyIn(const Transfer_t *transfer)
{
println("ethernetController CallbackNotifyIn (static)");
if (transfer->driver) {
print("transfer->qtd.token = ");
println(transfer->qtd.token & 255);
((ethernetController *)(transfer->driver))->new_dataNotifyIn(transfer);
}
}
void ethernetController::disconnect()
{
deviceAvailable = false;
deviceInitialized = false;
println("Device Disconnected...");
}
void ethernetController::new_dataOut(const Transfer_t *transfer)
{
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
println("ethernetController dataOut (static)", len, DEC);
print_hexbytes((uint8_t*)transfer->buffer, (len < 32)? len : 32 );
ethernetOutCompleted = true; // Last out transaction is completed.
}
void ethernetController::new_dataIn(const Transfer_t *transfer)
{
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
println("ethernetController dataIn (static): ", len, DEC);
print_hexbytes((uint8_t*)transfer->buffer, (len < 32)? len : 32 );
ethernetInCompleted = true; // Last in transaction is completed.
}
void ethernetController::new_dataNotifyIn(const Transfer_t *transfer)
{
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
println("ethernetController dataNotifyIn (static): ", len, DEC);
print_hexbytes((uint8_t*)transfer->buffer, (len < 32)? len : 32 );
}
And:
Code:
/*
* USBEthernet Teensy36 USB Host Mass Storage library
* Copyright (c) 2019 Warren Watson.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// USBEther.h
#ifndef _USBETHER_H_
#define _USBETHER_H_
#include "USBHost_t36.h"
//--------------------------------------------------------------------------
class ethernetController : public USBDriver {
public:
ethernetController(USBHost &host) { init(); }
ethernetController(USBHost *host) { init(); }
protected:
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
virtual void control(const Transfer_t *transfer);
virtual void disconnect();
static void callbackIn(const Transfer_t *transfer);
static void callbackOut(const Transfer_t *transfer);
static void callbackNotifyIn(const Transfer_t *transfer);
void new_dataIn(const Transfer_t *transfer);
void new_dataOut(const Transfer_t *transfer);
void new_dataNotifyIn(const Transfer_t *transfer);
void init();
private:
Pipe_t mypipes[3] __attribute__ ((aligned(32)));
Transfer_t mytransfers[7] __attribute__ ((aligned(32)));
strbuf_t mystring_bufs[1];
uint32_t packetSizeIn;
uint32_t packetSizeOut;
uint32_t packetSizeNotifyIn;
Pipe_t *datapipeIn;
Pipe_t *datapipeOut;
Pipe_t *notifypipeIn;
uint32_t endpointIn = 0;
uint32_t endpointOut = 0;
uint32_t endpointNotifyIn = 0;
setup_t setup;
uint8_t report[8];
volatile bool ethernetOutCompleted = false;
volatile bool ethernetInCompleted = false;
volatile bool ethernetControlCompleted = false;
bool deviceAvailable = false;
bool deviceInitialized = false;
};
#endif
The results of this sketch:
Code:
// Simple test of USB Host Ethernet Driver
// test.ino
// This example is in the public domain
#include "USBHost_t36.h"
#include "usbEther.h"
USBHost myusb;
//USBHub hub1(myusb);
//USBHub hub2(myusb);
//USBHub hub3(myusb);
ethernetController ethernet1(myusb);
void setup()
{
while (!Serial) ; // wait for Arduino Serial Monitor
Serial.println("USB Host Ethernet Testing");
myusb.begin();
}
void loop()
{
myusb.Task();
}
Is this:
Code:
USB Host Ethernet Testing
sizeof Device = 36
sizeof Pipe = 96
sizeof Transfer = 64
power up USBHS PHY
reset waited 4
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 1FFF3000
periodictable = 1FFF3000
port change: 10001803
connect
begin reset
port change: 18001205
port enabled
end recovery
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
12 01 00 02 FF FF 00 40 A6 07 15 85 01 01 01 02 03 01
VendorID = 07A6, ProductID = 8515, Version = 0101
Class/Subclass/Protocol = 255 / 255 / 0
Number of Configurations = 1
enumeration:
enumeration:
Manufacturer: ADMtek
enumeration:
Product: USB To LAN Converter
enumeration:
Serial Number: 0001
enumeration:
Config data length = 39
enumeration:
Configuration Descriptor:
09 02 27 00 01 01 00 80 70
NumInterfaces = 1
ConfigurationValue = 1
09 04 00 00 03 FF FF 00 00
Interface = 0
Number of endpoints = 3
Class/Subclass/Protocol = 255 / 255 / 0
07 05 81 02 00 02 00
Endpoint = 1 IN
Type = Bulk
Max Size = 512
Polling Interval = 0
07 05 02 02 00 02 00
Endpoint = 2 OUT
Type = Bulk
Max Size = 512
Polling Interval = 0
07 05 83 03 08 00 01
Endpoint = 3 IN
Type = Interrupt
Max Size = 8
Polling Interval = 1
enumeration:
ethernetController claim this=1FFF2020
Descriptor 4 = INTERFACE
ethernetController claim this=1FFF2020
09 04 00 00 03 FF FF 00 00 07 05 81 02 00 02 00 07 05 02 02 00 02 00 07 05 83 03 08 00 01
numendpoint=3
endpointIn=81
endpointOut=2
endpointNotificationIn=83
packet size in (ethernetController) = 512
packet size out (ethernetController) = 512
packet notify in (ethernetController) = 8
polling intervalIn = 0
polling intervalOut = 0
polling notifyIntervalIn = 1
new_Pipe
new_Pipe
new_Pipe
allocate_interrupt_pipe_bandwidth
ep interval = 1
interval = 1
best_bandwidth = 3, at offset = 0
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
Things I observed were endpoint type 3 (interrupt) can be 8 byte or up to 64 bytes.
Finding driver examples for the AMDTek AN8515 Is hard. Probably my search skills.
Any thoughts or clues?