1 /* 2 * Davicom DM9601 USB 1.1 Ethernet Driver. 3 * Copyright (c) 2008, 2011 Siarzhuk Zharski <imker@gmx.li> 4 * Copyright (c) 2009 Adrien Destugues <pulkomandy@gmail.com> 5 * Distributed under the terms of the MIT license. 6 * 7 * Heavily based on code of the 8 * Driver for USB Ethernet Control Model devices 9 * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> 10 * Distributed under the terms of the MIT license. 11 */ 12 13 14 #include "DavicomDevice.h" 15 16 #include <stdio.h> 17 #include <net/if_media.h> 18 19 #include "Driver.h" 20 #include "Settings.h" 21 22 23 const int kFrameSize = 1522; 24 25 enum VendorRequests { 26 ReqReadRegister = 0, 27 ReqWriteRegister = 1, 28 ReqWriteRegisterByte = 3, 29 }; 30 31 32 enum DM9601Registers { 33 RegNCR = 0x00, // Network Control Register 34 NCRExtPHY = 0x80, // Select External PHY 35 NCRFullDX = 0x08, // Full duplex 36 NCRLoopback = 0x06, // Internal PHY analog loopback 37 38 RegNSR = 0x01, // Network Status Register 39 NSRSpeed10 = 0x80, // 0 = 100MBps, 1 = 10MBps (internal PHY) 40 NSRLinkUp = 0x40, // 1 = link up (internal PHY) 41 NSRTXFull = 0x10, // TX FIFO full 42 NSRRXOver = 0x08, // RX FIFO overflow 43 44 RegRCR = 0x05, // RX Control Register 45 RCRDiscardLong = 0x20, // Discard long packet (over 1522 bytes) 46 RCRDiscardCRC = 0x10, // Discard CRC error packet 47 RCRAllMulticast = 0x08, // Pass all multicast 48 RCRPromiscuous = 0x02, // Promiscuous 49 RCRRXEnable = 0x01, // RX enable 50 51 RegEPCR = 0x0b, // EEPROM & PHY Control Register 52 EPCROpSelect = 0x08, // EEPROM or PHY Operation Select 53 EPCRRegRead = 0x04, // EEPROM or PHY Register Read Command 54 EPCRRegWrite = 0x02, // EEPROM or PHY Register Write Command 55 56 RegEPAR = 0x0c, // EEPROM & PHY Address Register 57 EPARIntPHY = 0x40, // [7:6] force to 01 if Internal PHY is selected 58 EPARMask = 0x1f, // mask [0:5] 59 60 RegEPDRL = 0x0d, // EEPROM & PHY Low Byte Data Register 61 62 RegEPDRH = 0x0e, // EEPROM & PHY Low Byte Data Register 63 64 RegPAR = 0x10, // [0x10 - 0x15] Physical Address Register 65 66 RegMAR = 0x16, // [0x16 - 0x1d] Multicast Address Register 67 68 RegGPCR = 0x1E, // General Purpose Control Register 69 GPCRPowerDown = 0x01, // [0:6] Define in/out direction of GPCR 70 // GPIO0 - is output for Power Down function 71 72 RegGPR = 0x1F, // General Purpose Register 73 GPRPowerDownInPHY = 0x01, // Power down Internal PHY 74 75 RegUSBC = 0xf4, // USB Control Register 76 USBCIntAck = 0x20, // ACK with 8-bytes of data on interrupt EP 77 USBCIntNAck = 0x10, // Supress ACK on interrupt EP 78 79 }; 80 81 82 enum MIIRegisters { 83 RegBMCR = 0x00, 84 BMCRIsolate = 0x0400, 85 BMCRReset = 0x8000, 86 87 RegBMSR = 0x01, 88 RegPHYID1 = 0x02, 89 RegPHYID2 = 0x03, 90 }; 91 92 #define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10)) 93 #define MII_MODEL(id2) (((id2) & 0x03f0) >> 4) 94 #define MII_REV(id2) ((id2) & 0x000f) 95 96 97 DavicomDevice::DavicomDevice(usb_device device, DeviceInfo& deviceInfo) 98 : fDevice(device), 99 fStatus(B_ERROR), 100 fOpen(false), 101 fRemoved(false), 102 fHasConnection(false), 103 fTXBufferFull(false), 104 fNonBlocking(false), 105 fInsideNotify(0), 106 fNotifyEndpoint(0), 107 fReadEndpoint(0), 108 fWriteEndpoint(0), 109 fMaxTXPacketSize(0), 110 fActualLengthRead(0), 111 fActualLengthWrite(0), 112 fStatusRead(0), 113 fStatusWrite(0), 114 fNotifyReadSem(-1), 115 fNotifyWriteSem(-1), 116 fLinkStateChangeSem(-1), 117 fNotifyData(NULL) 118 { 119 fDeviceInfo = deviceInfo; 120 121 memset(&fMACAddress, 0, sizeof(fMACAddress)); 122 123 fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read"); 124 if (fNotifyReadSem < B_OK) { 125 TRACE_ALWAYS("Error of creating read notify semaphore:%#010x\n", 126 fNotifyReadSem); 127 return; 128 } 129 130 fNotifyWriteSem = create_sem(0, DRIVER_NAME"_notify_write"); 131 if (fNotifyWriteSem < B_OK) { 132 TRACE_ALWAYS("Error of creating write notify semaphore:%#010x\n", 133 fNotifyWriteSem); 134 return; 135 } 136 137 fNotifyData = new DM9601NotifyData(); 138 if (fNotifyData == NULL) { 139 TRACE_ALWAYS("Error allocating notify buffer\n"); 140 return; 141 } 142 143 if (_SetupEndpoints() != B_OK) { 144 return; 145 } 146 147 _InitMII(); 148 149 fStatus = B_OK; 150 TRACE("Created!\n"); 151 } 152 153 154 DavicomDevice::~DavicomDevice() 155 { 156 if (fNotifyReadSem >= B_OK) 157 delete_sem(fNotifyReadSem); 158 if (fNotifyWriteSem >= B_OK) 159 delete_sem(fNotifyWriteSem); 160 161 if (!fRemoved) // ??? 162 gUSBModule->cancel_queued_transfers(fNotifyEndpoint); 163 164 delete fNotifyData; 165 TRACE("Deleted!\n"); 166 } 167 168 169 status_t 170 DavicomDevice::Open(uint32 flags) 171 { 172 if (fOpen) 173 return B_BUSY; 174 if (fRemoved) 175 return B_ERROR; 176 177 status_t result = _StartDevice(); 178 if (result != B_OK) { 179 return result; 180 } 181 182 // setup state notifications 183 result = gUSBModule->queue_interrupt(fNotifyEndpoint, fNotifyData, 184 sizeof(DM9601NotifyData), _NotifyCallback, this); 185 if (result != B_OK) { 186 TRACE_ALWAYS("Error of requesting notify interrupt:%#010x\n", result); 187 return result; 188 } 189 190 result = _EnableInterrupts(true); 191 192 fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK; 193 fOpen = true; 194 TRACE("Opened: %#010x!\n", result); 195 return result; 196 } 197 198 199 status_t 200 DavicomDevice::Close() 201 { 202 if (fRemoved) { 203 fOpen = false; 204 return B_OK; 205 } 206 207 _EnableInterrupts(false); 208 209 // wait until possible notification handling finished... 210 while (atomic_add(&fInsideNotify, 0) != 0) 211 snooze(100); 212 gUSBModule->cancel_queued_transfers(fNotifyEndpoint); 213 gUSBModule->cancel_queued_transfers(fReadEndpoint); 214 gUSBModule->cancel_queued_transfers(fWriteEndpoint); 215 216 fOpen = false; 217 218 status_t result = _StopDevice(); 219 TRACE("Closed: %#010x!\n", result); 220 return result; 221 } 222 223 224 status_t 225 DavicomDevice::Free() 226 { 227 TRACE("Freed!\n"); 228 return B_OK; 229 } 230 231 232 status_t 233 DavicomDevice::Read(uint8 *buffer, size_t *numBytes) 234 { 235 size_t numBytesToRead = *numBytes; 236 *numBytes = 0; 237 238 if (fRemoved) { 239 TRACE_ALWAYS("Error of receiving %d bytes from removed device.\n", 240 numBytesToRead); 241 return B_DEVICE_NOT_FOUND; 242 } 243 244 TRACE_RX("Request %d bytes.\n", numBytesToRead); 245 246 struct _RXHeader { 247 uint FOE :1; 248 uint CE :1; 249 uint LE :1; 250 uint PLE :1; 251 uint RWTO:1; 252 uint LCS :1; 253 uint MF :1; 254 uint RF :1; 255 uint countLow :8; 256 uint countHigh :8; 257 258 uint8 Errors() { return 0xbf & *(uint8*)this; } 259 } __attribute__((__packed__)); 260 261 _RXHeader header = { 0 }; 262 263 iovec rxData[] = { 264 { &header, sizeof(header) }, 265 { buffer, numBytesToRead } 266 }; 267 268 status_t result = gUSBModule->queue_bulk_v(fReadEndpoint, 269 rxData, 2, _ReadCallback, this); 270 if (result != B_OK) { 271 TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result); 272 return result; 273 } 274 275 uint32 flags = B_CAN_INTERRUPT | (fNonBlocking ? B_TIMEOUT : 0); 276 result = acquire_sem_etc(fNotifyReadSem, 1, flags, 0); 277 if (result < B_OK) { 278 TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result); 279 return result; 280 } 281 282 if (fStatusRead != B_OK && fStatusRead != B_CANCELED && !fRemoved) { 283 TRACE_ALWAYS("Device status error:%#010x\n", fStatusRead); 284 return fStatusRead; 285 } 286 287 if (fActualLengthRead < sizeof(_RXHeader)) { 288 TRACE_ALWAYS("Error: no place for RXHeader: only %d of %d bytes.\n", 289 fActualLengthRead, sizeof(_RXHeader)); 290 return B_ERROR; 291 } 292 293 if (header.Errors() != 0) { 294 TRACE_ALWAYS("RX header errors %#04x detected!\n", header.Errors()); 295 } 296 297 TRACE_STATS("FOE:%d CE:%d LE:%d PLE:%d rwTO:%d LCS:%d MF:%d RF:%d\n", 298 header.FOE, header.CE, header.LE, header.PLE, 299 header.RWTO, header.LCS, header.MF, header.RF); 300 301 *numBytes = header.countLow | ( header.countHigh << 8 ); 302 303 if (fActualLengthRead - sizeof(_RXHeader) > *numBytes) { 304 TRACE_ALWAYS("MISMATCH of the frame length: hdr %d; received:%d\n", 305 *numBytes, fActualLengthRead - sizeof(_RXHeader)); 306 } 307 308 TRACE_RX("Read %d bytes.\n", *numBytes); 309 return B_OK; 310 } 311 312 313 status_t 314 DavicomDevice::Write(const uint8 *buffer, size_t *numBytes) 315 { 316 size_t numBytesToWrite = *numBytes; 317 *numBytes = 0; 318 319 if (fRemoved) { 320 TRACE_ALWAYS("Error of writing %d bytes to removed device.\n", 321 numBytesToWrite); 322 return B_DEVICE_NOT_FOUND; 323 } 324 325 if (!fHasConnection) { 326 TRACE_ALWAYS("Error of writing %d bytes to device while down.\n", 327 numBytesToWrite); 328 return B_ERROR; 329 } 330 331 if (fTXBufferFull) { 332 TRACE_ALWAYS("Error of writing %d bytes to device: TX buffer full.\n", 333 numBytesToWrite); 334 return B_ERROR; 335 } 336 337 TRACE_TX("Write %d bytes.\n", numBytesToWrite); 338 339 // additional padding byte must be transmitted in case data size 340 // to be send is multiple of pipe's max packet size 341 uint16 length = numBytesToWrite; 342 size_t count = 2; 343 if (((numBytesToWrite + 2) % fMaxTXPacketSize) == 0) { 344 length++; 345 count++; 346 } 347 348 struct _TXHeader { 349 uint8 countLow; 350 uint8 countHigh; 351 } __attribute__((__packed__)); 352 353 _TXHeader header = { (uint8)(length & 0xff), 354 (uint8)((length >> 8) & 0xff) }; 355 356 uint8 padding = 0; 357 358 iovec txData[] = { 359 { &header, sizeof(_TXHeader) }, 360 { (uint8*)buffer, numBytesToWrite }, 361 { &padding, 1 } 362 }; 363 364 status_t result = gUSBModule->queue_bulk_v(fWriteEndpoint, 365 txData, count, _WriteCallback, this); 366 if (result != B_OK) { 367 TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result); 368 return result; 369 } 370 371 result = acquire_sem_etc(fNotifyWriteSem, 1, B_CAN_INTERRUPT, 0); 372 373 if (result < B_OK) { 374 TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result); 375 return result; 376 } 377 378 if (fStatusWrite != B_OK && fStatusWrite != B_CANCELED && !fRemoved) { 379 TRACE_ALWAYS("Device status error:%#010x\n", fStatusWrite); 380 return fStatusWrite; 381 } 382 383 *numBytes = fActualLengthWrite - sizeof(_TXHeader); 384 385 TRACE_TX("Written %d bytes.\n", *numBytes); 386 return B_OK; 387 } 388 389 390 status_t 391 DavicomDevice::Control(uint32 op, void *buffer, size_t length) 392 { 393 switch (op) { 394 case ETHER_INIT: 395 return B_OK; 396 397 case ETHER_GETADDR: 398 memcpy(buffer, &fMACAddress, sizeof(fMACAddress)); 399 return B_OK; 400 401 case ETHER_GETFRAMESIZE: 402 *(uint32 *)buffer = kFrameSize; 403 return B_OK; 404 405 case ETHER_NONBLOCK: 406 TRACE("ETHER_NONBLOCK\n"); 407 fNonBlocking = *((uint8*)buffer); 408 return B_OK; 409 410 case ETHER_SETPROMISC: 411 TRACE("ETHER_SETPROMISC\n"); 412 return _SetPromiscuousMode(*((uint8*)buffer)); 413 414 case ETHER_ADDMULTI: 415 TRACE("ETHER_ADDMULTI\n"); 416 return _ModifyMulticastTable(true, (ether_address_t*)buffer); 417 418 case ETHER_REMMULTI: 419 TRACE("ETHER_REMMULTI\n"); 420 return _ModifyMulticastTable(false, (ether_address_t*)buffer); 421 422 case ETHER_SET_LINK_STATE_SEM: 423 fLinkStateChangeSem = *(sem_id *)buffer; 424 return B_OK; 425 426 case ETHER_GET_LINK_STATE: 427 return _GetLinkState((ether_link_state *)buffer); 428 429 default: 430 TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op); 431 } 432 433 return B_DEV_INVALID_IOCTL; 434 } 435 436 437 void 438 DavicomDevice::Removed() 439 { 440 fRemoved = true; 441 fHasConnection = false; 442 443 // the notify hook is different from the read and write hooks as it does 444 // itself schedule traffic (while the other hooks only release a semaphore 445 // to notify another thread which in turn safly checks for the removed 446 // case) - so we must ensure that we are not inside the notify hook anymore 447 // before returning, as we would otherwise violate the promise not to use 448 // any of the pipes after returning from the removed hook 449 while (atomic_add(&fInsideNotify, 0) != 0) 450 snooze(100); 451 452 gUSBModule->cancel_queued_transfers(fNotifyEndpoint); 453 gUSBModule->cancel_queued_transfers(fReadEndpoint); 454 gUSBModule->cancel_queued_transfers(fWriteEndpoint); 455 456 if (fLinkStateChangeSem >= B_OK) 457 release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); 458 } 459 460 461 status_t 462 DavicomDevice::SetupDevice(bool deviceReplugged) 463 { 464 ether_address address; 465 status_t result = _ReadMACAddress(&address); 466 if (result != B_OK) { 467 TRACE_ALWAYS("Error reading MAC address:%#010x\n", result); 468 return result; 469 } 470 471 TRACE("MAC address is:%02x:%02x:%02x:%02x:%02x:%02x\n", 472 address.ebyte[0], address.ebyte[1], address.ebyte[2], 473 address.ebyte[3], address.ebyte[4], address.ebyte[5]); 474 475 if (deviceReplugged) { 476 // this might be the same device that was replugged - read the MAC 477 // address (which should be at the same index) to make sure 478 if (memcmp(&address, &fMACAddress, sizeof(address)) != 0) { 479 TRACE_ALWAYS("Cannot replace device with MAC address:" 480 "%02x:%02x:%02x:%02x:%02x:%02x\n", 481 fMACAddress.ebyte[0], fMACAddress.ebyte[1], 482 fMACAddress.ebyte[2], fMACAddress.ebyte[3], 483 fMACAddress.ebyte[4], fMACAddress.ebyte[5]); 484 return B_BAD_VALUE; // is not the same 485 } 486 } else 487 fMACAddress = address; 488 489 return B_OK; 490 } 491 492 493 status_t 494 DavicomDevice::CompareAndReattach(usb_device device) 495 { 496 const usb_device_descriptor *deviceDescriptor 497 = gUSBModule->get_device_descriptor(device); 498 499 if (deviceDescriptor == NULL) { 500 TRACE_ALWAYS("Error getting USB device descriptor.\n"); 501 return B_ERROR; 502 } 503 504 if (deviceDescriptor->vendor_id != fDeviceInfo.VendorId() 505 && deviceDescriptor->product_id != fDeviceInfo.ProductId()) { 506 // this certainly isn't the same device 507 return B_BAD_VALUE; 508 } 509 510 // this is the same device that was replugged - clear the removed state, 511 // re-setup the endpoints and transfers and open the device if it was 512 // previously opened 513 fDevice = device; 514 fRemoved = false; 515 status_t result = _SetupEndpoints(); 516 if (result != B_OK) { 517 fRemoved = true; 518 return result; 519 } 520 521 // we need to setup hardware on device replug 522 result = SetupDevice(true); 523 if (result != B_OK) { 524 return result; 525 } 526 527 if (fOpen) { 528 fOpen = false; 529 result = Open(fNonBlocking ? O_NONBLOCK : 0); 530 } 531 532 return result; 533 } 534 535 536 status_t 537 DavicomDevice::_SetupEndpoints() 538 { 539 const usb_configuration_info *config 540 = gUSBModule->get_nth_configuration(fDevice, 0); 541 542 if (config == NULL) { 543 TRACE_ALWAYS("Error of getting USB device configuration.\n"); 544 return B_ERROR; 545 } 546 547 if (config->interface_count <= 0) { 548 TRACE_ALWAYS("Error:no interfaces found in USB device configuration\n"); 549 return B_ERROR; 550 } 551 552 usb_interface_info *interface = config->interface[0].active; 553 if (interface == 0) { 554 TRACE_ALWAYS("Error:invalid active interface in " 555 "USB device configuration\n"); 556 return B_ERROR; 557 } 558 559 int notifyEndpoint = -1; 560 int readEndpoint = -1; 561 int writeEndpoint = -1; 562 563 for (size_t ep = 0; ep < interface->endpoint_count; ep++) { 564 usb_endpoint_descriptor *epd = interface->endpoint[ep].descr; 565 if ((epd->attributes & USB_ENDPOINT_ATTR_MASK) 566 == USB_ENDPOINT_ATTR_INTERRUPT) 567 { 568 notifyEndpoint = ep; 569 continue; 570 } 571 572 if ((epd->attributes & USB_ENDPOINT_ATTR_MASK) 573 != USB_ENDPOINT_ATTR_BULK) 574 { 575 TRACE_ALWAYS("Error: USB endpoint type %#04x is unknown.\n", 576 epd->attributes); 577 continue; 578 } 579 580 if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_MASK) 581 == USB_ENDPOINT_ADDR_DIR_IN) 582 { 583 readEndpoint = ep; 584 continue; 585 } 586 587 if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_MASK) 588 == USB_ENDPOINT_ADDR_DIR_OUT) 589 { 590 writeEndpoint = ep; 591 continue; 592 } 593 } 594 595 if (notifyEndpoint == -1 || readEndpoint == -1 || writeEndpoint == -1) { 596 TRACE_ALWAYS("Error: not all USB endpoints were found: notify:%d; " 597 "read:%d; write:%d\n", notifyEndpoint, readEndpoint, writeEndpoint); 598 return B_ERROR; 599 } 600 601 gUSBModule->set_configuration(fDevice, config); 602 603 fNotifyEndpoint = interface->endpoint[notifyEndpoint].handle; 604 fReadEndpoint = interface->endpoint[readEndpoint ].handle; 605 fWriteEndpoint = interface->endpoint[writeEndpoint ].handle; 606 fMaxTXPacketSize = interface->endpoint[writeEndpoint].descr->max_packet_size; 607 608 return B_OK; 609 } 610 611 612 status_t 613 DavicomDevice::_ReadMACAddress(ether_address_t *address) 614 { 615 status_t result = _ReadRegister(RegPAR, 616 sizeof(ether_address), (uint8*)address); 617 if (result != B_OK) { 618 TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result); 619 return result; 620 } 621 622 return B_OK; 623 } 624 625 626 status_t 627 DavicomDevice::_StartDevice() 628 { 629 uint8 control = 0; 630 631 // disable loopback 632 status_t result = _ReadRegister(RegNCR, 1, &control); 633 if (result != B_OK) { 634 TRACE_ALWAYS("Error reading NCR: %#010x.\n", result); 635 return result; 636 } 637 638 if (control & NCRExtPHY) 639 TRACE_ALWAYS("Device uses external PHY\n"); 640 641 control &= ~NCRLoopback; 642 result = _Write1Register(RegNCR, control); 643 if (result != B_OK) { 644 TRACE_ALWAYS("Error writing %#02X to NCR: %#010x.\n", control, result); 645 return result; 646 } 647 648 // Initialize RX control register, enable RX and activate multicast 649 result = _ReadRegister(RegRCR, 1, &control); 650 if (result != B_OK) { 651 TRACE_ALWAYS("Error reading RCR: %#010x.\n", result); 652 return result; 653 } 654 655 control &= ~RCRPromiscuous; 656 control |= RCRDiscardLong | RCRDiscardCRC | RCRRXEnable | RCRAllMulticast; 657 result = _Write1Register(RegRCR, control); 658 if (result != B_OK) { 659 TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result); 660 return result; 661 } 662 663 // clear POWER_DOWN state of internal PHY 664 result = _ReadRegister(RegGPCR, 1, &control); 665 if (result != B_OK) { 666 TRACE_ALWAYS("Error reading GPCR: %#010x.\n", result); 667 return result; 668 } 669 670 control |= GPCRPowerDown; 671 result = _Write1Register(RegGPCR, control); 672 if (result != B_OK) { 673 TRACE_ALWAYS("Error writing %#02X to GPCR: %#010x.\n", control, result); 674 return result; 675 } 676 677 result = _ReadRegister(RegGPR, 1, &control); 678 if (result != B_OK) { 679 TRACE_ALWAYS("Error reading GPR: %#010x.\n", result); 680 return result; 681 } 682 683 control &= ~GPRPowerDownInPHY; 684 result = _Write1Register(RegGPR, control); 685 if (result != B_OK) { 686 TRACE_ALWAYS("Error writing %#02X to GPR: %#010x.\n", control, result); 687 return result; 688 } 689 690 return B_OK; 691 } 692 693 694 status_t 695 DavicomDevice::_StopDevice() 696 { 697 uint8 control = 0; 698 699 // disable RX 700 status_t result = _ReadRegister(RegRCR, 1, &control); 701 if (result != B_OK) { 702 TRACE_ALWAYS("Error reading RCR: %#010x.\n", result); 703 return result; 704 } 705 706 control &= ~RCRRXEnable; 707 result = _Write1Register(RegRCR, control); 708 if (result != B_OK) 709 TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result); 710 711 return result; 712 } 713 714 715 status_t 716 DavicomDevice::_SetPromiscuousMode(bool on) 717 { 718 uint8 control = 0; 719 720 status_t result = _ReadRegister(RegRCR, 1, &control); 721 if (result != B_OK) { 722 TRACE_ALWAYS("Error reading RCR: %#010x.\n", result); 723 return result; 724 } 725 726 if (on) 727 control |= RCRPromiscuous; 728 else 729 control &= ~RCRPromiscuous; 730 731 result = _Write1Register(RegRCR, control); 732 if (result != B_OK) 733 TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result); 734 735 return result; 736 } 737 738 739 uint32 740 DavicomDevice::_EthernetCRC32(const uint8* buffer, size_t length) 741 { 742 uint32 result = 0xffffffff; 743 for (size_t i = 0; i < length; i++) { 744 uint8 data = *buffer++; 745 for (int bit = 0; bit < 8; bit++, data >>= 1) { 746 uint32 carry = ((result & 0x80000000) ? 1 : 0) ^ (data & 0x01); 747 result <<= 1; 748 if (carry != 0) 749 result = (result ^ 0x04c11db6) | carry; 750 } 751 } 752 return result; 753 } 754 755 756 status_t 757 DavicomDevice::_ModifyMulticastTable(bool join, ether_address_t *group) 758 { 759 char groupName[6 * 3 + 1] = { 0 }; 760 sprintf(groupName, "%02x:%02x:%02x:%02x:%02x:%02x", 761 group->ebyte[0], group->ebyte[1], group->ebyte[2], 762 group->ebyte[3], group->ebyte[4], group->ebyte[5]); 763 TRACE("%s multicast group %s\n", join ? "Joining" : "Leaving", groupName); 764 765 uint32 hash = _EthernetCRC32(group->ebyte, 6); 766 bool isInTable = fMulticastHashes.Find(hash) != fMulticastHashes.End(); 767 768 if (isInTable && join) 769 return B_OK; // already listed - nothing to do 770 771 if (!isInTable && !join) { 772 TRACE_ALWAYS("Cannot leave unlisted multicast group %s!\n", groupName); 773 return B_ERROR; 774 } 775 776 const size_t hashLength = 8; 777 uint8 hashTable[hashLength] = { 0 }; 778 hashTable[hashLength - 1] |= 0x80; // broadcast address 779 780 status_t result = _WriteRegister(RegMAR, hashLength, hashTable); 781 if (result != B_OK) { 782 TRACE_ALWAYS("Error initializing MAR: %#010x.\n", result); 783 return result; 784 } 785 786 if (join) 787 fMulticastHashes.PushBack(hash); 788 else 789 fMulticastHashes.Remove(hash); 790 791 for (int32 i = 0; i < fMulticastHashes.Count(); i++) { 792 uint32 hash = fMulticastHashes[i] >> 26; 793 hashTable[hash / 8] |= 1 << (hash % 8); 794 } 795 796 // clear/set pass all multicast bit as required 797 uint8 control = 0; 798 result = _ReadRegister(RegRCR, 1, &control); 799 if (result != B_OK) { 800 TRACE_ALWAYS("Error reading RCR: %#010x.\n", result); 801 return result; 802 } 803 804 if (fMulticastHashes.Count() > 0) 805 control &= ~RCRAllMulticast; 806 else 807 control |= RCRAllMulticast; 808 809 result = _Write1Register(RegRCR, control); 810 if (result != B_OK) { 811 TRACE_ALWAYS("Error writing %#02X to RCR: %#010x.\n", control, result); 812 return result; 813 } 814 815 result = _WriteRegister(RegMAR, hashLength, hashTable); 816 if (result != B_OK) 817 TRACE_ALWAYS("Error writing hash table in MAR: %#010x.\n", result); 818 819 return result; 820 } 821 822 823 void 824 DavicomDevice::_ReadCallback(void *cookie, int32 status, void *data, 825 size_t actualLength) 826 { 827 TRACE_RX("ReadCB: %d bytes; status:%#010x\n", actualLength, status); 828 DavicomDevice *device = (DavicomDevice *)cookie; 829 device->fActualLengthRead = actualLength; 830 device->fStatusRead = status; 831 device->fStats.readCount++; 832 release_sem_etc(device->fNotifyReadSem, 1, B_DO_NOT_RESCHEDULE); 833 } 834 835 836 void 837 DavicomDevice::_WriteCallback(void *cookie, int32 status, void *data, 838 size_t actualLength) 839 { 840 TRACE_TX("WriteCB: %d bytes; status:%#010x\n", actualLength, status); 841 DavicomDevice *device = (DavicomDevice *)cookie; 842 device->fActualLengthWrite = actualLength; 843 device->fStatusWrite = status; 844 device->fStats.writeCount++; 845 release_sem_etc(device->fNotifyWriteSem, 1, B_DO_NOT_RESCHEDULE); 846 } 847 848 849 void 850 DavicomDevice::_NotifyCallback(void *cookie, int32 status, void *data, 851 size_t actualLength) 852 { 853 DavicomDevice *device = (DavicomDevice *)cookie; 854 atomic_add(&device->fInsideNotify, 1); 855 if (status == B_CANCELED || device->fRemoved) { 856 atomic_add(&device->fInsideNotify, -1); 857 return; 858 } 859 860 if (status == B_OK) 861 device->_OnNotify(actualLength); 862 else 863 TRACE_ALWAYS("Status error:%#010x; length:%d\n", status, actualLength); 864 865 // schedule next notification buffer 866 gUSBModule->queue_interrupt(device->fNotifyEndpoint, device->fNotifyData, 867 sizeof(DM9601NotifyData), _NotifyCallback, device); 868 atomic_add(&device->fInsideNotify, -1); 869 } 870 871 872 status_t 873 DavicomDevice::_OnNotify(uint32 actualLength) 874 { 875 if (actualLength != sizeof(DM9601NotifyData)) { 876 TRACE_ALWAYS("Data underrun error. %d of %d bytes received\n", 877 actualLength, sizeof(DM9601NotifyData)); 878 return B_BAD_DATA; 879 } 880 881 bool linkIsUp = fNotifyData->LINKST != 0; 882 fTXBufferFull = fNotifyData->TXFULL != 0; 883 bool rxOverflow = fNotifyData->RXOV != 0; 884 885 bool linkStateChange = (linkIsUp != fHasConnection); 886 fHasConnection = linkIsUp; 887 888 if (linkStateChange) { 889 if (fHasConnection) { 890 TRACE("Link is now up at %s Mb/s\n", 891 fNotifyData->SPEED ? "10" : "100"); 892 } else 893 TRACE("Link is now down"); 894 } 895 896 #ifdef UDAV_TRACE 897 if (gTraceStats) { 898 if (fNotifyData->TXFULL) 899 fStats.txFull++; 900 if (fNotifyData->RXOV) 901 fStats.rxOverflow++; 902 903 if (fNotifyData->ROC) 904 fStats.rxOvCount += fNotifyData->ROC; 905 906 if (fNotifyData->RT) 907 fStats.runtFrames++; 908 if (fNotifyData->LCS) 909 fStats.lateRXCollisions++; 910 if (fNotifyData->RWTO) 911 fStats.rwTOs++; 912 if (fNotifyData->PLE) 913 fStats.physLayerErros++; 914 if (fNotifyData->AE) 915 fStats.alignmentErros++; 916 if (fNotifyData->CE) 917 fStats.crcErrors++; 918 if (fNotifyData->FOE) 919 fStats.overErrors++; 920 921 if (fNotifyData->TSR1.LC) 922 fStats.lateTXCollisions++; 923 if (fNotifyData->TSR1.LCR) 924 fStats.lostOfCarrier++; 925 if (fNotifyData->TSR1.NC) 926 fStats.noCarrier++; 927 if (fNotifyData->TSR1.COL) 928 fStats.txCollisions++; 929 if (fNotifyData->TSR1.EC) 930 fStats.excCollisions++; 931 932 if (fNotifyData->TSR2.LC) 933 fStats.lateTXCollisions++; 934 if (fNotifyData->TSR2.LCR) 935 fStats.lostOfCarrier++; 936 if (fNotifyData->TSR2.NC) 937 fStats.noCarrier++; 938 if (fNotifyData->TSR2.COL) 939 fStats.txCollisions++; 940 if (fNotifyData->TSR2.EC) 941 fStats.excCollisions++; 942 943 fStats.notifyCount++; 944 } 945 #endif 946 947 if (rxOverflow) 948 TRACE("RX buffer overflow. %d packets dropped\n", fNotifyData->ROC); 949 950 uint8 tsr = 0xfc & *(uint8*)&fNotifyData->TSR1; 951 if (tsr != 0) 952 TRACE("TX packet 1: Status %#04x is not OK.\n", tsr); 953 954 tsr = 0xfc & *(uint8*)&fNotifyData->TSR2; 955 if (tsr != 0) 956 TRACE("TX packet 2: Status %#04x is not OK.\n", tsr); 957 958 if (linkStateChange && fLinkStateChangeSem >= B_OK) 959 release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); 960 return B_OK; 961 } 962 963 964 status_t 965 DavicomDevice::_GetLinkState(ether_link_state *linkState) 966 { 967 uint8 registerValue = 0; 968 status_t result = _ReadRegister(RegNSR, 1, ®isterValue); 969 if (result != B_OK) { 970 TRACE_ALWAYS("Error reading NSR register! %x\n", result); 971 return result; 972 } 973 974 if (registerValue & NSRSpeed10) 975 linkState->speed = 10000000; 976 else 977 linkState->speed = 100000000; 978 979 linkState->quality = 1000; 980 981 linkState->media = IFM_ETHER | IFM_100_TX; 982 if (fHasConnection) { 983 linkState->media |= IFM_ACTIVE; 984 result = _ReadRegister(RegNCR, 1, ®isterValue); 985 if (result != B_OK) { 986 TRACE_ALWAYS("Error reading NCR register! %x\n", result); 987 return result; 988 } 989 990 if (registerValue & NCRFullDX) 991 linkState->media |= IFM_FULL_DUPLEX; 992 else 993 linkState->media |= IFM_HALF_DUPLEX; 994 995 if (registerValue & NCRLoopback) 996 linkState->media |= IFM_LOOP; 997 } 998 999 TRACE_STATE("Medium state: %s, %lld MBit/s, %s duplex.\n", 1000 (linkState->media & IFM_ACTIVE) ? "active" : "inactive", 1001 linkState->speed / 1000000, 1002 (linkState->media & IFM_FULL_DUPLEX) ? "full" : "half"); 1003 1004 TRACE_STATS("tx:%d rx:%d rxCn:%d rtF:%d lRxC:%d rwTO:%d PLE:%d AE:%d CE:%d " 1005 "oE:%d ltxC:%d lCR:%d nC:%d txC:%d exC:%d r:%d w:%d n:%d\n", 1006 fStats.txFull, fStats.rxOverflow, fStats.rxOvCount, 1007 fStats.runtFrames, fStats.lateRXCollisions, fStats.rwTOs, 1008 fStats.physLayerErros, fStats.alignmentErros, 1009 fStats.crcErrors, fStats.overErrors, 1010 fStats.lateTXCollisions, fStats.lostOfCarrier, 1011 fStats.noCarrier, fStats.txCollisions, fStats.excCollisions, 1012 fStats.readCount, fStats.writeCount, fStats.notifyCount); 1013 return B_OK; 1014 } 1015 1016 1017 status_t 1018 DavicomDevice::_ReadRegister(uint8 reg, size_t size, uint8* buffer) 1019 { 1020 if (size > 255) 1021 return B_BAD_VALUE; 1022 1023 size_t actualLength = 0; 1024 status_t result = gUSBModule->send_request(fDevice, 1025 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, 1026 ReqReadRegister, 0, reg, size, buffer, &actualLength); 1027 1028 if (size != actualLength) { 1029 TRACE_ALWAYS("Size mismatch reading register ! asked %d got %d", 1030 size, actualLength); 1031 } 1032 1033 return result; 1034 } 1035 1036 1037 status_t 1038 DavicomDevice::_WriteRegister(uint8 reg, size_t size, uint8* buffer) 1039 { 1040 if (size > 255) 1041 return B_BAD_VALUE; 1042 1043 size_t actualLength = 0; 1044 1045 status_t result = gUSBModule->send_request(fDevice, 1046 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 1047 ReqWriteRegister, 0, reg, size, buffer, &actualLength); 1048 1049 return result; 1050 } 1051 1052 1053 status_t 1054 DavicomDevice::_Write1Register(uint8 reg, uint8 value) 1055 { 1056 size_t actualLength = 0; 1057 1058 status_t result = gUSBModule->send_request(fDevice, 1059 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 1060 ReqWriteRegisterByte, value, reg, 0, NULL, &actualLength); 1061 1062 return result; 1063 } 1064 1065 1066 status_t 1067 DavicomDevice::_ReadMII(uint8 reg, uint16* data) 1068 { 1069 // select PHY and set PHY register address 1070 status_t result = _Write1Register(RegEPAR, EPARIntPHY | (reg & EPARMask)); 1071 if (result != B_OK) { 1072 TRACE_ALWAYS("Failed to set MII address %#x. Error:%#x\n", reg, result); 1073 return result; 1074 } 1075 1076 // select PHY operation and initiate reading 1077 result = _Write1Register(RegEPCR, EPCROpSelect | EPCRRegRead); 1078 if (result != B_OK) { 1079 TRACE_ALWAYS("Failed to starting MII reading. Error:%#x\n", result); 1080 return result; 1081 } 1082 1083 // finalize writing 1084 uint8 control = 0; 1085 result = _ReadRegister(RegEPCR, 1, &control); 1086 if (result != B_OK) { 1087 TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", result); 1088 return result; 1089 } 1090 1091 result = _Write1Register(RegEPCR, control & ~EPCRRegRead); 1092 if (result != B_OK) { 1093 TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", result); 1094 return result; 1095 } 1096 1097 // retrieve the result from data registers 1098 uint8 values[2] = { 0 }; 1099 result = _ReadRegister(RegEPDRL, 2, values); 1100 if (result != B_OK) { 1101 TRACE_ALWAYS("Failed to retrieve data %#x. Error:%#x\n", data, result); 1102 return result; 1103 } 1104 1105 *data = values[0] | values[1] << 8; 1106 return result; 1107 } 1108 1109 1110 status_t 1111 DavicomDevice::_WriteMII(uint8 reg, uint16 data) 1112 { 1113 // select PHY and set PHY register address 1114 status_t result = _Write1Register(RegEPAR, EPARIntPHY | (reg & EPARMask)); 1115 if (result != B_OK) { 1116 TRACE_ALWAYS("Failed to set MII address %#x. Error:%#x\n", reg, result); 1117 return result; 1118 } 1119 1120 // put the value to data register 1121 uint8 values[] = { (uint8)(data & 0xff), (uint8)((data >> 8) & 0xff) }; 1122 result = _WriteRegister(RegEPDRL, sizeof(uint16), values); 1123 if (result != B_OK) { 1124 TRACE_ALWAYS("Failed to put data %#x. Error:%#x\n", data, result); 1125 return result; 1126 } 1127 1128 // select PHY operation and initiate writing 1129 result = _Write1Register(RegEPCR, EPCROpSelect | EPCRRegWrite); 1130 if (result != B_OK) { 1131 TRACE_ALWAYS("Failed to starting MII wrintig. Error:%#x\n", result); 1132 return result; 1133 } 1134 1135 // finalize writing 1136 uint8 control = 0; 1137 result = _ReadRegister(RegEPCR, 1, &control); 1138 if (result != B_OK) { 1139 TRACE_ALWAYS("Failed to read EPCR register. Error:%#x\n", result); 1140 return result; 1141 } 1142 1143 result = _Write1Register(RegEPCR, control & ~EPCRRegWrite); 1144 if (result != B_OK) 1145 TRACE_ALWAYS("Failed to write EPCR register. Error:%#x\n", result); 1146 1147 return result; 1148 } 1149 1150 1151 status_t 1152 DavicomDevice::_InitMII() 1153 { 1154 uint16 control = 0; 1155 status_t result = _ReadMII(RegBMCR, &control); 1156 if (result != B_OK) { 1157 TRACE_ALWAYS("Failed to read MII BMCR register. Error:%#x\n", result); 1158 return result; 1159 } 1160 1161 result = _WriteMII(RegBMCR, control & ~BMCRIsolate); 1162 if (result != B_OK) { 1163 TRACE_ALWAYS("Failed to clear isolate PHY. Error:%#x\n", result); 1164 return result; 1165 } 1166 1167 result = _WriteMII(0, BMCRReset); 1168 if (result != B_OK) { 1169 TRACE_ALWAYS("Failed to reset BMCR register. Error:%#x\n", result); 1170 return result; 1171 } 1172 1173 uint16 id01 = 0, id02 = 0; 1174 result = _ReadMII(RegPHYID1, &id01); 1175 if (result != B_OK) { 1176 TRACE_ALWAYS("Failed to read PHY ID 0. Error:%#x\n", result); 1177 return result; 1178 } 1179 1180 result = _ReadMII(RegPHYID2, &id02); 1181 if (result != B_OK) { 1182 TRACE_ALWAYS("Failed to read PHY ID 1. Error:%#x\n", result); 1183 return result; 1184 } 1185 1186 TRACE_ALWAYS("MII Info: OUI:%04x; Model:%04x; rev:%02x.\n", 1187 MII_OUI(id01, id02), MII_MODEL(id02), MII_REV(id02)); 1188 1189 return result; 1190 } 1191 1192 1193 status_t 1194 DavicomDevice::_EnableInterrupts(bool enable) 1195 { 1196 uint8 control = 0; 1197 status_t result = _ReadRegister(RegUSBC, 1, &control); 1198 if (result != B_OK) { 1199 TRACE_ALWAYS("Error of reading USB control register:%#010x\n", result); 1200 return result; 1201 } 1202 1203 if (enable) { 1204 control |= USBCIntAck; 1205 control &= ~USBCIntNAck; 1206 } else { 1207 control &= ~USBCIntAck; 1208 } 1209 1210 result = _Write1Register(RegUSBC, control); 1211 if (result != B_OK) 1212 TRACE_ALWAYS("Error of setting USB control register:%#010x\n", result); 1213 1214 return result; 1215 } 1216 1217