From 6ef455e4a2b600012dbbad09883708255d8f66f4 Mon Sep 17 00:00:00 2001 From: Siarzhuk Zharski Date: Sat, 24 Dec 2011 20:09:10 +0000 Subject: [PATCH] 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. --- .../drivers/network/usb_asix/ASIXDevice.h | 19 +- .../network/usb_asix/ASIXVendorRequests.h | 3 +- .../network/usb_asix/AX88772Device.cpp | 252 ++++++++++++++++-- .../drivers/network/usb_asix/AX88772Device.h | 6 + .../drivers/network/usb_asix/Driver.cpp | 77 +++--- .../kernel/drivers/network/usb_asix/Driver.h | 2 +- 6 files changed, 297 insertions(+), 62 deletions(-) diff --git a/src/add-ons/kernel/drivers/network/usb_asix/ASIXDevice.h b/src/add-ons/kernel/drivers/network/usb_asix/ASIXDevice.h index af8be00be0..e932a377ab 100644 --- a/src/add-ons/kernel/drivers/network/usb_asix/ASIXDevice.h +++ b/src/add-ons/kernel/drivers/network/usb_asix/ASIXDevice.h @@ -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; diff --git a/src/add-ons/kernel/drivers/network/usb_asix/ASIXVendorRequests.h b/src/add-ons/kernel/drivers/network/usb_asix/ASIXVendorRequests.h index 59ec0ec61c..d383368a45 100644 --- a/src/add-ons/kernel/drivers/network/usb_asix/ASIXVendorRequests.h +++ b/src/add-ons/kernel/drivers/network/usb_asix/ASIXVendorRequests.h @@ -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 }; diff --git a/src/add-ons/kernel/drivers/network/usb_asix/AX88772Device.cpp b/src/add-ons/kernel/drivers/network/usb_asix/AX88772Device.cpp index 6f644c581d..728917fe66 100644 --- a/src/add-ons/kernel/drivers/network/usb_asix/AX88772Device.cpp +++ b/src/add-ons/kernel/drivers/network/usb_asix/AX88772Device.cpp @@ -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; diff --git a/src/add-ons/kernel/drivers/network/usb_asix/AX88772Device.h b/src/add-ons/kernel/drivers/network/usb_asix/AX88772Device.h index 0fd70a6685..7f1480e1f0 100644 --- a/src/add-ons/kernel/drivers/network/usb_asix/AX88772Device.h +++ b/src/add-ons/kernel/drivers/network/usb_asix/AX88772Device.h @@ -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_ diff --git a/src/add-ons/kernel/drivers/network/usb_asix/Driver.cpp b/src/add-ons/kernel/drivers/network/usb_asix/Driver.cpp index ef397ef6c7..b7aa8e687b 100644 --- a/src/add-ons/kernel/drivers/network/usb_asix/Driver.cpp +++ b/src/add-ons/kernel/drivers/network/usb_asix/Driver.cpp @@ -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(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(); } diff --git a/src/add-ons/kernel/drivers/network/usb_asix/Driver.h b/src/add-ons/kernel/drivers/network/usb_asix/Driver.h index 9ff1ece038..ea4e30920c 100644 --- a/src/add-ons/kernel/drivers/network/usb_asix/Driver.h +++ b/src/add-ons/kernel/drivers/network/usb_asix/Driver.h @@ -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;