Added AX88772A/B harwdare support

* Synchronized with FreeBSD driver - added support for AX88772A and
  AX88772B chipsets;
* Some new hardware ids added;
* Fixed devices lookup routine.
This commit is contained in:
Siarzhuk Zharski
2011-12-24 20:09:10 +00:00
parent 87ab70a3e2
commit 6ef455e4a2
6 changed files with 297 additions and 62 deletions
@@ -21,22 +21,21 @@
struct DeviceInfo {
union Id {
uint16 fIds[2];
uint32 fKey;
} fId;
uint16 fIds[2];
enum Type {
AX88172 = 0,
AX88772 = 1,
AX88178 = 2
AX88178 = 2,
AX88772A = 3,
AX88772B = 4
} fType;
const char* fName;
inline uint16 VendorId() { return fId.fIds[0]; }
inline uint16 ProductId() { return fId.fIds[1]; }
inline uint32 Key() { return fId.fKey; }
inline uint16 VendorId() { return fIds[0]; }
inline uint16 ProductId() { return fIds[1]; }
inline uint32 Key() { return fIds[0] << 16 | fIds[1]; }
};
@@ -83,7 +82,7 @@ virtual status_t SetPromiscuousMode(bool bOn);
uint32 EthernetCRC32(const uint8* buffer, size_t length);
virtual status_t ModifyMulticastTable(bool add,
ether_address_t* group);
status_t ReadMACAddress(ether_address_t *address);
virtual status_t ReadMACAddress(ether_address_t *address);
status_t ReadRXControlRegister(uint16 *rxcontrol);
status_t WriteRXControlRegister(uint16 rxcontrol);
@@ -115,7 +114,7 @@ virtual status_t ModifyMulticastTable(bool add,
int32 fStatusWrite;
sem_id fNotifyReadSem;
sem_id fNotifyWriteSem;
uint8 * fNotifyBuffer;
uint32 fNotifyBufferLength;
sem_id fLinkStateChangeSem;
@@ -51,7 +51,8 @@ enum ASIXVendorRequests {
READ_PHY_SEL_STATE = 0x21, // AX88772
WRITE_PHY_SEL = 0x22, // AX88772
READ_MIIS_IF_STATE = 0x21, // AX88178
WRITE_MIIS_IF_STATE = 0x22 // AX88178
WRITE_MIIS_IF_STATE = 0x22, // AX88178
WRITE_RXCONTROL_CFG = 0x2A // AX88772B
};
@@ -128,9 +128,13 @@ enum AX88772_SoftwareReset {
// Software PHY Select Status
enum AX88772_SoftwarePHYSelStatus {
SW_PHY_SEL_STATUS_EXT = 0x00,
SW_PHY_SEL_STATUS_INT = 0x01,
SW_PHY_SEL_STATUS_ASEL = 0x02
SW_PHY_SEL_STATUS_EXT = 0x00,
SW_PHY_SEL_STATUS_INT = 0x01,
SW_PHY_SEL_STATUS_ASEL = 0x02,
SW_PHY_SEL_STATUS_SS_MII = 0x04,
SW_PHY_SEL_STATUS_SS_RVRS_MII = 0x08,
SW_PHY_SEL_STATUS_SS_RVRS_GMII = 0x0C,
SW_PHY_SEL_STATUS_SS_ENB = 0x10
};
@@ -153,6 +157,38 @@ enum AX88772_BBState {
LINK_STATE_MDINT = 0x08
};
// EEPROM Map.
enum AX88772B_EEPROM {
EEPROM_772B_NODE_ID = 0x04
};
enum AX88772B_MFB {
AX88772B_MFB_2K = 0,
AX88772B_MFB_4K = 1,
AX88772B_MFB_6K = 2,
AX88772B_MFB_8K = 3,
AX88772B_MFB_16K = 4,
AX88772B_MFB_20K = 5,
AX88772B_MFB_24K = 6,
AX88772B_MFB_32K = 7,
AX88772B_MFB_Count = 8
};
struct _AX88772B_MFB {
size_t ByteCount;
size_t Threshold;
size_t Size;
} AX88772B_MFBTable[AX88772B_MFB_Count] = {
{ 0x8000, 0x8001, 2048 },
{ 0x8100, 0x8147, 4096 },
{ 0x8200, 0x81EB, 6144 },
{ 0x8300, 0x83D7, 8192 },
{ 0x8400, 0x851E, 16384 },
{ 0x8500, 0x8666, 20480 },
{ 0x8600, 0x87AE, 24576 },
{ 0x8700, 0x8A3D, 32768 }
};
const uint16 maxFrameSize = 1536;
@@ -184,6 +220,35 @@ AX88772Device::InitDevice()
}
status_t
AX88772Device::ReadMACAddress(ether_address_t *address)
{
if (fDeviceInfo.fType != DeviceInfo::AX88772B)
return ASIXDevice::ReadMACAddress(address);
// Auto-loaded default station address from internal ROM is
// 00:00:00:00:00:00 such that an explicit access to EEPROM
// is required to get real station address.
for (size_t i = 0; i < sizeof(ether_address_t) / 2; i++) {
size_t actual_length = 0;
uint16 addr = 0;
status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
READ_SROM, EEPROM_772B_NODE_ID + i, 0,
sizeof(addr), &addr, &actual_length);
if (result != B_OK) {
TRACE_ALWAYS("Error reading MAC[%d] address:%#010x\n", i, result);
return result;
}
address->ebyte[i * 2 + 0] = (uint8)addr;
address->ebyte[i * 2 + 1] = (uint8)(addr >> 8);
}
return B_OK;
}
status_t
AX88772Device::SetupDevice(bool deviceReplugged)
{
@@ -194,10 +259,51 @@ AX88772Device::SetupDevice(bool deviceReplugged)
result = fMII.Init(fDevice);
switch (fDeviceInfo.fType) {
case DeviceInfo::AX88772A:
result = _SetupAX88772A();
break;
case DeviceInfo::AX88772B:
result = _SetupAX88772B();
break;
default:
result = _SetupAX88772();
break;
}
if (result != B_OK)
return result;
result = fMII.SetupPHY();
if (result != B_OK) {
return result;
}
size_t actualLength = 0;
result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_MEDIUM_MODE,
MEDIUM_STATE_FD | MEDIUM_STATE_BIT2 |
MEDIUM_STATE_RFC| MEDIUM_STATE_TFC |
MEDIUM_STATE_RE | MEDIUM_STATE_PS_100,
0, 0, 0, &actualLength);
if (result != B_OK) {
TRACE_ALWAYS("Error of setting medium mode: %#010x\n", result);
}
TRACE_RET(result);
return result;
}
status_t
AX88772Device::_SetupAX88772()
{
size_t actualLength = 0;
// enable GPIO2 - magic from FreeBSD's if_axe
uint16 GPIOs = GPIO_OO_2EN | GPIO_IO_2 | GPIO_RSE;
result = gUSBModule->send_request(fDevice,
status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_GPIOS, GPIOs, 0, 0, 0, &actualLength);
@@ -268,25 +374,124 @@ AX88772Device::SetupDevice(bool deviceReplugged)
return result;
}
result = fMII.SetupPHY();
return B_OK;
}
status_t
AX88772Device::_WakeupPHY()
{
// select PHY
bool useEmbeddedPHY = fMII.PHYID() == PHYIDEmbedded;
uint16 selectPHY = useEmbeddedPHY ?
SW_PHY_SEL_STATUS_INT : SW_PHY_SEL_STATUS_EXT;
selectPHY |= SW_PHY_SEL_STATUS_SS_MII | SW_PHY_SEL_STATUS_SS_ENB;
size_t actualLength = 0;
status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_PHY_SEL, selectPHY, 0, 0, 0, &actualLength);
snooze(31000);
TRACE("Selecting %s PHY[%#02x].\n",
useEmbeddedPHY ? "embedded" : "external", selectPHY);
if (result != B_OK) {
TRACE_ALWAYS("Error of selecting PHY:%#010x\n", result);
return result;
}
result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_MEDIUM_MODE,
MEDIUM_STATE_FD | MEDIUM_STATE_BIT2 |
MEDIUM_STATE_RFC| MEDIUM_STATE_TFC |
MEDIUM_STATE_RE | MEDIUM_STATE_PS_100,
0, 0, 0, &actualLength);
struct SWReset {
uint16 reset;
bigtime_t delay;
} resetCommands[] = {
{ SW_RESET_IPRL | SW_RESET_IPPD, 250000 },
{ SW_RESET_IPRL, 1000000 },
{ SW_RESET_CLR, 31000 },
{ SW_RESET_IPRL, 31000 }
};
if (result != B_OK) {
TRACE_ALWAYS("Error of setting medium mode: %#010x\n", result);
for (size_t i = 0; i < _countof(resetCommands); i++) {
result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_SOFT_RESET, resetCommands[i].reset,
0, 0, 0, &actualLength);
snooze(resetCommands[i].delay);
if (result != B_OK) {
TRACE_ALWAYS("Error of SW reset command %d:[%#04x]: %#010x\n",
i, resetCommands[i].reset, result);
return result;
}
}
TRACE_RET(result);
return result;
return B_OK;
}
status_t
AX88772Device::_SetupAX88772A()
{
// Reload EEPROM
size_t actualLength = 0;
status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_GPIOS, GPIO_RSE, 0, 0, 0, &actualLength);
if (result != B_OK) {
TRACE_ALWAYS("Error of reloading EEPROM: %#010x\n", result);
return result;
}
result = _WakeupPHY();
if (result != B_OK)
return result;
result = WriteRXControlRegister(0);
if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
return result;
}
fIPG[0] = 0x15;
fIPG[1] = 0x16;
fIPG[2] = 0x1A;
return B_OK;
}
status_t
AX88772Device::_SetupAX88772B()
{
// Reload EEPROM
size_t actualLength = 0;
status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_GPIOS, GPIO_RSE, 0, 0, 0, &actualLength);
if (result != B_OK) {
TRACE_ALWAYS("Error of reloading EEPROM: %#010x\n", result);
return result;
}
result = _WakeupPHY();
if (result != B_OK)
return result;
result = WriteRXControlRegister(0);
if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
return result;
}
fIPG[0] = 0x15;
fIPG[1] = 0x16;
fIPG[2] = 0x1A;
return B_OK;
}
@@ -306,6 +511,21 @@ AX88772Device::StartDevice()
if (actualLength != sizeof(fIPG)) {
TRACE_ALWAYS("Mismatch of written IPGs data. "
"%d bytes of %d written.\n", actualLength, sizeof(fIPG));
}
// AX88772B uses different maximum frame burst configuration.
if (fDeviceInfo.fType == DeviceInfo::AX88772B) {
result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_RXCONTROL_CFG,
AX88772B_MFBTable[AX88772B_MFB_2K].ByteCount,
AX88772B_MFBTable[AX88772B_MFB_2K].Threshold,
0, 0, &actualLength);
if (result != B_OK) {
TRACE_ALWAYS("Error of writing frame burst:%#010x\n", result);
return result;
}
}
uint16 rxcontrol = RXCTL_START | RXCTL_BROADCAST;
@@ -25,6 +25,12 @@ virtual status_t SetupDevice(bool deviceReplugged);
virtual status_t StartDevice();
virtual status_t OnNotify(uint32 actualLength);
virtual status_t GetLinkState(ether_link_state *state);
virtual status_t ReadMACAddress(ether_address_t *address);
status_t _WakeupPHY();
status_t _SetupAX88772();
status_t _SetupAX88772A();
status_t _SetupAX88772B();
};
#endif // _USB_AX88772_DEVICE_H_
@@ -35,33 +35,38 @@ mutex gDriverLock;
// IMPORTANT: keep entries sorted by ids to let the
// binary search lookup procedure work correctly !!!
DeviceInfo gSupportedDevices[] = {
{ { { 0x0411, 0x003d } }, DeviceInfo::AX88172, "Melco LUA-U2-KTX" },
{ { { 0x04bb, 0x0930 } }, DeviceInfo::AX88178, "I/O Data ETG-US2" },
{ { { 0x04f1, 0x3008 } }, DeviceInfo::AX88172, "JVC MP-PRX1" },
{ { { 0x050d, 0x5055 } }, DeviceInfo::AX88178, "Belkin F5D5055" },
{ { { 0x0557, 0x2009 } }, DeviceInfo::AX88172, "ATEN UC-210T" },
{ { { 0x05ac, 0x1402 } }, DeviceInfo::AX88772, "Apple A1277" },
{ { { 0x077b, 0x2226 } }, DeviceInfo::AX88172, "LinkSys USB 2.0" },
{ { { 0x07aa, 0x0017 } }, DeviceInfo::AX88172, "Corega USB2TX" },
{ { { 0x07b8, 0x420a } }, DeviceInfo::AX88172, "ABOCOM UF200" },
{ { { 0x07d1, 0x3c05 } }, DeviceInfo::AX88772, "D-Link DUB-E100 rev.B1" },
{ { { 0x0846, 0x1040 } }, DeviceInfo::AX88172, "NetGear USB 2.0 Ethernet" },
{ { { 0x086e, 0x1920 } }, DeviceInfo::AX88172, "System TALKS SGC-X2UL" },
{ { { 0x08dd, 0x90ff } }, DeviceInfo::AX88172, "Billionton USB2AR" },
{ { { 0x0b95, 0x1720 } }, DeviceInfo::AX88172, "ASIX 88172 10/100" },
{ { { 0x0b95, 0x1780 } }, DeviceInfo::AX88178, "ASIX 88178 10/100/1000" },
{ { { 0x0b95, 0x7720 } }, DeviceInfo::AX88772, "ASIX 88772 10/100" },
{ { { 0x0df6, 0x061c } }, DeviceInfo::AX88178, "Sitecom LN-028" },
{ { { 0x1189, 0x0893 } }, DeviceInfo::AX88172, "Acer C&M EP-1427X-2" },
{ { { 0x13b1, 0x0018 } }, DeviceInfo::AX88772, "Linksys USB200M rev.2" },
{ { { 0x14ea, 0xab11 } }, DeviceInfo::AX88178, "Planex GU-1000T" },
{ { { 0x1557, 0x7720 } }, DeviceInfo::AX88772, "OQO 01+ Ethernet" },
{ { { 0x1631, 0x6200 } }, DeviceInfo::AX88172, "GoodWay USB2Ethernet" },
{ { { 0x1737, 0x0039 } }, DeviceInfo::AX88178, "LinkSys 1000" },
{ { { 0x2001, 0x1A00 } }, DeviceInfo::AX88172, "D-Link DUB-E100" },
{ { { 0x2001, 0x3c05 } }, DeviceInfo::AX88772, "D-Link DUB-E100 rev.B1" },
{ { { 0x6189, 0x182d } }, DeviceInfo::AX88172, "Sitecom LN-029" }
};
{ { 0x0411, 0x003d }, DeviceInfo::AX88172, "Melco LUA-U2-KTX" },
{ { 0x0411, 0x006e }, DeviceInfo::AX88178, "Melco LUA3-U2-AGT" },
{ { 0x04bb, 0x0930 }, DeviceInfo::AX88178, "I/O Data ETG-US2" },
{ { 0x04f1, 0x3008 }, DeviceInfo::AX88172, "JVC MP-PRX1" },
{ { 0x050d, 0x5055 }, DeviceInfo::AX88178, "Belkin F5D5055" },
{ { 0x0557, 0x2009 }, DeviceInfo::AX88172, "ATEN UC-210T" },
{ { 0x05ac, 0x1402 }, DeviceInfo::AX88772, "Apple A1277" },
{ { 0x077b, 0x2226 }, DeviceInfo::AX88172, "LinkSys USB 2.0" },
{ { 0x0789, 0x0160 }, DeviceInfo::AX88178, "Logitec LAN-GTJ/U2A" },
{ { 0x07aa, 0x0017 }, DeviceInfo::AX88172, "Corega USB2TX" },
{ { 0x07b8, 0x420a }, DeviceInfo::AX88172, "ABOCOM UF200" },
{ { 0x07d1, 0x3c05 }, DeviceInfo::AX88772, "D-Link DUB-E100 rev.B1" },
{ { 0x0846, 0x1040 }, DeviceInfo::AX88172, "NetGear USB 2.0 Ethernet" },
{ { 0x086e, 0x1920 }, DeviceInfo::AX88172, "System TALKS SGC-X2UL" },
{ { 0x08dd, 0x90ff }, DeviceInfo::AX88172, "Billionton USB2AR" },
{ { 0x0b95, 0x1720 }, DeviceInfo::AX88172, "ASIX 88172 10/100" },
{ { 0x0b95, 0x1780 }, DeviceInfo::AX88178, "ASIX 88178 10/100/1000" },
{ { 0x0b95, 0x7720 }, DeviceInfo::AX88772, "ASIX 88772 10/100" },
{ { 0x0b95, 0x772a }, DeviceInfo::AX88772A, "AX88772A 10/100" },
{ { 0x0b95, 0x772b }, DeviceInfo::AX88772B, "AX88772B 10/100" },
{ { 0x0b95, 0x7e2b }, DeviceInfo::AX88772B, "AX88772B 10/100" },
{ { 0x0df6, 0x061c }, DeviceInfo::AX88178, "Sitecom LN-028" },
{ { 0x1189, 0x0893 }, DeviceInfo::AX88172, "Acer C&M EP-1427X-2" },
{ { 0x13b1, 0x0018 }, DeviceInfo::AX88772A, "Linksys USB200M rev.2" },
{ { 0x14ea, 0xab11 }, DeviceInfo::AX88178, "Planex GU-1000T" },
{ { 0x1557, 0x7720 }, DeviceInfo::AX88772, "OQO 01+ Ethernet" },
{ { 0x1631, 0x6200 }, DeviceInfo::AX88172, "GoodWay USB2Ethernet" },
{ { 0x1737, 0x0039 }, DeviceInfo::AX88178, "LinkSys 1000" },
{ { 0x2001, 0x1A00 }, DeviceInfo::AX88172, "D-Link DUB-E100" },
{ { 0x2001, 0x3c05 }, DeviceInfo::AX88772, "D-Link DUB-E100 rev.B1" },
{ { 0x6189, 0x182d }, DeviceInfo::AX88172, "Sitecom LN-029" }
};
ASIXDevice *
@@ -75,24 +80,26 @@ lookup_and_create_device(usb_device device)
return NULL;
}
TRACE("trying %#06x:%#06x.\n",
TRACE("trying %#06x:%#06x.\n",
deviceDescriptor->vendor_id, deviceDescriptor->product_id);
// use binary search to lookup device in table
DeviceInfo::Id id = { { deviceDescriptor->vendor_id,
deviceDescriptor->product_id } };
uint32 id = deviceDescriptor->vendor_id << 16
| deviceDescriptor->product_id;
int left = -1;
int right = _countof(gSupportedDevices);
while ((right - left) > 1) {
int i = (left + right) / 2;
((gSupportedDevices[i].Key() < id.fKey) ? left : right) = i;
((gSupportedDevices[i].Key() < id) ? left : right) = i;
}
if (gSupportedDevices[right].Key() == id.fKey) {
if (gSupportedDevices[right].Key() == id) {
switch (gSupportedDevices[right].fType) {
case DeviceInfo::AX88172:
return new AX88172Device(device, gSupportedDevices[right]);
case DeviceInfo::AX88772:
case DeviceInfo::AX88772A:
case DeviceInfo::AX88772B:
return new AX88772Device(device, gSupportedDevices[right]);
case DeviceInfo::AX88178:
return new AX88178Device(device, gSupportedDevices[right]);
@@ -101,6 +108,8 @@ lookup_and_create_device(usb_device device)
static_cast<int>(gSupportedDevices[right].fType));
break;
}
} else {
TRACE_ALWAYS("Search for %#x failed %d-%d.\n", id, left, right);
}
return NULL;
@@ -224,7 +233,7 @@ init_driver()
const size_t count = _countof(gSupportedDevices);
static usb_support_descriptor sDescriptors[count] = {{ 0 }};
for(size_t i = 0; i < count; i++) {
for (size_t i = 0; i < count; i++) {
sDescriptors[i].vendor = gSupportedDevices[i].VendorId();
sDescriptors[i].product = gSupportedDevices[i].ProductId();
}
@@ -22,7 +22,7 @@
const uint8 kInvalidRequest = 0xff;
const char* const kVersion = "ver.0.9.1";
const char* const kVersion = "ver.0.10.1";
extern usb_module_info *gUSBModule;