1 /* 2 * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. 3 * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li> 4 * Distributed under the terms of the MIT license. 5 * 6 * Heavily based on code of the 7 * Driver for USB Ethernet Control Model devices 8 * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> 9 * Distributed under the terms of the MIT license. 10 * 11 */ 12 13 14 #include "AX88178Device.h" 15 16 #include <net/if_media.h> 17 18 #include "ASIXVendorRequests.h" 19 #include "Settings.h" 20 21 22 // Most of vendor requests for all supported chip types use the same 23 // constants (see ASIXVendorRequests.h) but the layout of request data 24 // may be slightly diferrent for specific chip type. Below is a quick 25 // reference for AX88178 vendor requests data layout. 26 27 // READ_RXTX_SRAM, //C002_AA0B_0C00_0800 Rx/Tx SRAM Read 28 // WRITE_RXTX_SRAM, //4003_AA0B_0C00_0800 Rx/Tx SRAM Write 29 // SW_MII_OP, //4006_0000_0000_0000 SW Serial Management Control 30 // READ_MII, //c007_aa00_cc00_0200 PHY Read 31 // WRITE_MII, //4008_aa00_cc00_0200 PHY Write 32 // READ_MII_STATUS, //c009_0000_0000_0100 Serial Management Status 33 // HW_MII_OP, //400a_0000_0000_0000 HW Serial Management Control 34 // READ_SROM, //C00B_AA00_0000_0200 SROM Read 35 // WRITE_SROM, //400C_AA00_CCDD_0000 SROM Write 36 // WRITE_SROM_ENABLE, //400D_0000_0000_0000 SROM Write Enable 37 // WRITE_SROM_DISABLE, //400E_0000_0000_0000 SROM Write Disable 38 // READ_RX_CONTROL, //C00F_0000_0000_0200 Read Rx Control 39 // WRITE_RX_CONTROL, //4010_AABB_0000_0000 Write Rx Control 40 // READ_IPGS, //C011_0000_0000_0300 Read IPG/IPG1/IPG2 Register 41 // WRITE_IPGS, //4012_AABB_CC00_0000 Write IPG/IPG1/IPG2 Register 42 // READ_NODEID, //C013_0000_0000_0600 Read Node ID 43 // WRITE_NODEID, //4014_0000_0000_0600 Write Node ID 44 // READ_MF_ARRAY, //C015_0000_0000_0800 Read Multicast Filter Array 45 // WRITE_MF_ARRAY, //4016_0000_0000_0800 Write Multicast Filter Array 46 // READ_TEST, //4017_AA00_0000_0000 Write Test Register 47 // READ_PHYID, //C019_0000_0000_0200 Read Ethernet/HomePNA PHY Address 48 // READ_MEDIUM_STATUS, //C01A_0000_0000_0200 Read Medium Status 49 // WRITE_MEDIUM_MODE, //401B_AABB_0000_0000 Write Medium Mode Register 50 // GET_MONITOR_MODE, //C01C_0000_0000_0100 Read Monitor Mode Status 51 // SET_MONITOR_MODE, //401D_AA00_0000_0000 Write Monitor Mode Register 52 // READ_GPIOS, //C01E_0000_0000_0100 Read GPIOs Status 53 // WRITE_GPIOS, //401F_AA00_0000_0000 Write GPIOs 54 // WRITE_SOFT_RESET, //4020_AA00_0000_0000 Write Software Reset 55 // READ_MIIS_IF_STATE, //C021_AA00_0000_0100 Read MII/GMII/RGMII Iface Status 56 // WRITE_MIIS_IF_STATE, //4022_AA00_0000_0000 Write MII/GMII/RGMII Iface Control 57 58 // RX Control Register bits 59 // RXCTL_PROMISCUOUS, // forward all frames up to the host 60 // RXCTL_ALL_MULTICAT, // forward all multicast frames up to the host 61 // RXCTL_SEP, // forward frames with CRC error up to the host 62 // RXCTL_BROADCAST, // forward broadcast frames up to the host 63 // RXCTL_MULTICAST, // forward multicast frames that are 64 // matching to multicast filter up to the host 65 // RXCTL_AP, // forward unicast frames that are matching 66 // to multicast filter up to the host 67 // RXCTL_START, // ethernet MAC start operating 68 // RXCTL_USB_MFB, // Max Frame Burst TX on USB 69 70 71 // PHY IDs request answer data layout 72 struct AX88178_PhyIDs { 73 uint8 SecPhyID; 74 uint8 PriPhyID2; 75 } _PACKED; 76 77 78 // Medium state bits 79 enum AX88178_MediumState { 80 MEDIUM_STATE_GM = 0x0001, 81 MEDIUM_STATE_FD = 0x0002, 82 MEDIUM_STATE_AC = 0x0004, // must be always set 83 MEDIUM_STATE_ENCK = 0x0008, 84 MEDIUM_STATE_RFC = 0x0010, 85 MEDIUM_STATE_TFC = 0x0020, 86 MEDIUM_STATE_JFE = 0x0040, 87 MEDIUM_STATE_PF_ON = 0x0080, 88 MEDIUM_STATE_PF_OFF = 0x0000, 89 MEDIUM_STATE_RE = 0x0100, 90 MEDIUM_STATE_PS_100 = 0x0200, 91 MEDIUM_STATE_PS_10 = 0x0000, 92 MEDIUM_STATE_SBP1 = 0x0800, 93 MEDIUM_STATE_SBP0 = 0x0000, 94 MEDIUM_STATE_SM_ON = 0x1000 95 }; 96 97 98 // Monitor Mode bits 99 enum AX88178_MonitorMode { 100 MONITOR_MODE_MOM = 0x01, 101 MONITOR_MODE_RWLU = 0x02, 102 MONITOR_MODE_RWMP = 0x04, 103 MONITOR_MODE_US = 0x10 104 }; 105 106 107 // General Purpose I/O Register 108 enum AX88178_GPIO { 109 GPIO_OO_0EN = 0x01, 110 GPIO_IO_0 = 0x02, 111 GPIO_OO_1EN = 0x04, 112 GPIO_IO_1 = 0x08, 113 GPIO_OO_2EN = 0x10, 114 GPIO_IO_2 = 0x20, 115 GPIO_RSE = 0x80 116 }; 117 118 119 // Software Reset Register bits 120 enum AX88178_SoftwareReset { 121 SW_RESET_RR = 0x01, 122 SW_RESET_RT = 0x02, 123 SW_RESET_PRTE = 0x04, 124 SW_RESET_PRL = 0x08, 125 SW_RESET_BZ = 0x10, 126 SW_RESET_BIT6 = 0x40 // always set to 1 127 }; 128 129 130 // MII/GMII/RGMII Interface Conttrol 131 enum AX88178_MIISInterfaceStatus { 132 MIIS_IF_STATE_DM = 0x01, 133 MIIS_IF_STATE_RB = 0x02 134 }; 135 136 137 // Notification data layout 138 struct AX88178_Notify { 139 uint8 btA1; 140 uint8 bt01; 141 uint8 btBB; // AX88178_BBState below 142 uint8 bt03; 143 uint16 regCCDD; 144 uint16 regEEFF; 145 } _PACKED; 146 147 148 // Link-State bits 149 enum AX88178_BBState { 150 LINK_STATE_PPLS = 0x01, 151 LINK_STATE_SPLS = 0x02, 152 LINK_STATE_FLE = 0x04, 153 LINK_STATE_MDINT = 0x08 154 }; 155 156 157 const uint16 maxFrameSize = 1536; 158 159 160 AX88178Device::AX88178Device(usb_device device, DeviceInfo& deviceInfo) 161 : 162 ASIXDevice(device, deviceInfo) 163 { 164 fStatus = InitDevice(); 165 } 166 167 168 status_t 169 AX88178Device::InitDevice() 170 { 171 fFrameSize = maxFrameSize; 172 fUseTRXHeader = true; 173 174 fReadNodeIDRequest = READ_NODEID; 175 176 fNotifyBufferLength = sizeof(AX88178_Notify); 177 fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength); 178 if (fNotifyBuffer == NULL) { 179 TRACE_ALWAYS("Error of allocating memory for notify buffer.\n"); 180 return B_NO_MEMORY; 181 } 182 183 TRACE_RET(B_OK); 184 return B_OK; 185 } 186 187 188 status_t 189 AX88178Device::SetupDevice(bool deviceReplugged) 190 { 191 status_t result = ASIXDevice::SetupDevice(deviceReplugged); 192 if (result != B_OK) { 193 return result; 194 } 195 196 result = fMII.Init(fDevice); 197 198 if (result != B_OK) { 199 return result; 200 } 201 202 size_t actualLength = 0; 203 // get the "magic" word from EEPROM 204 result = gUSBModule->send_request(fDevice, 205 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SROM_ENABLE, 206 0, 0, 0, 0, &actualLength); 207 208 if (result != B_OK) { 209 TRACE_ALWAYS("Error of enabling SROM access:%#010x\n", result); 210 return result; 211 } 212 213 uint16 eepromData = 0; 214 status_t op_result = gUSBModule->send_request(fDevice, 215 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, READ_SROM, 216 0x17, 0, sizeof(eepromData), &eepromData, &actualLength); 217 218 if (op_result != B_OK) { 219 TRACE_ALWAYS("Error of reading SROM data:%#010x\n", result); 220 } 221 222 if (actualLength != sizeof(eepromData)) { 223 TRACE_ALWAYS("Mismatch of reading SROM data." 224 "Read %d bytes instead of %d\n", actualLength, sizeof(eepromData)); 225 } 226 227 result = gUSBModule->send_request(fDevice, 228 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SROM_DISABLE, 229 0, 0, 0, 0, &actualLength); 230 231 if (result != B_OK) { 232 TRACE_ALWAYS("Error of disabling SROM access: %#010x\n", result); 233 return result; 234 } 235 236 if (op_result != B_OK) { 237 return op_result; 238 } 239 240 // some shaman's dances with GPIO 241 struct GPIOData { 242 bigtime_t delay; 243 uint16 value; 244 } GPIOCommands[] = { 245 // eeprom bit 8 is off 246 { 40000 , GPIO_OO_1EN | GPIO_IO_1 | GPIO_RSE }, 247 { 30000 , GPIO_OO_2EN | GPIO_IO_2 | GPIO_OO_1EN | GPIO_IO_1 }, 248 { 300000 , GPIO_OO_2EN | GPIO_OO_1EN | GPIO_IO_1 }, 249 { 30000 , GPIO_OO_2EN | GPIO_IO_2 | GPIO_OO_1EN | GPIO_IO_1 }, 250 // eeprom bit 8 is on 251 { 40000 , GPIO_OO_1EN | GPIO_IO_1 | GPIO_RSE }, 252 { 30000 , GPIO_OO_1EN }, 253 { 30000 , GPIO_OO_1EN | GPIO_IO_1 }, 254 }; 255 256 bool bCase8 = (eepromData >> 8) != 1; 257 size_t from = bCase8 ? 0 : 4; 258 size_t to = bCase8 ? 3 : 6; 259 260 for (size_t i = from; i <= to; i++) { 261 result = gUSBModule->send_request(fDevice, 262 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_GPIOS, 263 GPIOCommands[i].value, 0, 0, 0, &actualLength); 264 265 snooze(GPIOCommands[i].delay); 266 267 if (result != B_OK) { 268 TRACE_ALWAYS("Error of GPIO setup command %d:[%#04x]: %#010x\n", 269 i, GPIOCommands[i].value, result); 270 return result; 271 } 272 } 273 274 uint8 uSWReset = 0; 275 // finally a bit of exercises for SW reset register... 276 result = gUSBModule->send_request(fDevice, 277 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SOFT_RESET, 278 uSWReset, 0, 0, 0, &actualLength); 279 280 if (result != B_OK) { 281 TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset, result); 282 return result; 283 } 284 285 snooze(150000); 286 287 uSWReset = SW_RESET_PRL | SW_RESET_BIT6; 288 result = gUSBModule->send_request(fDevice, 289 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SOFT_RESET, 290 uSWReset, 0, 0, 0, &actualLength); 291 292 if (result != B_OK) { 293 TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset, result); 294 return result; 295 } 296 297 snooze(150000); 298 299 result = WriteRXControlRegister(0); 300 if (result != B_OK) { 301 TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result); 302 return result; 303 } 304 305 result = fMII.SetupPHY(); 306 307 TRACE_RET(result); 308 return result; 309 } 310 311 312 status_t 313 AX88178Device::StartDevice() 314 { 315 size_t actualLength = 0; 316 status_t result = gUSBModule->send_request(fDevice, 317 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_IPGS, 318 0, 0, sizeof(fIPG), fIPG, &actualLength); 319 320 if (result != B_OK) { 321 TRACE_ALWAYS("Error of writing IPGs:%#010x\n", result); 322 return result; 323 } 324 325 if (actualLength != sizeof(fIPG)) { 326 TRACE_ALWAYS("Mismatch of written IPGs data. " 327 "%d bytes of %d written.\n", actualLength, sizeof(fIPG)); 328 } 329 330 uint16 rxcontrol = RXCTL_START | RXCTL_BROADCAST; 331 result = WriteRXControlRegister(rxcontrol); 332 if (result != B_OK) { 333 TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 334 rxcontrol, result); 335 } 336 337 TRACE_RET(result); 338 return result; 339 } 340 341 342 status_t 343 AX88178Device::OnNotify(uint32 actualLength) 344 { 345 if (actualLength < sizeof(AX88178_Notify)) { 346 TRACE_ALWAYS("Data underrun error. %d of %d bytes received\n", 347 actualLength, sizeof(AX88178_Notify)); 348 return B_BAD_DATA; 349 } 350 351 AX88178_Notify *notification = (AX88178_Notify *)fNotifyBuffer; 352 353 if (notification->btA1 != 0xa1) { 354 TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n", 355 notification->btA1); 356 } 357 358 uint phyIndex = 0; 359 bool linkIsUp = fHasConnection; 360 switch(fMII.ActivePHY()) { 361 case PrimaryPHY: 362 phyIndex = 1; 363 linkIsUp = (notification->btBB & LINK_STATE_PPLS) 364 == LINK_STATE_PPLS; 365 break; 366 case SecondaryPHY: 367 phyIndex = 2; 368 linkIsUp = (notification->btBB & LINK_STATE_SPLS) 369 == LINK_STATE_SPLS; 370 break; 371 default: 372 case CurrentPHY: 373 TRACE_ALWAYS("Error: PHY is not initialized.\n"); 374 return B_NO_INIT; 375 } 376 377 bool linkStateChange = linkIsUp != fHasConnection; 378 fHasConnection = linkIsUp; 379 380 if (linkStateChange) { 381 TRACE("Link state of PHY%d has been changed to '%s'\n", 382 phyIndex, fHasConnection ? "up" : "down"); 383 } 384 385 if (linkStateChange && fLinkStateChangeSem >= B_OK) 386 release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); 387 388 return B_OK; 389 } 390 391 392 status_t 393 AX88178Device::GetLinkState(ether_link_state *linkState) 394 { 395 size_t actualLength = 0; 396 uint16 mediumStatus = 0; 397 status_t result = gUSBModule->send_request(fDevice, 398 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, READ_MEDIUM_STATUS, 399 0, 0, sizeof(mediumStatus), &mediumStatus, &actualLength); 400 401 if (result != B_OK) { 402 TRACE_ALWAYS("Error of reading medium status:%#010x.\n", result); 403 return result; 404 } 405 406 if (actualLength != sizeof(mediumStatus)) { 407 TRACE_ALWAYS("Mismatch of reading medium status." 408 "Read %d bytes instead of %d\n", 409 actualLength, sizeof(mediumStatus)); 410 } 411 412 TRACE_FLOW("Medium status is %#04x\n", mediumStatus); 413 414 linkState->quality = 1000; 415 416 linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0); 417 linkState->media |= (mediumStatus & MEDIUM_STATE_FD) 418 ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX; 419 420 linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100) 421 ? 100000000 : 10000000; 422 linkState->speed = (mediumStatus & MEDIUM_STATE_GM) 423 ? 1000000000 : linkState->speed; 424 425 TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n", 426 (linkState->media & IFM_ACTIVE) ? "active" : "inactive", 427 linkState->speed / 1000000, 428 (linkState->media & IFM_FULL_DUPLEX) ? "full" : "half"); 429 return B_OK; 430 } 431